Tokens

FerrisKey issues JSON Web Tokens (JWTs) as the result of successful authentication. Each token type serves a specific purpose in the OAuth2/OIDC protocol.

Token Types

TokenPurposeTypical Lifetime
Access TokenAuthorize API requests to resource servers300s (5 min)
Refresh TokenObtain new access tokens without re-authentication86400s (24 hr)
ID TokenConvey user identity to the client (OIDC)300s (5 min)
Temporary TokenAuthorize required action completion only300s (5 min)

JWT Structure

Every FerrisKey token is a signed JWT with three parts: header, payload, and signature.

Standard Claims

ClaimDescription
subSubject — the user’s unique ID
audAudience — the client ID
issIssuer — the realm’s token endpoint URL
expExpiration timestamp
iatIssued-at timestamp
nbfNot-before timestamp
jtiJWT ID — unique token identifier
scopeSpace-separated list of granted scopes

Custom Claims

Protocol mappers (configured through client scopes) inject additional claims:

ClaimSource
realm_rolesUser’s realm role names
client_rolesUser’s client-specific role names
permissionsResolved permission bitmask
preferred_usernameUsername
emailEmail address
given_nameFirst name
family_nameLast name

Token Lifetimes

Token lifetimes are configured at two levels:

  1. Realm defaults — Apply to all clients in the realm
  2. Client overrides — Take precedence when set
TokenRealm DefaultClient Override
Access Tokenaccess_token_lifetime (300s)access_token_lifetime
Refresh Tokenrefresh_token_lifetime (86400s)refresh_token_lifetime
ID Tokenid_token_lifetime (300s)id_token_lifetime
Temporary Tokentemporary_token_lifetime (300s)temporary_token_lifetime

The resolution rule is simple: if the client defines an override, use it. Otherwise, fall back to the realm default.

Token Generation Chain

graph LR
    A[User + Client] --> B[Resolve Scopes]
    B --> C[Execute Protocol Mappers]
    C --> D[Build JWT Payload]
    D --> E[Sign with Realm Key]
    E --> F[Access Token + Refresh Token + ID Token]
  1. The user authenticates to a client
  2. Default scopes (plus any requested optional scopes) are resolved
  3. Protocol mappers from each scope produce claims
  4. Claims are assembled into the JWT payload with standard claims
  5. The token is signed using the realm’s signing key and algorithm
  6. Access, refresh, and (optionally) ID tokens are returned

Token Introspection

Resource servers can validate tokens by calling the introspection endpoint:

curl -X POST http://localhost:3333/realms/{realm}/protocol/openid-connect/token/introspect \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "token=eyJhbG..." \
  -d "client_id=my-client" \
  -d "client_secret=my-secret"

The response includes active: true/false and the full set of token claims when active.