Software Licensing
Most software products need a way to control who can use them and under what terms. Whether you ship a desktop application, an on-premise server, a CLI tool, or an SDK, you need to answer questions like: “Has this user paid?”, “How many seats are allowed?”, “Is this license still valid?”, and “Can this device run the software?”
Auris Licensing provides a complete system for issuing, validating, and managing software license keys. It is built into the Auris platform alongside authentication and authorization, so you can tie licensing directly to your existing users, organizations, and tenants.
The Licensing Model
Auris Licensing is organized around three core concepts: Policies, Keys, and Entitlements. They form a hierarchy that separates the blueprint (what kind of license) from the instance (a specific license issued to a specific customer) from the grants (what the license actually allows).
Policies
A policy is a template that defines the rules and shape of a class of licenses. You create policies before issuing any keys. A single product might have several policies — one for a trial, one for a personal plan, one for an enterprise plan.
A policy defines:
| Field | Description |
|---|---|
| Name | Human-readable identifier (e.g., “Pro Plan”, “Enterprise Trial”) |
| Key format | How generated keys look — alphanumeric, UUID, or custom pattern |
| Duration | Default validity period (e.g., 30 days, 1 year, perpetual) |
| Max seats | Maximum number of simultaneous users (for seat-based licensing) |
| Max devices | Maximum number of activated devices (for device-bound licensing) |
| Features | List of feature flags the key grants access to |
| Validation mode | How the key is validated at runtime — Online, Hybrid, or Offline |
| Floating | Whether seats use lease-based checkout (see Floating Licenses) |
| Overage strategy | What happens when limits are exceeded — hard block or grace period |
| Transfer policy | Whether keys can be transferred between licensees |
Policies are immutable by design. When you need to change the terms for new customers, you create a new policy version. Existing keys issued under the old policy retain their original terms unless explicitly migrated.
Keys
A key is a specific license instance issued against a policy and granted to a licensee. The licensee can be a user, an organization, or a device — depending on your licensing model.
When a key is created, Auris:
- Generates the key string according to the policy’s key format
- Records the association between the key, the policy, and the licensee
- Computes the initial entitlements based on the policy defaults
- Sets the expiration date (if the policy has a duration)
- Emits a
license.key.createdevent (for webhooks and automation)
Keys have a lifecycle:
Created → Active → [Suspended] → [Expired | Revoked]- Active: The key passes validation checks and the licensee can use the software.
- Suspended: Temporarily disabled (e.g., payment failed). Can be reactivated.
- Expired: The key’s validity period has elapsed. Cannot be reactivated without issuing a new key or extending the expiration.
- Revoked: Permanently invalidated by an administrator. Cannot be reactivated.
Entitlements
Entitlements are what the key actually grants at runtime. They are the concrete permissions and limits that your application checks against.
Entitlements include:
- Feature flags: Named boolean values (e.g.,
advanced-analytics,custom-branding,api-access) - Seat count: How many users can use the software concurrently or in total
- Device count: How many machines the key can be activated on
- Expiry date: When the entitlements expire
- Metadata: Arbitrary key-value pairs for custom licensing logic
While entitlements are initially derived from the policy, they can be overridden per key. This allows you to handle exceptions without creating a new policy — for example, granting an extra 5 seats to a specific customer as part of a negotiated deal.
The separation between policies and entitlements is deliberate. Policies define defaults and constraints. Entitlements define what this specific key grants right now. This means you can update a key’s entitlements (add a feature, extend expiry) without changing the policy that governs all other keys.
Validation Modes
When your application needs to check whether a license is valid, it performs a validation check. Auris supports three validation modes, each with different tradeoffs between security, availability, and latency.
Online Validation
Every validation check makes an API call to Auris:
Client → POST /api/licensing/validate → Auris API → Database → ResponseThe API verifies the key exists, is active, has not expired, and that the current device/user is within the allowed limits. The response includes the full entitlements object.
Strengths: Always up-to-date. Revocations take effect immediately. Seat and device counts are accurate in real time.
Weaknesses: Requires network connectivity. Adds latency to every check. If Auris is unreachable, the application cannot validate.
Best for: SaaS applications, web apps, and any environment with reliable internet connectivity.
Hybrid Validation
Online-first with a signed JWT fallback for offline scenarios:
Client → POST /api/licensing/validate → Success? Use response
→ Failure/timeout? Use cached JWTWhen an online validation succeeds, the API returns a signed license token (JWT) alongside the entitlements. The client caches this JWT locally. If a subsequent validation attempt fails (network error, timeout), the client falls back to the cached JWT.
The license JWT contains:
{
"sub": "key_abc123",
"iss": "https://api.altovar.net",
"iat": 1710000000,
"exp": 1710086400,
"entitlements": {
"features": ["advanced-analytics", "api-access"],
"maxSeats": 10,
"maxDevices": 5
},
"policy": "pol_enterprise",
"licensee": {
"type": "organization",
"id": "org_xyz"
}
}The JWT is signed with the tenant’s private key (RS256). Your application verifies the signature using the public key from the JWKS endpoint — no network call to Auris needed for cached validation.
Strengths: Works offline for the duration of the JWT’s exp claim. Online checks keep entitlements fresh. Graceful degradation.
Weaknesses: During offline periods, revocations and entitlement changes are not reflected until the JWT expires and a new online check succeeds.
Best for: Desktop applications, mobile apps, and environments with intermittent connectivity.
Offline Validation
JWT-only validation with no network dependency at all:
Client → Verify JWT signature locally → Check exp claim → Read entitlementsThe license JWT is issued once (during activation) and stored on the client. Every validation check is a local cryptographic operation — verify the signature, check the expiration, read the entitlements.
Strengths: Zero network dependency. Sub-millisecond validation. Works in air-gapped environments.
Weaknesses: Entitlement changes require re-issuing and re-importing the JWT. Revocations rely on the separate revocation list mechanism (see Revocation).
Best for: On-premise software, embedded systems, air-gapped environments, and any scenario where the client cannot or should not contact an external API.
Offline validation is inherently less secure than online validation. The JWT can be copied between devices, and revocations are delayed until the revocation list is fetched. Use offline mode only when network constraints make online or hybrid validation impractical, and combine it with device fingerprinting for additional protection.
Floating Licenses
Traditional seat-based licensing assigns seats permanently — if you have 10 seats, only 10 named users can ever use the software. Floating licenses take a different approach: seats are leased temporarily and returned when no longer in use.
This is ideal for organizations where many employees need occasional access but few use the software simultaneously. A company with 50 employees might only need 10 floating seats if no more than 10 people use the software at the same time.
How Floating Licenses Work
The floating license lifecycle has three operations:
Checkout
When a user launches the application, the client requests a seat lease from Auris:
POST /api/licensing/checkout
{
"key": "key_abc123",
"userId": "user_alice",
"leaseDuration": 30 // minutes
}Auris checks whether a seat is available (current active leases < max seats). If a seat is available, it creates a lease record with an expiration time and returns a lease token. If all seats are occupied, the checkout fails with a SEATS_EXHAUSTED error.
Heartbeat
While the user is actively using the software, the client periodically extends the lease:
POST /api/licensing/heartbeat
{
"leaseId": "lease_xyz",
"extend": 30 // minutes
}The heartbeat resets the lease expiration timer. If the client stops sending heartbeats (application crash, network loss, user walks away), the lease will naturally expire.
Checkin
When the user closes the application, the client explicitly releases the seat:
POST /api/licensing/checkin
{
"leaseId": "lease_xyz"
}The lease is deleted immediately, freeing the seat for another user. If the client does not checkin (crash, force-quit), the lease expires automatically after the lease duration elapses.
Lease Expiry and Recovery
The automatic expiry mechanism is critical for floating licenses. Without it, a crashed client would permanently consume a seat. Auris runs a periodic cleanup that removes expired leases, ensuring that seats are always recoverable.
The lease duration is a balance between responsiveness and resilience:
- Short leases (5-10 minutes): Seats are recovered quickly after a crash, but heartbeat traffic is higher.
- Long leases (30-60 minutes): Less heartbeat traffic, but a crashed client holds a seat for longer.
The recommended default is 15-30 minutes, with heartbeats sent at half the lease interval.
Offline Activation
Some environments have no network access at all — factory floor systems, classified government networks, medical devices, industrial control systems. For these scenarios, Auris supports a fully offline activation workflow that never requires the client to communicate directly with the Auris API.
The Offline Activation Flow
The process involves a human intermediary who carries data between the air-gapped machine and a machine with API/console access:
Step 1: Client generates a request payload
The client application collects the license key and a device fingerprint, packages them into a structured payload, and encodes it as a base64 string:
{
"key": "key_abc123",
"fingerprint": "fp_sha256_a1b2c3d4e5f6...",
"requestedAt": "2025-06-15T10:30:00Z",
"clientVersion": "2.4.1"
}The user copies this base64 string (displayed as text or QR code) and brings it to a networked machine.
Step 2: Admin submits the request
The admin pastes the request payload into the Auris Console (under Licensing > Offline Activations) or submits it via the API:
POST /api/licensing/activate/offline
{
"requestPayload": "eyJrZXkiOiAia2V5X2FiYz..."
}Auris validates the key, registers the device fingerprint, and generates a signed response token — a JWT containing the full entitlements, bound to the specific device fingerprint.
Step 3: Client imports the response token
The admin copies the response token back to the air-gapped machine. The client application imports it, verifies the signature against a bundled or previously fetched public key, and activates the license.
From this point forward, the client validates the license entirely offline by verifying the JWT signature and checking its claims.
Offline activation tokens are bound to the device fingerprint included in the request. If the hardware changes significantly (see Device Fingerprinting), the token will fail validation and a new offline activation must be performed.
Device Fingerprinting
Device-bound licensing requires a way to identify machines reliably. Auris uses a composite fingerprint built from multiple hardware and OS attributes, hashed into a stable identifier.
The fingerprint is computed from a combination of:
- CPU model and core count
- Total system memory
- OS type and version
- Disk serial numbers
- Network interface MAC addresses (filtered to exclude virtual adapters)
- Machine ID or hardware UUID (platform-specific)
No single attribute is used in isolation, because any one attribute can change (a RAM upgrade, a new network card). Instead, the fingerprint uses a threshold-based matching algorithm: if a sufficient number of attributes still match, the fingerprint is considered the same machine. This tolerates minor hardware changes while still detecting when a license has been moved to a fundamentally different machine.
The threshold is configurable per policy:
| Setting | Description | Default |
|---|---|---|
| Match threshold | Percentage of attributes that must match | 70% |
| Strict mode | All attributes must match exactly | false |
| Reactivation grace | Number of allowed reactivations after fingerprint change | 1 |
When a fingerprint mismatch is detected beyond the configured tolerance, the validation fails with a DEVICE_MISMATCH error. The end user must deactivate the old device (if accessible) or contact the administrator to reset the device binding.
Revocation
Revoking a license key means permanently or temporarily preventing it from passing validation. How quickly revocation takes effect depends on the validation mode.
Online Revocation
When a key is revoked and the client uses online validation, the revocation is immediate. The next POST /api/licensing/validate call returns:
{
"ok": true,
"data": {
"valid": false,
"code": "KEY_REVOKED",
"message": "This license key has been revoked."
}
}No additional mechanism is needed — the server is the source of truth.
Offline Revocation
When the client uses offline or hybrid validation, the revoked key’s JWT remains cryptographically valid until it expires. To address this, Auris publishes a revocation list — a signed JWT containing an array of revoked key identifiers and their revocation timestamps.
{
"iss": "https://api.altovar.net",
"iat": 1710000000,
"exp": 1710086400,
"revoked": [
{ "key": "key_abc123", "revokedAt": "2025-06-15T14:00:00Z" },
{ "key": "key_def456", "revokedAt": "2025-06-14T09:30:00Z" }
]
}Clients that support offline validation should periodically fetch the revocation list from the well-known endpoint (GET /api/licensing/.well-known/revocation-list) and cache it locally. During offline validation, the client checks the license JWT and the cached revocation list.
Grace Period and TTL
Revocation in offline scenarios is inherently delayed. Two configuration options control the tradeoff:
| Setting | Description | Default |
|---|---|---|
| Revocation list TTL | How long a cached revocation list is considered fresh | 24 hours |
| Grace period | How long after revocation the key still passes validation (for offline clients) | 72 hours |
The grace period exists to prevent abrupt disruption in environments where connectivity is rare. An air-gapped client that fetches the revocation list weekly will still honor revocations within the grace window. After the grace period, the key is hard-blocked regardless of cached state.
The grace period is a business decision, not a technical limitation. Setting it to zero means revocations are only effective when the client can fetch the latest revocation list. Setting it too long means revoked keys continue to work for an extended period. Choose a value that matches your update cadence and risk tolerance.
Customer Portal
Auris Licensing includes a customer-facing portal where end users (licensees) can view and manage their own licenses without contacting the software vendor.
How It Works
The customer portal is accessed via the same Auris-hosted login flow used for authentication. When a user logs in, they see only licenses associated with their account — either directly (user-bound keys) or through their organization membership (org-bound keys).
The portal provides:
- License overview: All active, expired, and suspended keys with their entitlements
- Device management: View activated devices, deactivate a device to free up a slot
- Offline tokens: Download signed license JWTs for offline use
- Usage history: Seat usage over time (for floating licenses)
- Renewal status: Expiration dates and renewal links (if payment integration is configured)
Separation from Admin Management
The customer portal is distinct from the Auris Console. Administrators in the Console have full control over all licenses, policies, and keys across all customers. The customer portal shows only what belongs to the authenticated user.
This separation means:
- End users cannot see other customers’ licenses
- End users cannot modify policy settings or create new keys
- End users can perform self-service actions (deactivate device, download offline token) without admin intervention
- Administrators can disable specific self-service actions per policy if needed
Automation
Manual license management does not scale. When a customer pays for your software, you want the license key to be issued automatically. When a subscription lapses, you want the key to be suspended. Auris Licensing integrates with payment providers and the Auris event system to automate the full lifecycle.
Payment Webhook Integration
Auris supports direct integration with Stripe and PayPal for payment-driven licensing:
Stripe:
checkout.session.completed→ Create a new key against the appropriate policyinvoice.paid→ Extend the key’s expiration (subscription renewal)invoice.payment_failed→ Suspend the key (grace period configurable)customer.subscription.deleted→ Revoke or expire the key
PayPal:
PAYMENT.SALE.COMPLETED→ Create a new keyBILLING.SUBSCRIPTION.RENEWED→ Extend expirationBILLING.SUBSCRIPTION.CANCELLED→ Revoke or expire the keyBILLING.SUBSCRIPTION.SUSPENDED→ Suspend the key
Event-Action Mapping
Beyond payment webhooks, the Auris event system allows you to define custom automation rules. Any licensing event can trigger an action:
| Event | Example Action |
|---|---|
license.key.created | Send welcome email with the key |
license.key.expired | Notify the customer, offer renewal |
license.key.suspended | Send payment reminder |
license.validation.failed | Log the attempt, alert on repeated failures |
license.seats.exhausted | Notify admin, suggest upgrade |
license.device.limit_reached | Notify user with deactivation instructions |
These rules are configured in the Auris Console under Licensing > Automation Rules or via the API. They integrate with the same Actions Engine used for authentication flows, so you can use custom JavaScript actions for complex logic.
Payment automation requires connecting your Stripe or PayPal account in the Auris Console under Integrations. The webhook endpoints are provisioned automatically — you only need to provide API keys and select the policy to use for each product/plan.
How It All Fits Together
Licensing in Auris is not an isolated feature — it is woven into the broader identity and access management platform:
- Users and organizations from Auris IAM are the licensees. No separate user database needed.
- Authentication via Auris Hosted Login gates access to the customer portal.
- RBAC permissions control who can manage licenses in the Console (
manage:licenses,view:licenses). - FGA can be used alongside licensing for fine-grained resource access within a licensed application.
- Webhooks notify your systems of licensing events in real time.
- Audit logs record every licensing operation (key created, validated, revoked, device activated).
This integration means you define users once, authenticate them once, and manage both access control and licensing from a single platform.
Related Concepts
- Sessions & Token Rotation — How sessions and JWTs work in Auris
- Tokens Explained — JWT structure, signing, and verification
- Actions & Sandboxed Execution — Custom automation logic for licensing events
- Multi-Tenancy — How licensing works across tenants
- OAuth 2.0 & OIDC — The authentication framework powering the customer portal