#214: OIDC Authorization Code with PKCE, Keycloak as reference IdP #282

Closed
fable-5 wants to merge 0 commits from issue-214-oidc into main
Collaborator

External authentication (ADR 0021) on jose + fetch - no new dependency for a security base function. Discovery-based; JWKS validation under an explicit RS256/ES256 allowlist with issuer/audience/expiry/nonce binding; state+nonce+PKCE verifier in a signed HttpOnly Lax cookie (dedicated HKDF purpose). Deploy-level config (OIDC_*); login page discovers the provider via GET /auth/methods. JIT accounts (ACTIVE, verified-mail required); NO silent adoption by e-mail - oidc_link_required plus the explicit link flow (audited, catalogue v1.3). Tests against a protocol-faithful fake IdP (invalid state/nonce/signature/issuer/audience/expiry each rejected); verified end-to-end against real Keycloak 26.0 (repeatable procedure in security.md). Part of M27. Refs #214

External authentication (ADR 0021) on jose + fetch - no new dependency for a security base function. Discovery-based; JWKS validation under an explicit RS256/ES256 allowlist with issuer/audience/expiry/nonce binding; state+nonce+PKCE verifier in a signed HttpOnly Lax cookie (dedicated HKDF purpose). Deploy-level config (OIDC_*); login page discovers the provider via GET /auth/methods. JIT accounts (ACTIVE, verified-mail required); NO silent adoption by e-mail - oidc_link_required plus the explicit link flow (audited, catalogue v1.3). Tests against a protocol-faithful fake IdP (invalid state/nonce/signature/issuer/audience/expiry each rejected); verified end-to-end against real Keycloak 26.0 (repeatable procedure in security.md). Part of M27. Refs #214
fable-5 added 1 commit 2026-07-31 13:09:52 +02:00
#214: OIDC Authorization Code with PKCE, Keycloak as reference IdP
Some checks failed
CI / Lint, typecheck, test (pull_request) Failing after 14s
CI / Import/export fidelity gate (pull_request) Has been skipped
CI / Build container images (pull_request) Has been skipped
CI / Auth e2e pack (pull_request) Has been skipped
5796b7a5dd
External authentication (ADR 0021) built on jose (#188's vetted library)
plus fetch — no new dependency enters the supply chain for a security
base function. Discovery-configured; ID tokens validate against the
IdP's JWKS under an explicit RS256/ES256 allowlist with issuer,
audience, expiry and nonce binding. State, nonce and the PKCE verifier
travel in a signed HttpOnly Lax cookie keyed by a dedicated HKDF
purpose (oidc-state, ADR 0020).

Deploy-level configuration (OIDC_ISSUER/CLIENT_ID/CLIENT_SECRET/SCOPES/
PROVIDER_LABEL): who authenticates users is a platform decision. The
login page discovers the provider via GET /auth/methods and renders the
SSO button (i18n de+en).

Identities use the existing slot (provider oidc:<issuer>, subject from
the token). First login creates the account just-in-time — ACTIVE and
mail-verified only when the IdP asserts a verified address. An existing
local account is NEVER adopted silently by e-mail (account-takeover
path): login refuses with oidc_link_required and the owner links
explicitly via GET /auth/oidc/link (audited auth.identity_linked,
catalogue v1.3). Sessions come from the one existing session service.

Tests run the full flow against a protocol-faithful fake IdP: PKCE
verifier at the token endpoint, JIT creation incl. personal pond,
invalid state/nonce/signature/issuer/audience/expiry each rejected, the
linking refusal and the explicit link flow. Verified end-to-end against
a real Keycloak 26.0 (repeatable procedure documented in security.md
§External authentication).

Refs #214.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AUtYMxwTCMHG9mVHnwbFg8
Author
Collaborator

Contained in the fast-forward merges of PRs #283-#285 (runs 602-604 green over the cumulative diffs incl. this PR commits; this PR own run 601 failed only on the known runner-infra signature: corrupted action cache, dist/pnpm.cjs). Commits are on main - closed like #268/#275/#279/#280.

Contained in the fast-forward merges of PRs #283-#285 (runs 602-604 green over the cumulative diffs incl. this PR commits; this PR own run 601 failed only on the known runner-infra signature: corrupted action cache, dist/pnpm.cjs). Commits are on main - closed like #268/#275/#279/#280.
fable-5 closed this pull request 2026-07-31 13:36:21 +02:00
Some checks failed
CI / Lint, typecheck, test (pull_request) Failing after 14s
Required
Details
CI / Import/export fidelity gate (pull_request) Has been skipped
CI / Build container images (pull_request) Has been skipped
Required
Details
CI / Auth e2e pack (pull_request) Has been skipped

Pull request closed

Sign in to join this conversation.
No description provided.