Koder ID Auth — Conformance & Coverage Registry

Tracks which Koder components implement specs/auth/oauth-flow.kmd and run the test template specs/auth/oauth-flow-test-template.kmd across their UI surfaces. Pre-release release engineering MUST verify the row for the releasing component shows green for the enabled surfaces.

Status values:

  • PASS — all 12 cases (T1-T8 + I1-I3 + N1-N4) green
  • PASS¹ — all 12 cases green modulo I1-staging SKIP; the wire

    contract is covered by the G1 central oauth-stub and the SKIP is a deployment artifact (G2 — stg.id.koder.dev provisioning) rather than a coverage gap. Promotes to PASS when G2 lands.

  • PARTIAL — some cases green, some pending (note which)
  • FAIL — test template implemented but blocking failure
  • N/A — surface not shipped for this component
  • TODO — implementation pending
  • SKIP — intentionally skipped with rationale

Surfaces

ID Surface Notes
S1 backend server-side, no user UI; auth applies to API consumers
S2 mobile (Flutter) Android + iOS
S3 desktop (Flutter) Linux + macOS + Windows
S4 tv (React TizenOS/WebOS) device auth grant (RFC 8628)
S5 web (Flutter Web or templ+HTMX)
S6 cli (Go cobra) local loopback flow
S7 tui (Bubble Tea) local loopback flow
S8 desktop shell (native, non-Flutter) session-wide auth; Kolide; libsecret storage

Conformance grid

Date is "last audit date" for the row. Update entry when conformance state changes.

Date Component S1 S2 S3 S4 S5 S6 S7 S8 Notes
2026-05-24 products/dev/flow (Koder Flow) (path corrected 2026-05-24 per RFC-003; previously listed as services/foundation/flow) PASS¹ N/A N/A N/A PASS¹ N/A N/A N/A Promoted PARTIAL → PASS¹ on 2026-05-24 after the FLOW-118 sub-chain landed across FLOW-120..129 (1010 sub-tickets done — epic CLOSED). ¹ = PASS modulo I1-staging SKIP because G2 stg.id.koder.dev is not yet provisioned (the central pkgoauthstub from G1 covers the wire contract end-to-end, so the SKIP is a deployment artifact, not a coverage gap). T8 refresh-rotation landed via FLOW-124 — direct-against-stub contract test since Flow itself does not exercise the refresh path post-login (gothic stores the refreshtoken; never used). Posture drops to plain PASS (no ¹) when G2 unblocks I1. T-SUITE concrete coverage (all PASS unless noted): R1 issuer pin via tests/regression/oauth/001-signin-tmpl-koder-id-only.test.sh + production services/foundation/id OAuth source id=1; R2 kebab slug koder-id via 004-migration-default-provider.test.sh migration check; R3 authorize URL invariants asserted inline in `TestOAuthT2KoderIDStubCallbackWire (clientid, redirecturi, responsetypecode, state, codechallenge S256); **R4** callback 303 to / or /dashboard asserted in T2; **R5** Jet vhost root removed 2026-05-12 + LANDINGPAGE = login; **R6** zero local form via 002-pkce-no-client-secret.test.sh + 004-no-local-signin-form.test.sh; **R7** LinkAccountMode via TestOAuthR7KoderIDStubLinkAccountToExistingEmail (FLOW-126 — auto-link existing fixture user by email match, asserts no duplicate row); **R8** session cookie scope asserted in T2 callback assertion; **R9** redirect_to preserve via TestOAuthR9KoderIDStubDeepLinkPreserve (FLOW-127 — ?redirect_toexplore survives OAuth dance via redirect_to cookie). **T2** callback wire via TestOAuthT2KoderIDStubCallbackWire` (FLOW-121 — full PKCE S256 dance against pkgoauthstub). T3 invalidgrant via `TestOAuthT3KoderIDStubInvalidCode (FLOW-122 — FaultInvalidCode; callback 303 to /user/login). **T4** authenticated-session persists — DELEGATED to Forgejo session middleware (kodersid cookie). **T5** logout via TestOAuthT5KoderIDStubLogout (FLOW-123 — POST /user/logout clears cookie; cross-service oidcv1/endsession is koder_kit concern via KIT-050). **T6** dual-state root via LANDINGPAGE = login + signin.tmpl auto-bounce. **T7** deep-link preserve covered jointly with R9. **T8** refresh rotation — **PENDING FLOW-124** (only outstanding wire case; the pkg/oauthstub handleRefresh rotates correctly per FLOW-120 audit). **N1** state mismatch via TestOAuthN1KoderIDStubStateMismatch (FLOW-125 — FaultStateNoEcho`; callback returns 500, no session). N2 redirecturi tamper covered structurally by stub's exact-match enforcement + would-be N2 test obsoleted since stub rejects at authorize. N3 code replay via TestOAuthN3_KoderIDStub_CodeReplay (FLOW-125 — replay on fresh session returns 500, single-use code defense). N4 open-redirect via TestOAuthN4_KoderIDStub_OpenRedirectDefense (FLOW-127 — `?redirect_to=https:evil falls back to / via httplib.IsRiskyRedirectURL). **I1-I3** SKIP pending G2 staging provisioning. **CI**: .koder-flowworkflowsoauth-regression.yml runs structural (4 bash regressions) + wire (10 Go tests via FLOW-128) on path-filtered triggers. **Source files**: testsintegrationoauthkoderidviastub_test.go (10 tests), testsregressionoauth