Skip to main content

License keys

This page covers the operational side of license keys: how to install one, where to get one, how to rotate one, and how to read a failure when verification rejects yours. For the licensing model itself (tiers, what each tier includes, why we ship closed binaries), see licensing.

What a license key is

A license key is a single string — an ed25519-signed JWT. It looks like this when decoded:

{
"iss": "identsphere.com",
"sub": "Acme Corp",
"tier": "scale",
"features": ["saml", "scim", "branded_emails"],
"max_users": 10000,
"issued_at": 1748400000,
"expires_at": 1779936000,
"license_id": "9e2a1e1a-7e2c-4d6c-9f6b-e8d44b1f0b32",
"instance_pin": null
}

The signature is verified at process startup against the public key embedded in the IdentSphere binary. No network call is made. If the signature is good, the claims are trusted as-is.

The plaintext you receive from sales@identsphere.com is the JWT itself — the full eyJ… string. Keep it together with your other secrets; treat it as moderately sensitive (it identifies your organization and encodes your tier).

Getting a license

TierHow
CommunityNone needed — run the binary with neither env var set
TrialEmail sales@identsphere.com; you'll receive a 30-day JWT
Pro / Scale / EnterpriseSubscription with sales@identsphere.com; JWTs are issued from the customer portal once your contract is active

A signed customer portal lives at portal.identsphere.com for paid customers. You can download fresh JWTs from there at any time — for example after rotating your deployment to a new cluster.

Installing a license

The IdentSphere server looks at two environment variables, in order:

  1. IDENTSPHERE_LICENSE_FILE — a filesystem path containing the JWT.
  2. IDENTSPHERE_LICENSE — the JWT directly.

If both are unset, the server boots in Community tier and prints a prominent warning. If either is set but the JWT fails verification, the server exits non-zero with EX_CONFIG (78) so your orchestrator notices.

# /etc/identsphere/license.jwt on the host
docker run \
-v /etc/identsphere/license.jwt:/etc/identsphere/license.jwt:ro \
-e IDENTSPHERE_LICENSE_FILE=/etc/identsphere/license.jwt \
-e DATABASE_URL=postgres://… \
-e IDENTSPHERE_JWT_SECRET=\
-e IDENTSPHERE_PUBLIC_BASE_URL=https://auth.example.com \
-e IDENTSPHERE_FROM_EMAIL=auth@example.com \
ghcr.io/identsphere/server:latest

Kubernetes Secret

apiVersion: v1
kind: Secret
metadata:
name: identsphere-license
type: Opaque
stringData:
license.jwt: |
eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ4YXV0aC5kZXYi...
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: IdentSphere
spec:
template:
spec:
containers:
- name: IdentSphere
image: ghcr.io/identsphere/server:latest
env:
- name: IDENTSPHERE_LICENSE_FILE
value: /etc/identsphere/license.jwt
volumeMounts:
- name: license
mountPath: /etc/identsphere
readOnly: true
volumes:
- name: license
secret:
secretName: identsphere-license
items:
- key: license.jwt
path: license.jwt

Inline (for ephemeral testing only)

docker run -e IDENTSPHERE_LICENSE="$(cat license.jwt)"

This works but exposes the JWT in docker inspect and process environment dumps. Use the file path in real deployments.

Verifying a license was loaded

On startup, IdentSphere logs one of:

INFO identsphere_core::license::verifier: license verified tier=scale customer="Acme Corp" license_id=9e2a1e1a-7e2c-4d6c-9f6b-e8d44b1f0b32 expires_at=1779936000 file=/etc/identsphere/license.jwt

…or:

WARN identsphere_core::license::verifier: no IDENTSPHERE_LICENSE / IDENTSPHERE_LICENSE_FILE set; running in Community tier. Paid features (SAML, SCIM, audit export, etc.) will be disabled. Contact sales@identsphere.com for a license.

When the license is within seven days of expiry, a separate warning fires on every startup:

WARN identsphere_core::license::verifier: IdentSphere license expires in less than 7 days; renew at sales@identsphere.com days_left=5 customer="Acme Corp"

The /healthz and /metrics endpoints surface the current tier and expiry epoch for monitoring; alert on both.

Rotating a license

When a license is renewed (e.g. annual renewal) you'll receive a new JWT. To install it:

Zero-downtime rotation (Kubernetes)

  1. Update the Secret containing license.jwt with the new value.
  2. Roll the deployment (kubectl rollout restart deployment/IdentSphere). The standard rolling update keeps you on the old pods until the new pods pass readiness checks.

Docker / docker compose

  1. Replace the mounted file on disk.
  2. Send SIGTERM to the container or docker compose up -d — the process re-reads the file on startup.

IdentSphere does not support hot-reload of license JWTs without restart. A restart is the boundary at which we re-verify. If you need truly zero-downtime rotation, run more than one replica behind a load balancer (which you should be doing anyway).

When verification fails

The server exits with EX_CONFIG (78) and prints a one-line summary. Common cases:

invalid license signature

The JWT was signed with a different key than the one baked into your binary. Causes:

  • You are running a tampered build of IdentSphere.
  • You received a JWT issued for a different IdentSphere release line.
  • The file is corrupted; check wc -c against the expected length.

Fix: re-download the JWT from the customer portal. If the problem persists, the binary you're running is likely tampered; pull a fresh image from ghcr.io/identsphere/server and check the image digest against the one in the release notes.

malformed license: …

The JWT couldn't be parsed. Causes:

  • The file contains leading or trailing whitespace.
  • Someone copy-pasted only part of the JWT.
  • A newline-conversion tool munged the file (CRLF on Windows mounts is the usual culprit).

Fix: regenerate the file from the source. The JWT is one long ASCII line with no embedded newlines.

license expired at <timestamp>

Your license's expires_at has passed. Causes:

  • Your subscription expired.
  • You're still running last year's trial.

Fix: contact sales@identsphere.com for a fresh JWT, or remove the env vars to fall back to Community.

license issuer not recognized

The JWT's iss claim is something other than "identsphere.com". This should never happen with a JWT from us. If you see it, the file is forged or for a different product.

Troubleshooting checklist

# 1. Is the env var set inside the container?
docker exec identsphere env | grep IDENTSPHERE_LICENSE

# 2. Is the file mounted and readable?
docker exec identsphere cat /etc/identsphere/license.jwt | wc -c
# Should be ~300–500 bytes for a typical license.

# 3. Decode the payload (no signature check) to see the claims:
docker exec identsphere sh -c 'awk -F. "{print \$2}" /etc/identsphere/license.jwt' \
| base64 -d 2>/dev/null

# 4. Watch the boot log for the verifier line:
docker logs IdentSphere 2>&1 | grep -i license

Air-gapped deployments

License verification is offline by design, so air-gapped operation needs no special accommodation:

  • Place the JWT on disk in your air-gapped environment.
  • Mount it into the container.
  • Set IDENTSPHERE_LICENSE_FILE to its path.

No network call is made to identsphere.com at any point.

Renewing before expiry

We will email the contact on file in the customer portal 30 days, 14 days, and 3 days before expiry. The binary itself logs warnings inside the last 7 days. If you'd prefer to monitor programmatically, scrape /metrics for the gauge:

identsphere_license_expires_at_unix 1779936000

…and alert when it's less than now + 14d.

See also