OIDC Authentication

Configure OpenID Connect SSO for AllureDeck with role mapping from identity provider group claims.

Overview

AllureDeck supports two authentication methods operating simultaneously:

  1. Local authentication — static admin/viewer credentials via environment variables
  2. OIDC SSO — OpenID Connect with any compliant identity provider

Local auth serves as a break-glass fallback when SSO is enabled.

Role Permissions
admin Full access: create/delete projects, manage reports, manage users, system settings, API keys
editor Upload results, generate reports, manage known issues, set default branches
viewer Read-only access to all reports, dashboards, and analytics

How It Works

AllureDeck uses the Authorization Code + PKCE flow. The entire OIDC exchange happens server-side — the frontend only provides an SSO button.

Authorization Code + PKCE flow
Browser                    AllureDeck API              Identity Provider
  |                              |                              |
  |-- click "Sign in with SSO" ->                              |
  |                              |-- redirect with PKCE ------->
  |                              |                              |
  |                              |<---- authorization code -----|
  |                              |                              |
  |                              |-- exchange code + verifier ->
  |                              |<---- ID token ---------------|
  |                              |                              |
  |                              |  validate token, extract claims,
  |                              |  resolve role from groups,
  |                              |  JIT-provision user record,
  |                              |  issue AllureDeck JWT cookies
  |                              |                              |
  |<-- redirect with cookies ---|                              |

Key security properties:

  • PKCE (S256) on every authorization request
  • State parameter encrypted with AES-GCM in an httpOnly cookie
  • Nonce validated in the ID token to prevent replay attacks
  • Group claims read from the signed ID token only (not userinfo endpoint)
  • JIT provisioning — user records created on first login, updated on subsequent logins

Configuration Reference

All OIDC settings are provided via environment variables. Variables marked with * are required when OIDC_ENABLED=true — the server refuses to start if they are missing.

Environment Variable Required Default Description
OIDC_ENABLED No false Master toggle for SSO
OIDC_ISSUER_URL Yes* IdP discovery URL (must support /.well-known/openid-configuration)
OIDC_CLIENT_ID Yes* OAuth2 client ID registered with the IdP
OIDC_CLIENT_SECRET Yes* OAuth2 client secret (confidential client)
OIDC_REDIRECT_URL Yes* Callback URL: https://<your-domain>/api/v1/auth/oidc/callback
OIDC_SCOPES No openid,profile,email Comma-separated OIDC scopes
OIDC_GROUPS_CLAIM No groups JWT claim name containing group memberships
OIDC_ADMIN_GROUPS No Comma-separated group IDs mapping to admin role
OIDC_EDITOR_GROUPS No Comma-separated group IDs mapping to editor role
OIDC_DEFAULT_ROLE No viewer Role assigned when no group matches
OIDC_STATE_COOKIE_SECRET Yes* AES encryption key for state cookies (exactly 32 bytes)
OIDC_POST_LOGIN_REDIRECT No / Frontend URL after successful SSO login
OIDC_END_SESSION_URL No RP-initiated logout URL (optional)

* Required when OIDC_ENABLED=true. Server refuses to start if missing.

Role Mapping

Roles are resolved from IdP group claims using highest-priority-wins:

  1. If any group matches OIDC_ADMIN_GROUPSadmin
  2. Else if any matches OIDC_EDITOR_GROUPSeditor
  3. Else → OIDC_DEFAULT_ROLE (default: viewer)

User Lifecycle

  • First login: User record created automatically (JIT provisioning) with resolved role
  • Subsequent logins: Name, email, and role updated from latest token claims
  • Deactivation: Set is_active=false in users table. User receives 403 on next SSO login

Provider Setup

Select your identity provider below for step-by-step configuration instructions.

Azure AD (Entra ID)

  1. Register an application in Azure Portal → App registrations
  2. Set redirect URI to https://alluredeck.example.com/api/v1/auth/oidc/callback (Web platform)
  3. Create a client secret under Certificates & secrets
  4. Under Token configuration, add optional groups claim (Security groups, type: Group ID)
  5. Note your tenant ID
Environment variables
OIDC_ENABLED=true
OIDC_ISSUER_URL=https://login.microsoftonline.com/<tenant-id>/v2.0
OIDC_CLIENT_ID=<application-client-id>
OIDC_CLIENT_SECRET=<client-secret-value>
OIDC_REDIRECT_URL=https://alluredeck.example.com/api/v1/auth/oidc/callback
OIDC_GROUPS_CLAIM=groups
OIDC_ADMIN_GROUPS=<azure-ad-group-object-id-for-admins>
OIDC_EDITOR_GROUPS=<azure-ad-group-object-id-for-editors>
OIDC_STATE_COOKIE_SECRET=<32-byte-random-string>
Group overage: When a user belongs to 200+ groups, Azure AD returns a _claim_sources reference instead of inline groups. AllureDeck detects this and assigns OIDC_DEFAULT_ROLE.

Keycloak

  1. Create client in realm (Client type: OpenID Connect, Access type: confidential)
  2. Set Valid redirect URIs to https://alluredeck.example.com/api/v1/auth/oidc/callback
  3. Under Client scopes → add mapper of type "Group Membership" with token claim name groups
Environment variables
OIDC_ENABLED=true
OIDC_ISSUER_URL=https://keycloak.example.com/realms/<realm>
OIDC_CLIENT_ID=alluredeck
OIDC_CLIENT_SECRET=<client-secret>
OIDC_REDIRECT_URL=https://alluredeck.example.com/api/v1/auth/oidc/callback
OIDC_GROUPS_CLAIM=groups
OIDC_ADMIN_GROUPS=alluredeck-admins
OIDC_EDITOR_GROUPS=alluredeck-editors
OIDC_STATE_COOKIE_SECRET=<32-byte-random-string>

Google Workspace

  1. Create OAuth 2.0 credentials in Google Cloud Console → APIs & Services → Credentials
  2. Set authorized redirect URI to https://alluredeck.example.com/api/v1/auth/oidc/callback
  3. Note: Google does not provide group claims by default
No group claims: Google does not provide group claims in the ID token by default. All users will receive OIDC_DEFAULT_ROLE unless you use Google Workspace directory groups with a custom claim mapper.
Environment variables
OIDC_ENABLED=true
OIDC_ISSUER_URL=https://accounts.google.com
OIDC_CLIENT_ID=<client-id>.apps.googleusercontent.com
OIDC_CLIENT_SECRET=<client-secret>
OIDC_REDIRECT_URL=https://alluredeck.example.com/api/v1/auth/oidc/callback
OIDC_DEFAULT_ROLE=editor
OIDC_STATE_COOKIE_SECRET=<32-byte-random-string>

Okta

  1. Create an OIDC Web Application in Okta Admin Console
  2. Set sign-in redirect URI to https://alluredeck.example.com/api/v1/auth/oidc/callback
  3. Under Sign On → OpenID Connect ID Token, add a Groups claim filter
Environment variables
OIDC_ENABLED=true
OIDC_ISSUER_URL=https://<your-okta-domain>/oauth2/default
OIDC_CLIENT_ID=<client-id>
OIDC_CLIENT_SECRET=<client-secret>
OIDC_REDIRECT_URL=https://alluredeck.example.com/api/v1/auth/oidc/callback
OIDC_GROUPS_CLAIM=groups
OIDC_ADMIN_GROUPS=alluredeck-admins
OIDC_EDITOR_GROUPS=alluredeck-editors
OIDC_STATE_COOKIE_SECRET=<32-byte-random-string>

Deployment Examples

Docker Compose

docker-compose.yml
services:
  allure-api:
    environment:
      OIDC_ENABLED: "true"
      OIDC_ISSUER_URL: "https://login.microsoftonline.com/<tenant>/v2.0"
      OIDC_CLIENT_ID: "<client-id>"
      OIDC_CLIENT_SECRET: "<client-secret>"
      OIDC_REDIRECT_URL: "http://localhost:5050/api/v1/auth/oidc/callback"
      OIDC_ADMIN_GROUPS: "<admin-group-id>"
      OIDC_EDITOR_GROUPS: "<editor-group-id>"
      OIDC_STATE_COOKIE_SECRET: "<32-byte-random-string>"

Helm Chart

values.yaml
api:
  oidc:
    enabled: true
    issuerUrl: "https://login.microsoftonline.com/<tenant>/v2.0"
    clientId: "<client-id>"
    clientSecret: "<client-secret>"
    redirectUrl: "https://alluredeck.example.com/api/v1/auth/oidc/callback"
    adminGroups: "<admin-group-id>"
    editorGroups: "<editor-group-id>"
    stateCookieSecret: "<32-byte-random-string>"
Auto-generated secrets: The chart stores clientSecret and stateCookieSecret in a Kubernetes Secret. If left empty, random values are auto-generated on first install and preserved across upgrades.

Generating Secrets

The OIDC_STATE_COOKIE_SECRET must be exactly 32 bytes. Use any of these methods to generate one:

Generate a 32-byte secret
# OpenSSL
openssl rand -base64 32 | head -c 32

# Python
python3 -c "import secrets; print(secrets.token_urlsafe(24)[:32])"

# /dev/urandom
head -c 32 /dev/urandom | base64 | head -c 32

Troubleshooting

Symptom Cause Fix
Server refuses to start with "OIDC_ISSUER_URL is required" OIDC enabled but required fields missing Set all required env vars
Server refuses to start with secret length error Key length wrong Generate key of exactly 32 bytes
"OIDC discovery failed" at startup Cannot reach issuer URL Verify OIDC_ISSUER_URL is reachable and returns .well-known/openid-configuration
SSO login redirects but callback returns 400 State mismatch or expired Ensure OIDC_REDIRECT_URL matches IdP; check clock sync
User gets viewer role despite admin group Group ID mismatch Compare group claim value against OIDC_ADMIN_GROUPS; Azure uses GUIDs, Keycloak uses paths
Azure AD user gets viewer despite membership Group overage (200+ groups) Reduce group count or use filtered claims
User gets 403 after successful SSO Account deactivated Check is_active in users table
SSO button not visible Config reports OIDC disabled Verify OIDC_ENABLED=true and API reachable