Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

JWT Configuration

TL;DR — SCHEMABOUND rotates JWT signing keys without downtime by accepting a comma-separated list via SCHEMABOUND_JWT_SECRETS. New tokens are signed with the last entry; old entries remain valid until explicitly removed. Supports HS256, RS256, and ES256 algorithms configured per-issuer via JWT_ALGORITHM.

Use this page if you need to: configure JWT secret rotation for zero-downtime key changes, set up OIDC token validation against external identity providers (Entra ID, Okta, Keycloak), or troubleshoot expired/invalid JWT errors.

Configuration Variables

VariableDefaultPurpose
SCHEMABOUND_JWT_SECRETS(required)Comma-separated list of signing keys; last entry is current, earlier entries validate until removed
JWT_ALGORITHMHS256Signing algorithm per issuer: HS256, RS256, or ES256

Rolling Key Rotation

SCHEMABOUND supports zero-downtime JWT secret rotation by accepting multiple secrets in a single configuration. The runtime evaluates keys in order from newest to oldest during validation; the last entry is used for new token signing while earlier entries remain active for validating tokens issued before rotation.

# Before rotation (single key)
SCHEMABOUND_JWT_SECRETS=old_secret_key_here JWT_ALGORITHM=HS256

# During rotation (two keys — old validates, new signs)
SCHEMABOUND_JWT_SECRETS=new_key_abc123,old_secret_key_here JWT_ALGORITHM=HS256

# After rotation complete (single key again)
SCHEMABOUND_JWT_SECRETS=new_key_abc123 JWT_ALGORITHM=HS256

Rotation Procedure

  1. Generate a new signing secret using your preferred secure generator (e.g., openssl rand -hex 32)
  2. Add the new key to the front of SCHEMABOUND_JWT_SECRETS while keeping the old key at the end
  3. Restart SCHEMABOUND (or trigger a hot-reload via admin endpoint) — both keys are now active for validation; new tokens sign with the front entry
  4. Wait until all previously-issued tokens have expired (check exp claim)
  5. Remove the old key from the end of SCHEMABOUND_JWT_SECRETS and restart

External Identity Provider Verification

When SCHEMABOUND validates JWTs issued by external IdPs (Entra ID, Okta, Keycloak), it fetches public keys from the provider’s JWKS endpoint rather than using symmetric secrets:

# OIDC issuer URL for JWKS discovery
SCHEMABOUND_OIDC_ISSUER=https://login.microsoftonline.com/<tenant-id>/v2.0

# Or explicit JWKS endpoint URL (if not discoverable via OIDC)
SCHEMABOUND_JWKS_ENDPOINT=https://login.microsoftonline.com/common/discovery/v2.0/keys

Public keys are cached in memory and refreshed on a configurable interval (SCHEMABOUND_JWKS_CACHE_TTL, default 1 hour). Expired cache entries trigger an async refresh without blocking request processing.

Algorithm Selection

AlgorithmUse CaseKey TypeExample Provider
HS256Internal service-to-service auth; fast signing/validationSymmetric shared secretSelf-signed, development mode
RS256External IdP verification with public/private key pairsAsymmetric RSA (2048+ bit)Okta, Keycloak, Azure AD
ES256External IdP verification; smaller signatures than RSAAsymmetric EC P-256Entra ID, Google Identity Platform

Troubleshooting

“Invalid signature” errors after key rotation

If clients report invalid_signature after adding a new key to SCHEMABOUND_JWT_SECRETS, verify:

  1. The old key is still listed at the end of the comma-separated list
  2. No leading/trailing whitespace in individual keys
  3. The restart completed before new tokens were issued (check SCHEMABOUND logs for “JWT secrets loaded” message)

Expired token errors from IdP-issued JWTs

External IdP tokens have fixed expiration windows (typically 1 hour). If SCHEMABOUND receives token_expired responses but the IdP says the token is valid:

  1. Check system clock synchronization — NTP drift causes timestamp validation failures
  2. Verify SCHEMABOUND_OIDC_ISSUER matches the IdP’s actual issuer URL (trailing slashes matter)