How OIDC SSO Integration Works with Claims-Based Admin Mapping in TREK
TREK determines administrator privileges during OIDC SSO authentication by inspecting a configurable claim (default groups) for a specific value defined in OIDC_ADMIN_VALUE, automatically granting the admin role when the claim value matches while protecting the bootstrap user and last remaining admin from demotion.
TREK implements OpenID Connect (OIDC) single sign-on to delegate authentication to external identity providers like Google, Keycloak, or Authentik. After verifying the ID token, the system performs claims-based admin mapping to determine whether the authenticated user should receive administrator privileges or standard user access. This mapping relies on environment variables to inspect specific claims in the OIDC userinfo response, making it easy to synchronize your identity provider's group memberships with TREK's role-based access control.
Configuration Environment Variables
Claims-based admin mapping is controlled exclusively through environment variables. These settings cannot be modified from the admin panel and must be configured before starting the application.
OIDC_ADMIN_CLAIM: Specifies the claim name to inspect for role information (default:groups). Common alternatives includerolesorrealm_access.roles.OIDC_ADMIN_VALUE: The exact value that must be present in the claim to grant admin privileges. When unset, claim-based admin mapping is disabled and all users receive the standarduserrole.OIDC_ISSUER,OIDC_CLIENT_ID,OIDC_CLIENT_SECRET: Standard OIDC configuration for provider discovery and token exchange.
For a complete reference, see the environment variable documentation in wiki/OIDC-SSO.md and wiki/Environment-Variables.md.
Authentication Flow Overview
The OIDC SSO process follows these steps to authenticate and authorize users:
- The user initiates login via
GET /api/auth/oidc/login, which redirects to the identity provider. - After authentication, the IdP redirects to
GET /api/auth/oidc/callbackwith an authorization code. - TREK exchanges the code for tokens using
exchangeCodeForToken()inserver/src/services/oidcService.ts. - The ID token is verified via
verifyIdToken()using the provider's JWKS. - User information is retrieved via
getUserInfo(). - The system calls
findOrCreateUser()to link the OIDC identity to a local account or create a new one. - Role resolution occurs through
resolveOidcRole(), which determines if the user receivesadminoruserprivileges.
Claims-Based Admin Mapping Logic
The core role resolution logic resides in server/src/services/oidcService.ts within the resolveOidcRole function. This function implements a hierarchy of checks to determine the appropriate role.
First User Protection
The bootstrap administrator (the first account ever created in the TREK instance) is automatically granted admin privileges regardless of OIDC claims. This ensures you cannot lock yourself out during initial setup.
Claim Inspection
For subsequent users, if OIDC_ADMIN_VALUE is configured, TREK examines the claim specified by OIDC_ADMIN_CLAIM:
export function resolveOidcRole(userInfo: OidcUserInfo, isFirstUser: boolean): 'admin' | 'user' {
// First user always becomes admin
if (isFirstUser) return 'admin';
const adminValue = process.env.OIDC_ADMIN_VALUE;
if (!adminValue) return 'user'; // Claim-based admin disabled
const claimKey = process.env.OIDC_ADMIN_CLAIM || 'groups';
const claimData = userInfo[claimKey];
// Handle array claims (e.g., ["admins", "users"])
if (Array.isArray(claimData)) {
return claimData.some(v => String(v) === adminValue) ? 'admin' : 'user';
}
// Handle string claims
if (typeof claimData === 'string') {
return claimData === adminValue ? 'admin' : 'user';
}
return 'user';
}
The function handles both array and string claim formats, converting values to strings for comparison against OIDC_ADMIN_VALUE.
Role Re-evaluation and Safety
TREK stores the resolved role in the users.role column and re-evaluates it on every login. However, the system includes a critical safety check: if the resolved role would downgrade the last remaining admin, TREK logs a warning and preserves the admin role to prevent accidental lock-out.
Configuration Examples
Docker Compose Setup
Configure claims-based admin mapping in your docker-compose.yml:
services:
trek:
environment:
- OIDC_ISSUER=https://auth.example.com
- OIDC_CLIENT_ID=trek
- OIDC_CLIENT_SECRET=super-secret
- OIDC_ADMIN_CLAIM=groups # Claim to inspect
- OIDC_ADMIN_VALUE=app-trek-admins # Value granting admin access
Custom Role Claims
For identity providers using roles instead of groups:
export OIDC_ADMIN_CLAIM=roles
export OIDC_ADMIN_VALUE=administrator
Users with "roles": ["administrator", "editor"] in their ID token will receive admin privileges.
Programmatic Role Verification
When building custom middleware or extensions, you can reuse the role resolution logic:
import { resolveOidcRole } from './services/oidcService';
function checkAdminAccess(userInfo: OidcUserInfo): boolean {
// Pass false for isFirstUser when checking existing users
return resolveOidcRole(userInfo, false) === 'admin';
}
Key Implementation Files
| File | Purpose |
|---|---|
server/src/services/oidcService.ts |
Core OIDC implementation including resolveOidcRole(), findOrCreateUser(), and token validation |
wiki/OIDC-SSO.md |
High-level documentation of the OIDC flow and required environment variables |
wiki/Environment-Variables.md |
Complete reference for all OIDC-related configuration |
server/tests/unit/services/oidcService.test.ts |
Unit tests covering claims-based admin mapping scenarios |
docker-compose.yml |
Example production configuration showing OIDC variable placement |
Summary
- Claims-based admin mapping uses
OIDC_ADMIN_CLAIM(default:groups) andOIDC_ADMIN_VALUEto determine administrator privileges from OIDC tokens. - The first user in the system is automatically granted admin status regardless of claims.
- The
resolveOidcRole()function inserver/src/services/oidcService.tshandles both array and string claim formats. - Roles are re-evaluated on every login, with safety mechanisms preventing the demotion of the last remaining admin.
- Configuration is environment-variable only and cannot be changed through the web interface.
Frequently Asked Questions
What happens if OIDC_ADMIN_VALUE is not set?
When OIDC_ADMIN_VALUE is undefined, claims-based admin mapping is disabled. Every user authenticating via SSO receives the standard user role, and no automatic admin promotion occurs based on OIDC claims. You must manually promote users to admin through the database or admin panel.
Can I use nested claims for role mapping?
The current implementation in resolveOidcRole() performs a direct property lookup on the userinfo object using userInfo[claimKey]. Nested claims (e.g., realm_access.roles) require your identity provider to flatten the claim or you must configure a custom claim mapper in your IdP to surface the nested value as a top-level claim.
Does TREK support multiple admin values or regex patterns?
As implemented in server/src/services/oidcService.ts, the comparison uses exact string equality (===). The code checks if any array element equals the OIDC_ADMIN_VALUE or if the string claim equals it exactly. Multiple values or regex patterns are not supported; you must specify a single exact value.
How does TREK handle claim value type coercion?
The function explicitly converts array elements to strings using String(v) before comparison, ensuring consistent matching regardless of whether the IdP sends integers or strings. However, the OIDC_ADMIN_VALUE environment variable is always treated as a string for comparison purposes.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →