Overview
AUTH_TYPE=OIDC enables SSO against any OIDC provider:
- Authorization code flow with PKCE (performed by keep-ui via NextAuth; the client secret stays on the UI server side only)
- RS256 bearer token verification in the backend via the provider’s JWKS
(discovered from
{issuer}/.well-known/openid-configuration) - Group-to-role mapping: provider groups are mapped to keep roles
(
admin/noc/webhook) with comma-separated lists - Just-in-time user provisioning: users are created on first sign-in, and their role is refreshed from the token on every API request (a group change on the provider takes effect without re-login)
- Token refresh (requires the
offline_accessscope)
keep), like Okta/OneLogin. It does
not replace the Keycloak EE integration, which additionally provides custom
roles, resource-based permissions, multi-org and in-app user/group management.
How It Works
aud=client_id for it. Keycloak access tokens default to aud="account", so
id_token is the safe default. To validate access tokens instead, set
KEEP_OIDC_TOKEN_TYPE=access_token and (if needed) KEEP_OIDC_AUDIENCE.
A user whose token carries no group matching any KEEP_OIDC_*_ROLES list gets
403 — there is deliberately no default role.
Environment Variables
Backend (keep-api)
When a group appears in several lists, the priority is
admin > noc > webhook.
Frontend (keep-ui)
The provider must allow the redirect URI:
https://<your-keep-domain>/api/auth/callback/oidc.
Provider Configuration Examples
Keycloak (any realm, no EE license required)
- Create a realm (e.g.
keep) or use an existing one. The issuer ishttps://<keycloak-host>/realms/<realm>. - Create a client:
- Client type: Confidential
- Client ID:
keep - Client authentication: On
- Standard flow: Enabled, Direct access grants: Disabled
- Valid redirect URIs:
https://<your-keep-domain>/api/auth/callback/oidc - Copy the client secret from the Credentials tab.
- Add the groups claim (Keycloak does not include groups in tokens by default):
- Client scopes → select the
keepclient’s dedicated scope → Add mapper → Group Membership:- Token claim name:
groups - Add to ID token: On (sufficient for the default
id_tokenmode) - Full group path: Off (otherwise claims look like
/keep-admins— either keep it off, or list full paths inKEEP_OIDC_*_ROLES)
- Token claim name:
- Client scopes → select the
- Create groups
keep-admins/keep-nocand assign users.
openid email profile (see
KEEP_OIDC_SCOPES below the examples):
- the
groupsscope does not exist in a default realm — the Group Membership mapper adds thegroupsclaim to the token even when the scope is not requested, so simply do not request it; offline_accessrequires the client to allow offline tokens — a default client returnsoffline_tokens_not_allowedon the token request. Either omit the scope (refresh tokens keep working for the duration of the SSO session) or enable offline access for the client.
Dex
Dex is useful on its own and as an LDAP/AD federation front (its ldap connector brings directory groups into thegroups claim).
- To skip the consent screen set
oauth2.skipApprovalScreen: true(notskipApproval). - Static (
staticPasswords) users do not carry agroupsclaim — they cannot get a role in keep by design. Use them as break-glass IdP accounts, or put directory users in the mapped groups. - With the ldap connector, request the
groupsscope — Dex adds thegroupsclaim only when that scope is granted.
Authentik
- Create an OAuth2/OpenID provider:
- Client type: Confidential
- Redirect URIs:
https://<your-keep-domain>/api/auth/callback/oidc - Scopes: add
email,profile,offline_accessand a group-membership scope mapping (Authentik’s default “groups” property mapping emits thegroupsclaim).
- The issuer is shown on the provider page:
https://authentik.example.com/application/o/<slug>/. - Assign users to keep groups (
keep-admins/keep-noc) and use the same env variables as in the examples above.
Security Notes
- Tokens are verified on every API request: RS256 signature via JWKS,
iss=KEEP_OIDC_ISSUER,aud= client id (or override),expwith a 60s leeway. Key rotation on the provider is handled automatically (JWKS is re-fetched for unknown key ids). - The discovery document is fetched once per issuer and cached; it is not requested per API call.
- No mapped group → 403 (there is no fallback role).
- API keys are unaffected by provider availability (they use a separate code path). If the provider is down, previously issued tokens stay valid until they expire, but no new ones can be obtained.
- Sign out clears the keep session; the SSO session at the provider stays alive (same behavior as the Okta/OneLogin integrations).

