Skip to main content
Version: 0.9

SSO claim mapping

Audience: TokenTimer Enterprise system administrators tuning the attribute / claim paths used by the SAML and OIDC strategies.

TokenTimer needs four pieces of data from your IdP on every SSO login:

ClaimUsed for
Subject (stable ID)Persistent identity link in external_identities
EmailAccount creation, account lookup, account-link guard
Display nameFriendly name in the UI
GroupsResolution against SSO group to role mappings

Each one is configured as a comma-separated list of paths in SSO Providers under Claim mapping (or bootstrap claim_mapping on the provider row). Paths are tried in order; the first non-empty value wins. Dot notation walks into nested objects (name.givenName, _json.x-hasura-allowed-roles). Numeric segments index into arrays (emails.0.value).

How resolution works

For each path:

  1. The strategy looks up profile._json[path] first (the raw IdP-emitted payload from the validated ID Token / UserInfo).
  2. Falls back to profile[path] (the normalised passport profile).
  3. Direct-hit before dot-walking, so SAML attributes named with dots (urn:oid:0.9.2342.19200300.100.1.3) work without quoting.
  4. Empty / null values fall through to the next path.

For groups, the strategy uses extractAll which:

  • Flattens arrays.
  • Splits comma- and semicolon-separated strings.
  • Trims and lower-case-dedupes the result.

Defaults

If you leave a field blank, TokenTimer falls back to broad, widely supported defaults.

ProviderClaimDefault path list
SAMLemailemail,nameID,urn:oid:0.9.2342.19200300.100.1.3,http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress
SAMLdisplayNamedisplayName,urn:oid:2.16.840.1.113730.3.1.241,http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
SAMLgroupsgroups,Groups,http://schemas.xmlsoap.org/claims/Group,http://schemas.microsoft.com/ws/2008/06/identity/claims/role,memberOf
SAMLsubjectnameID
OIDCemailemail,emails.0.value
OIDCdisplayNamedisplayName,name,name.givenName
OIDCgroupsgroups,roles,cognito:groups
OIDCsubjectsub,oid,id

Per-IdP examples

Full setup guides (redirect URIs, IdP consoles, env vars): SSO identity provider guides.

Azure AD / Microsoft Entra ID (OIDC)

Email: email
Display name: name
Groups: groups
Subject: oid # stable across email rename

Notes: Azure emits group object IDs by default. If your mappings use display names, switch the token configuration to "emit groups as group names" or add a groupMembershipClaims to the manifest.

Setup: Microsoft Entra ID (OIDC and SAML).

Okta (OIDC / SAML)

OIDC:

Email: email
Display name: name
Groups: groups
Subject: sub

SAML:

Email: email,urn:oid:0.9.2342.19200300.100.1.3
Display name: displayName
Groups: groups
Subject: nameID

Okta typically uses groups as an attribute name when you map a "Groups" assertion in the SAML profile.

Setup: Okta.

Cognito (OIDC)

Email: email
Display name: name
Groups: cognito:groups
Subject: sub

The cognito:groups claim is namespaced; do not strip the prefix.

Setup: Amazon Cognito.

Keycloak (OIDC)

Email: email
Display name: name
Groups: groups,realm_access.roles
Subject: sub

realm_access.roles walks into the nested object emitted by Keycloak's default mapper.

For realm/client creation, redirect URIs, PKCE, and group mappers, see Keycloak.

Google Workspace (OIDC)

Email: email
Display name: name
Groups: groups # only if you bind a custom claim mapping
Subject: sub

Google does not emit groups out of the box. You'll need an admin SDK sync or a Google-side claim transformation to populate groups.

Setup: Google Workspace.

Auth0 (OIDC)

Email: email
Display name: name
Groups: groups # requires Login Action / custom claim
Subject: sub

Setup: Auth0.

AD FS (SAML)

Email: email,http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress
Display name: displayName,http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
Groups: groups,http://schemas.xmlsoap.org/claims/Group
Subject: nameID

Setup: AD FS.

Subject choice

Should I key on email or on a stable subject?

Always key on a stable subject when the IdP exposes one. Email is mutable; a rename in the IdP turns into a "new user" event with TokenTimer if email is the identity key. With a stable subject, the rename updates users.email on the existing account and tokens, memberships, and audit trail follow the same user.

If your IdP does not emit a stable subject (rare; even SAML 2.0 NameID covers this when not using transient), leave the subject path empty and TokenTimer falls back to email-based matching. The trade-off is that an IdP-side email rename then creates a new account; see the Identity model for the full picture.

Cross-provider merge

When a user first logs in via Okta SAML and later via Azure OIDC with the same email, TokenTimer:

  1. Looks up Entra OIDC (provider_slug='entra', subject_id=<oid>), which misses.
  2. Falls back to email match, hitting the user created via Okta SAML.
  3. Inserts a new external_identities row linking the OIDC subject to the existing user.

Both providers now point at the same users.id. See the Identity model for the full lifecycle.

GitOps field locks

Per-provider claim paths can be locked via bootstrap manifest or SSO Providers. GitOps deployments may also set SSO_<SLUG>_* env vars for core provider fields (see the Configuration reference).

Example bootstrap claim_mapping on an OIDC provider:

"claim_mapping": {
"email": "email,emails.0.value",
"display_name": "name",
"groups": "groups,roles,realm_access.roles",
"subject": "sub"
}

Example SAML provider:

"claim_mapping": {
"email": "email,nameID",
"display_name": "displayName",
"groups": "groups,memberOf",
"subject": "nameID"
}

Precedence: env field lock > database (provider row) > default.

OIDC discovery

On first contact with the IdP, TokenTimer fetches the OpenID Connect discovery document at {issuer}/.well-known/openid-configuration (from the provider row) and populates the authorization, token, userinfo, and JWKS endpoints from it. The document is cached in-process for 5 minutes.

Precedence per endpoint URL:

  1. Explicit override from SSO Providers advanced fields on the provider row.
  2. The discovery document at {issuer}/.well-known/openid-configuration.
  3. Issuer-shaped fallback when discovery is unavailable: Keycloak realms use /protocol/openid-connect/*; other issuers use Auth0-shaped paths (/authorize, /oauth/token, /userinfo). Use the provider wizard to prefill overrides for non-standard IdPs (GitLab, ZITADEL, Google, etc.).

To disable the discovery fetch entirely (offline IdPs, isolated networks), disable discovery on the provider and provide endpoint overrides (or rely on step 3 fallbacks where applicable).

At strategy build or reload time the OIDC config records discoverySource as discovery, manual, issuer_endpoint_fallback, or fallback. Admins can use Test in SSO Providers or GET /api/admin/sso/oidc/diagnostics?slug=<slug> on the API pod under test.

Both /auth/saml/<slug>?next=/dashboard/tokens/123 and /auth/oidc/<slug>?next=/dashboard/tokens/123 land the user on the requested path after a successful flow. The path is validated as a same-origin pathname before being passed to the IdP:

  • Must start with / and not //.
  • Must not contain a URL scheme.
  • Max 512 chars.

Anything else falls back to /dashboard. SAML uses the standard RelayState parameter; OIDC stashes the path on the session.