Keycloak: paldocs (OIDC Client, Themes, Secrets Wiring)

arch-keycloak-paldocs Architecture

architecture

Keycloak: paldocs

OIDC authentication for paldocs, following the established pattern from landscaping-assistant (the reference implementation for Rails + Keycloak on this platform).

Diagram

Components

Component Purpose Notes
Keycloak Server Identity provider (OIDC) quay.io/keycloak/keycloak:26.0.7, <code>keycloak</code> namespace, URL: <code>https://keycloak.tail5b443a.ts.net</code>. H2 dev-file DB with 2Gi PVC.
Keycloak Realm (TBD) Auth boundary for paldocs users Each project gets its own realm (platform convention). Managed via <code>keycloak_realms</code> map in <code>pal-e-services/terraform/k3s.tfvars</code>.
OIDC Client (TBD) paldocs client registration in Keycloak Confidential, Auth Code + PKCE (S256), realm roles mapper enabled, refresh tokens enabled. Managed via <code>keycloak_clients</code> map in <code>k3s.tfvars</code>, applied by <code>keycloak.tf</code> for_each.
Login Theme CSS-only branded login page Three-repo pattern: source in paldocs repo (<code>keycloak-theme/</code>), ConfigMap in pal-e-platform (<code>modules/keycloak/main.tf</code>), <code>login_theme</code> on realm in pal-e-services. Extends base <code>keycloak</code> parent theme.
OmniAuth (Rails) Server-side OIDC integration <code>omniauth-openid-connect</code> gem. Callback: <code>/auth/keycloak/callback</code>. Session stores user info from ID token.
NetworkPolicy Network access from paldocs to keycloak namespace Keycloak has default-deny ingress. Currently allows: tailscale, westside-ai-assistant, pal-enterprises, landscaping-assistant, monitoring. Paldocs must be added.

Key Decisions

  • Confidential client, not public: Rails is server-rendered. The client secret stays on the server and never reaches the browser. Matches pal-enterprises and landscaping-assistant patterns.
  • Auth Code + PKCE, not ROPC: Direct Access Grants (ROPC) is prohibited by OAuth 2.1 (RFC 9700). Landscaping-assistant tried ROPC and immediately reverted (PR #158). PKCE S256 is defense-in-depth even for confidential clients.
  • Refresh tokens enabled: Required for long-lived mobile sessions (turbo-ios). Users expect to stay logged in on their phones.
  • Realm roles in tokens: include_realm_roles_mapper = true puts roles at realm_access.roles in the ID/access token. Rails reads roles directly from the token without an extra Keycloak API call.
  • CSS-only theme: No custom FreeMarker templates, no Docker image rebuild. CSS overrides PatternFly defaults. Design tokens mirror the paldocs application.css.
  • Terraform-managed, not manual: Adding a client is a k3s.tfvars entry + tofu apply. The old SOP for manual admin console creation is superseded.
  • arch-infra -- Public domain affects Keycloak redirect URIs (paldocs.app/auth/keycloak/callback)
  • arch-k8s -- Deployment overlay needs KEYCLOAK_* env vars from k8s secret
  • arch-rails-db -- Shared database where user/session data lives
  • story-paldocs-ios-testflight -- Auth is on the critical path for iOS
  • paldocs #26 -- Keycloak TF client creation
  • paldocs #82 -- Login theme
  • pal-e-deployments #224 -- KEYCLOAK env vars in deployment overlay
  • pal-e-platform #303 -- Keycloak client tracking (platform-level)
  • arch-keycloak -- pal-enterprises Keycloak note (same platform pattern, different project)
  • landscaping-assistant/docs/keycloak-setup.md -- Reference: complete walkthrough of the same pattern
  • landscaping-assistant/docs/auth-strategy.md -- Reference: Auth Code + PKCE rationale
  • pal-e-services/terraform/keycloak.tf -- OIDC client resources (for_each on keycloak_clients)