WakaStart
Authentication

Authentication — Concepts & Flow

Overview of the Wakastart OAuth2 PKCE flow: key concepts, complete diagram and Keycloak prerequisites.

Version v1.04 min read

Authentication — Concepts & Flow

Since IAM-S0 / IAM-C4 (May 2026) — The Keycloak realm is no longer built on the frontend side. Discovery exposes a public POST /discover/start-login endpoint that resolves the realm + client_id from the host and returns a ready-to-follow Keycloak URL. No Wakapp holds INTERNAL_API_SECRET.

Why this step

Authentication is the most critical flow of your integration. A poorly implemented flow exposes you to vulnerabilities (code interception, CSRF, token leakage). PKCE (Proof Key for Code Exchange) is mandatory and guarantees that an OIDC code stolen in transit is unusable without the code_verifier known only to the legitimate client.

The Wakastart flow adds two steps specific to the platform: start-login (Discovery resolves the realm) and enrich (the BFF enriches the Keycloak JWT with application access rights: admin/team levels and resource.action rights).

Key concepts

  • code_verifier: random 43-128 char string, generated client-side, stored in sessionStorage.
  • code_challenge: BASE64URL(SHA256(code_verifier)), sent to Keycloak.
  • access_token: RS256 JWT issued by Keycloak, short lifetime (5-15 min).
  • refresh_token: long-lived token used to obtain new access_tokens.
  • wakaToken: JWT signed by the WakaStart authentication service, containing the business rights. Mandatory to call downstream services.
  • enrichment: proprietary step that turns the basic Keycloak JWT into an enriched wakaToken.

Complete flow in 10 steps

Loading diagram…

Keycloak prerequisites — OIDC client

For the flow to work, the OIDC client must be configured as follows:

ParameterValueReason
Client IDValue of apps.client_id in the DB (auto-generated from the WID)Discovery resolves this client_id
Client authenticationOFF (public client)PKCE without a secret — mandatory
AuthorizationOFFNot necessary
Standard flowONOAuth2 PKCE flow
Direct access grantsOFF (recommended)Avoid Resource Owner Password Credentials
Implicit flowOFFDeprecated, insecure
PKCE MethodS256Mandatory
Valid redirect URIshttps://app.<tenant>.<platform>/api/auth/callback (exact path, no wildcard)Exact match on Keycloak — a single callback per environment
Web originshttps://app.<tenant>.<platform>CORS pre-flight

Security — Never declare a wildcard (/*) in redirect URIs. Any valid path as a redirect is an Open Redirect target if an application route is compromised (XSS, subdomain takeover). Declare one exact callback per environment (typically /api/auth/callback) and add a second exact callback for logout if needed.

Client authentication: ON causes Invalid client or Invalid client credentials at the token exchange — Keycloak expects a client_secret that public PKCE does not provide. This is the first thing to check in case of a 401 on callback.


Keycloak Organizations (IAM-C4 — mandatory)

The WakaStart authentication service rejects any Keycloak token without the organization claim. Three conditions must be met:

1. Realm — Organizations feature enabled

Console Keycloak → realm → Realm settings → General → "Organizations enabled"

This automatically creates an organization client scope at the realm level.

2. OIDC client — organization scope attached as default

Console Keycloak → realm → Clients → {client_id} → Client scopes → ajouter "organization" en Default

Automated by npx prisma db seed.

3. User — member of a Keycloak organization For each Customer in the DB, a Keycloak organization exists (alias = customer.wid). Active users must be members of it. Automated by npx ts-node prisma/backfill-keycloak-orgs.ts (idempotent).

Without these 3 conditions: enrichment returns 401 and the user sees an "Missing or invalid enriched token" error.


Error handling at the callback

CaseSymptomSolution
redirect_uri mismatch400 Invalid redirect_uri from KeycloakCheck the exact URI match in the Keycloak console
Incorrect client_id401 Invalid clientExtract client_id from the keycloakUrl, do not hardcode it
Incorrect code_verifier400 invalid_grantCheck verifier/challenge consistency (do not re-encode)
Missing organization401 Missing enriched tokenEnable Organizations + attach the scope to the client (see above)
Enrich failswakastart_token missing from cookiesLog the HTTP response of /api/auth/enrich

Learn more