OIDC claims
OIDC claims
Auth Service injects custom claims into the id_token (and userinfo endpoint response) for every OAuth 2.1 authorization. Claims are scoped to the requesting application — two applications that share the same user pool get independent claim sets.
Available scopes
Request these scopes in the authorization URL to receive the corresponding claims:
| Scope | Claim added | Description |
|---|---|---|
openid | sub, iss, iat, exp | Required for OIDC. Always returned. |
profile | name, image, updatedAt | Basic user profile. |
email | email, emailVerified | User email address. |
roles | roles | Array of role names assigned to the user in this app. |
permissions | permissions | Flat array of permission strings. |
features | features | JSON object of subscription plan feature flags. |
offline_access | — | Issues a refresh_token. |
Claim formats
roles
An array of role name strings:
{ "roles": ["editor", "beta-tester"] }
Roles are defined per-application via the Roles & permissions admin API.
permissions
A flat array of permission strings derived from the roles assigned to the user. The format is:
"resource"— read permission (action isread)"resource.write"— write permission (action iswrite)
{ "permissions": ["articles", "comments.write", "media"] }
Permissions are derived in getUserClaims() (src/services/claims.ts): for each role the user holds in the application, all linked permissions are resolved and deduplicated.
features
A free-form JSON object from the user's active subscription plan. The shape is whatever you define when creating the plan:
{
"features": {
"maxProjects": 5,
"exportEnabled": false,
"storageGb": 10
}
}
If the user has no active subscription for the application, features is an empty object {}.
Access gate
The customIdTokenClaims hook also enforces access control. Token issuance fails with an OIDC FORBIDDEN error if:
- The user has no
userApplicationsrecord for the requesting application, or their record is inactive. - The application has
isMfaRequired: trueand the user has not enabled any MFA method (TOTP or passkey).
This means you do not need a separate "check if user has access" API call — the token will simply not be issued.
Discovery endpoints
Auth Service exposes the following OIDC / OAuth 2.1 discovery endpoints at the issuer root (i.e. BETTER_AUTH_URL/…), in addition to the BetterAuth paths under /api/auth/…:
| Path | Description |
|---|---|
/.well-known/openid-configuration | OIDC discovery document |
/.well-known/oauth-authorization-server | OAuth 2.0 Authorization Server Metadata (RFC 8414) |
/api/auth/jwks | JSON Web Key Set (public keys for token verification) |
/api/auth/oauth2/authorize | Authorization endpoint |
/api/auth/oauth2/token | Token endpoint |
/api/auth/oauth2/userinfo | UserInfo endpoint |