Tokens and Claims
This page describes token response fields, ID token validation expectations, scopes, and the claims exposed by Muhajir Studio OIDC endpoints.
Token Response
POST /api/auth/oauth2/token returns OidcTokenResponse on success:
| Field | Type | Notes |
|---|---|---|
access_token | string | Bearer token for UserInfo and external APIs. |
token_type | Bearer | Token type is always Bearer. |
expires_in | number | Positive integer lifetime in seconds. |
id_token | string | Optional in schema; present when the OIDC provider issues one for the flow. |
refresh_token | string | Optional; present when refresh-token behavior is available for the grant/client. |
scope | string | Optional space-separated granted scope string. |
Use Authorization: Bearer ACCESS_TOKEN for bearer-protected endpoints.
Access Tokens
Access tokens are stored by the OIDC provider and resolved server-side for first-party external APIs. /api/external/me accepts only OIDC bearer access tokens; cookie-only sessions are not accepted there.
An access token is rejected when:
- the
Authorizationheader is missing - the scheme is not
Bearer - the token is unknown
- the token is expired
- the token has no associated user
In those cases, bearer-protected APIs return 401.
ID Tokens
The ID token claims schema allows standard OIDC fields and selected optional claims:
| Claim | Notes |
|---|---|
iss | Issuer. Must match configured OIDC_ISSUER. |
sub | Stable subject identifier. |
aud | Audience. Must include your client_id. |
exp | Expiration time. Must be in the future. |
iat | Issued-at time. |
nonce | Present when nonce was included and should match your stored nonce. |
email | Available when email-related claims are granted. |
email_verified | Available when email-related claims are granted. |
name | Available when profile-related claims are granted. |
picture | Available when profile-related claims are granted. |
given_name | Available when profile-related claims are granted. |
family_name | Available when profile-related claims are granted. |
permissions | Available when the permissions scope is granted and claims are included. |
When using the ID token for local sign-in, validate:
- signature with keys from
/api/auth/jwks issaudexpiataccording to your client policynoncewhen you sent one in the authorize request
Scopes
Supported scopes come from OIDC_SCOPE_METADATA and are exposed by GET /api/public/oidc/scopes.
| Scope | Developer purpose | Claims |
|---|---|---|
openid | Required OIDC scope for stable subject identity. | sub |
profile | Allows profile claims such as name and picture when available. | name, picture, given_name, family_name |
email | Allows email and email verification claims when available. | email, email_verified |
offline_access | Allows refresh-token based sessions where supported. | none |
permissions | Allows permissions claim and permission-based fields in supported APIs. | permissions |
For dynamic applications, admin-selected scopes are the source of truth. During authorization, the server rewrites the request scope to the application's configured scope set.
Permissions Claim
The OIDC provider adds custom UserInfo claims through buildAdditionalUserInfoClaims. Currently, this adds only permissions and only when the granted scopes include permissions.
When included, permissions is the user's effective permission key list from the roles/permissions system.
Example:
{
"sub": "user-id",
"permissions": ["manage-applications", "login-web-admin"]
}
Never check user roles directly in clients. Permission keys are the supported authorization signal.
External Current User Claims
GET /api/external/me returns a smaller, stable external API shape filtered by granted scopes:
| Scope | Response fields |
|---|---|
openid | sub |
profile | name, picture |
email | email, emailVerified |
permissions | permissions |
The endpoint requires openid. If the bearer token is valid but lacks openid, the response is:
{
"error": "FORBIDDEN",
"missingScopes": ["openid"]
}
Refresh Tokens
Refresh tokens can be present in standard token responses when refresh behavior is available for the grant/client. The offline_access scope is intended for refresh-token based sessions where supported.
First-party cookie-token helpers move refresh tokens out of the JSON response and into an HTTP-only cookie. Third-party integrations should normally use the standard /api/auth/oauth2/token endpoint and handle refresh tokens according to their platform security model.
OAuth Error Shape
OIDC and token errors follow the OAuth error schema:
{
"error": "invalid_request",
"error_description": "...",
"error_uri": "https://example.com/docs/error"
}
error_description and error_uri are optional.