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
| Tier | How |
|---|---|
| Community | None needed — run the binary with neither env var set |
| Trial | Email sales@identsphere.com; you'll receive a 30-day JWT |
| Pro / Scale / Enterprise | Subscription 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:
IDENTSPHERE_LICENSE_FILE— a filesystem path containing the JWT.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.
Recommended: a mounted file
# /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)
- Update the
Secretcontaininglicense.jwtwith the new value. - 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
- Replace the mounted file on disk.
- Send
SIGTERMto the container ordocker 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 -cagainst 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_FILEto 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.