Skip to content

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)

  1. Org admin navigates to Settings → Security → SSO
  2. Selects "SAML 2.0" as SSO provider
  3. Downloads SP metadata (or copies ACS URL + Entity ID)
  4. Configures IdP (Okta, Entra ID, etc.) with SP metadata
  5. Uploads IdP metadata XML (or enters IdP SSO URL + certificate)
  6. Tests SSO connection with "Test Login" button
  7. Enables "Enforce SSO" — all org members must use SSO
  8. 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)

  1. Org admin selects "OIDC" as SSO provider
  2. Enters discovery URL (or manually: authorization endpoint, token endpoint, JWKS URI)
  3. Enters client ID and client secret (registered in IdP)
  4. Configures redirect URI in IdP (app provides the value)
  5. Tests connection
  6. 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