Skip to main content

Guides

SaaS Product Licensing

Validate licenses server-side with session management and automatic provisioning via Stripe.

Template used
This guide uses the saas policy template: unlimited devices, daily heartbeat, transferable, no fingerprint required.

1. Create Product and Policy

SaaS products use floating licenses with no device limits. Heartbeats ensure active usage tracking.

setup.py
from licentric import Licentric

client = Licentric(api_key="lk_live_your_key_here")

product = client.products.create(
    name="My SaaS Platform",
    code="SAAS"
)

policy = client.policies.create(
    name="SaaS Subscription",
    product_id=product.id,
    template="saas"  # Unlimited devices, heartbeat, transferable
)

2. Validate on Login

Validate the license once when the user logs in and store the result in their session. No fingerprint is needed for SaaS — use the license key alone.

Python

auth.py
from licentric import Licentric

client = Licentric(api_key="lk_live_your_key_here")

def validate_on_login(license_key: str, user_id: str) -> bool:
    """Validate the license when a user logs in."""
    result = client.validate(key=license_key)

    if not result.valid:
        return False

    # Store validation result in session
    session = get_session(user_id)
    session["license_valid"] = True
    session["license_id"] = result.license_id
    session["entitlements"] = result.entitlements
    session.save()

    return True

TypeScript

auth.ts
import { Licentric } from "@licentric/sdk";

const client = new Licentric({ apiKey: "lk_live_your_key_here" });

async function validateOnLogin(
  licenseKey: string,
  userId: string
): Promise<boolean> {
  const result = await client.validate({ key: licenseKey });

  if (!result.valid) {
    return false;
  }

  // Store validation result in session
  const session = await getSession(userId);
  session.licenseValid = true;
  session.licenseId = result.licenseId;
  session.entitlements = result.entitlements;
  await session.save();

  return true;
}

3. Protect Routes with Middleware

Use middleware to check the session for a valid license on each request. This avoids re-validating against the API on every page load.

middleware.py
def require_valid_license(handler):
    """Middleware: check session for valid license on each request."""
    def wrapper(request):
        session = get_session(request.user_id)

        if not session.get("license_valid"):
            return Response(status=403, body={
                "error": "No valid license. Please subscribe."
            })

        return handler(request)
    return wrapper

# Usage
@require_valid_license
def dashboard_handler(request):
    return render_dashboard(request)

4. Send Heartbeats

The SaaS template enables heartbeats by default. Send a heartbeat periodically to confirm the license is actively in use. If a heartbeat is missed, validation returns HEARTBEAT_REQUIRED.

heartbeat.py
# The SaaS template enables heartbeats by default.
# Heartbeats ensure licenses are actively in use.
#
# Server-side: send heartbeat on each authenticated request
# (or on a schedule, e.g., every 30 minutes)

def send_heartbeat(license_id: str, machine_id: str):
    """Ping Licentric to confirm active usage."""
    client.machines.heartbeat(
        license_id=license_id,
        machine_id=machine_id
    )

5. Pair with Stripe

For the best SaaS experience, connect Stripe to automatically provision licenses when customers subscribe. See the Stripe Integration guide for full setup.

webhook_handler.py
# When a Stripe checkout completes, Licentric automatically:
# 1. Creates a customer (if not exists)
# 2. Issues a license key
# 3. Sends the key via webhook to your app
#
# Your webhook handler:
def handle_license_created(event):
    license = event["data"]
    user = find_user_by_email(license["email"])
    user.license_key = license["key"]
    user.save()
    send_welcome_email(user)
No fingerprinting needed
SaaS products validate server-side, so there is no device to fingerprint. Use entitlements to control feature access across subscription tiers instead. See the Feature Gating guide.