Authentication & SSO¶
OWNER: aimee ALSO_USED_BY: anna, hugo (implementation), faye, sytske
Enterprise SSO is a revenue unlock. Deals above EUR 10k/year rarely close without it. This page covers the full authentication surface for B2B SaaS on the GE stack.
Authentication Tiers¶
| Tier | Features | Typical Plan |
|---|---|---|
| Basic | Email/password, email verification, password reset | Free / Starter |
| Standard | + Social login, MFA (TOTP), session management | Professional |
| Enterprise | + SAML SSO, OIDC, SCIM, MFA enforcement, IP allowlist | Enterprise |
CHECK: Determine tier requirements during scoping — this drives auth architecture choice CHECK: If enterprise tier expected within 6 months, build on Keycloak from day one
Auth Architecture Decision¶
SCOPE_ITEM: auth_architecture_selection IF: Client expects < 50 organizations, no enterprise SSO requirement THEN: Use NextAuth.js with Drizzle adapter — simpler, fewer moving parts IF: Client expects enterprise customers OR SSO requirement within 12 months THEN: Use Keycloak — full IdP with SAML, OIDC, SCIM, MFA out of the box IF: Client needs both simplicity now AND enterprise SSO later THEN: Start with NextAuth.js, plan Keycloak migration as Phase 2 (budget 60-80 hours)
NextAuth.js Pattern (GE Stack)¶
INCLUDES: NextAuth.js v5 with Drizzle adapter
INCLUDES: Credential provider (email/password with bcrypt)
INCLUDES: OAuth providers (Google, Microsoft, GitHub)
INCLUDES: JWT strategy with short-lived access tokens (15 min)
INCLUDES: Refresh token rotation (7-day lifetime)
INCLUDES: Session callback injects org_id, role, permissions into token
Keycloak Pattern (GE Stack)¶
INCLUDES: Keycloak deployed as Docker container (EU-hosted)
INCLUDES: Realm per environment (dev, staging, production)
INCLUDES: Identity brokering for social login and corporate IdPs
INCLUDES: SAML 2.0 and OIDC protocol support out of the box
INCLUDES: SCIM plugin for directory sync
INCLUDES: Custom theme matching client's brand
INCLUDES: Admin API for programmatic user/org management
CHECK: Keycloak adds infrastructure cost (~1 vCPU, 2GB RAM) — include in hosting estimate
Corporate SSO — SAML 2.0¶
SCOPE_ITEM: saml_sso INCLUDES: Service Provider (SP) metadata generation INCLUDES: IdP metadata import (XML upload or metadata URL) INCLUDES: SP-initiated flow (user starts at app login page) INCLUDES: IdP-initiated flow (user starts at corporate portal) INCLUDES: Assertion signature validation (RSA-SHA256) INCLUDES: Certificate rotation support (accept old + new during rollover) INCLUDES: Attribute mapping (email, first_name, last_name, groups) INCLUDES: Per-organization SAML configuration COMPLIANCE: XML parser hardened — disable external entities (XXE prevention) COMPLIANCE: Assertions encrypted with AES-256 (optional but recommended) COMPLIANCE: Relay state validated to prevent open redirect
SAML Setup Flow (Admin Experience)¶
- Org admin navigates to Settings → Security → SSO
- Selects "SAML 2.0" as SSO provider
- Downloads SP metadata (or copies ACS URL + Entity ID)
- Configures IdP (Okta, Entra ID, etc.) with SP metadata
- Uploads IdP metadata XML (or enters IdP SSO URL + certificate)
- Tests SSO connection with "Test Login" button
- Enables "Enforce SSO" — all org members must use SSO
- Email/password login disabled for org members when SSO enforced
CHECK: Test against Okta, Microsoft Entra ID, Google Workspace, and OneLogin CHECK: IdP-initiated flow requires RelayState handling — do not skip CHECK: Certificate expiry monitoring — alert org admin 30 days before expiry
SP-Initiated vs IdP-Initiated¶
SCOPE_ITEM: sp_initiated_sso INCLUDES: User enters email on login page INCLUDES: App looks up org by email domain INCLUDES: App redirects to IdP with SAML AuthnRequest INCLUDES: IdP authenticates user INCLUDES: IdP redirects back to ACS URL with SAML Response INCLUDES: App validates assertion, creates/updates user, creates session
SCOPE_ITEM: idp_initiated_sso INCLUDES: User clicks app tile in corporate portal (Okta dashboard, etc.) INCLUDES: IdP sends unsolicited SAML Response to ACS URL INCLUDES: App validates assertion (no matching AuthnRequest — stateless validation) INCLUDES: App creates session, redirects to dashboard CHECK: IdP-initiated is less secure (no request-response binding) — some security teams reject it CHECK: Must validate InResponseTo is empty (not a replayed SP-initiated response)
Corporate SSO — OIDC¶
SCOPE_ITEM: oidc_sso INCLUDES: Authorization Code Flow with PKCE (mandatory for public clients) INCLUDES: Per-organization OIDC provider configuration INCLUDES: Discovery document support (.well-known/openid-configuration) INCLUDES: Token validation (signature, issuer, audience, expiry) INCLUDES: Userinfo endpoint fallback for missing claims INCLUDES: ID token claim mapping (email, name, groups) CHECK: OIDC is simpler to implement than SAML — prefer when IdP supports it CHECK: Some enterprise IdPs (older ADFS) only support SAML — must support both
OIDC Setup Flow (Admin Experience)¶
- Org admin selects "OIDC" as SSO provider
- Enters discovery URL (or manually: authorization endpoint, token endpoint, JWKS URI)
- Enters client ID and client secret (registered in IdP)
- Configures redirect URI in IdP (app provides the value)
- Tests connection
- Enables enforcement
SCIM 2.0 Directory Sync¶
SCOPE_ITEM: scim_provisioning INCLUDES: SCIM 2.0 server endpoints (/Users, /Groups) INCLUDES: SCIM bearer token authentication (per-org token) INCLUDES: Create user (POST /Users) INCLUDES: Update user (PATCH /Users/{id}) — name, email, active status INCLUDES: Deactivate user (PATCH active=false) — immediate access revocation INCLUDES: Delete user (DELETE /Users/{id}) — maps to deactivation, not data deletion INCLUDES: Group sync (create, update members, delete) INCLUDES: Group-to-role mapping (IdP group "Engineering" → app role "Member") OPTIONAL: Custom SCIM attributes (department, job title, cost center) COMPLIANCE: SCIM deprovisioning must revoke access within 60 seconds CHECK: Test against Okta SCIM provisioning and Microsoft Entra ID SCIM
SCIM Implementation Notes¶
SCOPE_ITEM: scim_endpoints
INCLUDES: GET /scim/v2/Users — list users (pagination, filtering)
INCLUDES: GET /scim/v2/Users/{id} — get user
INCLUDES: POST /scim/v2/Users — create user
INCLUDES: PATCH /scim/v2/Users/{id} — partial update
INCLUDES: PUT /scim/v2/Users/{id} — full replace
INCLUDES: DELETE /scim/v2/Users/{id} — deactivate
INCLUDES: GET /scim/v2/Groups — list groups
INCLUDES: POST /scim/v2/Groups — create group
INCLUDES: PATCH /scim/v2/Groups/{id} — update membership
CHECK: SCIM filtering uses a specific syntax (eq, co, sw operators) — implement parser CHECK: Okta sends PATCH with "Operations" array — handle multi-operation patches CHECK: Rate limit SCIM endpoints (100 req/min per org) to prevent IdP sync storms
JIT (Just-In-Time) Provisioning¶
SCOPE_ITEM: jit_provisioning INCLUDES: User created on first SSO login (no pre-registration needed) INCLUDES: User attributes populated from SSO assertion (name, email, groups) INCLUDES: Default role assigned (configurable per org) INCLUDES: Group-to-role mapping applied on each login (roles updated dynamically) INCLUDES: JIT does NOT create organization — org must exist first CHECK: JIT + SCIM can conflict — if SCIM is active, JIT should only update, not create CHECK: JIT provisioning must be audit-logged (who was auto-created, when, with what role)
MFA Enforcement¶
SCOPE_ITEM: mfa_enforcement INCLUDES: TOTP (RFC 6238) — authenticator app (Google Authenticator, Authy, 1Password) INCLUDES: Recovery codes (10 codes, single-use, shown once at setup) INCLUDES: MFA setup flow with QR code and manual entry fallback INCLUDES: Org-level MFA enforcement (admin requires all members to enable MFA) INCLUDES: Grace period for MFA enforcement (7 days to set up after policy change) OPTIONAL: WebAuthn / passkeys (hardware keys, platform authenticators) OPTIONAL: SMS MFA (discouraged — SIM swap vulnerability, regulatory issues in EU) COMPLIANCE: MFA enforcement required for SOC 2 Type II CHECK: If SSO is enforced, MFA is handled by IdP — do not double-MFA
MFA Decision Matrix¶
IF: Org uses SSO with IdP-enforced MFA THEN: App-level MFA is redundant — disable for SSO users IF: Org uses email/password auth THEN: MFA should be available and strongly encouraged IF: Org is on enterprise plan THEN: MFA enforcement toggle visible in security settings IF: Platform admin access THEN: MFA is always mandatory — non-negotiable
Session Management¶
SCOPE_ITEM: session_management INCLUDES: Short-lived access tokens (15 minutes) INCLUDES: Refresh tokens with rotation (7-day lifetime, single-use) INCLUDES: Session stored server-side (PostgreSQL or Redis) INCLUDES: Session metadata (IP, user agent, last active, created_at) INCLUDES: Active sessions list in user settings INCLUDES: Revoke individual session or all sessions INCLUDES: Force logout (admin can terminate any user's sessions) INCLUDES: Idle timeout (configurable, default 30 minutes) COMPLIANCE: Session tokens httpOnly, Secure, SameSite=Lax COMPLIANCE: Refresh token rotation prevents token replay CHECK: Do not store session tokens in localStorage — XSS risk
Session Limits¶
IF: Client wants concurrent session limits THEN: Implement per-user max sessions (default: 5 across devices) IF: User exceeds session limit THEN: Oldest session is terminated (FIFO), user notified via email
Domain-Based Org Detection¶
SCOPE_ITEM: domain_org_mapping INCLUDES: Email domain mapped to organization (e.g., @acme.com → Acme Inc org) INCLUDES: Domain verification via DNS TXT record INCLUDES: Multiple domains per org (e.g., @acme.com, @acme.nl, @acme.de) INCLUDES: Auto-join policy (users with matching email domain auto-join org) OPTIONAL: Domain claim (org claims a domain, no other org can use it) CHECK: Domain verification prevents org spoofing — required for SSO enforcement
Keycloak Integration Patterns (GE-Specific)¶
Deployment¶
SCOPE_ITEM: keycloak_deployment
INCLUDES: Keycloak 25+ (Quarkus distribution)
INCLUDES: PostgreSQL as Keycloak database (separate from app DB)
INCLUDES: EU-hosted (same region as application)
INCLUDES: TLS termination at load balancer
INCLUDES: Custom theme for login pages (matches client brand)
INCLUDES: Health check endpoint for monitoring
Realm Configuration¶
SCOPE_ITEM: keycloak_realm
INCLUDES: One realm per environment (dev, staging, production)
INCLUDES: Client registration for the SaaS application
INCLUDES: Identity brokering for each customer's IdP
INCLUDES: Authentication flow customization (MFA step, conditional SSO)
INCLUDES: User federation (LDAP connector for legacy clients)
INCLUDES: Event logging (login, logout, errors → forwarded to app audit log)
App Integration¶
SCOPE_ITEM: keycloak_app_integration
INCLUDES: OIDC client in Keycloak for the SaaS application
INCLUDES: Token exchange for API-to-API calls
INCLUDES: Admin API client for user management operations
INCLUDES: Webhook events from Keycloak to app (user created, role changed)
INCLUDES: Mapper for custom claims (org_id, tenant_id in JWT)
CHECK: Keycloak admin API uses service account auth — store credentials in Vault CHECK: Keycloak upgrade path — pin to LTS versions, test upgrades in staging first