JWT_PUBLIC_KEY_URL to a URL that serves the public key material for your token issuer. When the variable is set,
Onyx accepts a signed JWT in the Authorization header:
This option is part of Onyx Community Edition. It needs no Enterprise license,
and it works the same way in both editions. See Support and stability below.
Setup
1
Publish your public key
Your identity provider must serve the verification key at a URL that the Onyx API server can reach.
Onyx accepts two formats:
- JWKS — a JSON document with a
keysarray. This is what Microsoft Entra ID, Okta, Auth0, and most other providers publish at theirjwks_uri. - PEM — a single PEM-encoded RSA public key.
Content-Type: application/json,
or a body that starts with {, is read as JWKS. Any other body is read as PEM.2
Configure Onyx
Set the variable in your Restart the API server to apply the change.
.env or values.yaml file (Docker and Kubernetes, respectively)..env
values.yaml
3
Send a request
Put the token in the
Authorization header of any Onyx API call. GET /api/me returns the user that Onyx resolved,
so it is a good first check.Token requirements
The address in the identity claim is normalized and lowercased. It becomes the Onyx user’s email.
Key selection and rotation
When the URL serves JWKS, Onyx selects the key by the token headerkid, then by x5t.
If neither matches and the document holds exactly one key, Onyx uses that key.
Onyx caches the fetched key material. If verification fails, Onyx clears the cache, fetches the URL again,
and retries once. Routine key rotation therefore needs no restart.
User handling
A request authenticated by JWT is treated like any other logged-in user.- Just-in-time provisioning. If no Onyx user has that email, Onyx creates one. The account is marked verified and gets a random password it never uses.
- Existing users. If the email belongs to an existing user, that user is returned. Deactivated users are rejected. Accounts that are not web-login accounts are rejected.
- Access policies still apply. The email must satisfy the same invite allowlist and
VALID_EMAIL_DOMAINSrules as every other login path. - Session expiry. With
TRACK_EXTERNAL_IDP_EXPIRY=true, Onyx stores the token’sexpas the user’s external IdP expiry.
Enterprise Edition adds two behaviors on this path. Emails in the default-admin list are made admins at creation.
Provisioning a new user also consumes a license seat,
so a login for an unknown user fails once the workspace reaches its seat limit.
Community Edition applies no seat limit.
Enterprise Edition can also manage access through SCIM.
Precedence
A valid Onyx session cookie takes priority. Onyx reads theAuthorization header only when the request has no session.
API keys and personal access tokens use the same header. Onyx tries the JWT path first,
and a value that is not a valid RS256 JWT falls through to the API key and personal access token paths.
Those credentials keep working unchanged when JWT_PUBLIC_KEY_URL is set.
Support and stability
JWT_PUBLIC_KEY_URL is a documented and supported configuration option.
Onyx treats it like every other published setting on this page:
- The variable name, the
Authorization: Bearerheader, the RS256 requirement, the accepted key formats, and the identity claim order are part of the documented interface. - Automated tests cover the behavior described above — existing-user login, just-in-time provisioning, rejection of tokens signed by an unknown key, rejection of expired tokens, and key rotation without a restart.
- If a future release changes or replaces this option, the change is called out in the release notes for that release, together with the mechanism that replaces it.
If you plan to build an integration on this option, contact us.
We are happy to review your design and tell you about anything on the roadmap that touches it.
Troubleshooting
Onyx logs every verification failure on the API server. Checkapi_server logs for these messages:
A request that fails JWT verification is not rejected outright. It continues as an unauthenticated request,
and the endpoint returns
401 if it needs a user.