Files
summercms/.planning/phases/08-oauth2-1-authorization-server/08-04-PLAN.md
2026-09-23 17:46:38 +02:00

8.8 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
phase plan type wave depends_on files_modified autonomous requirements must_haves
08-oauth2-1-authorization-server 04 execute 4
08-03
wristband/token.go
wristband/token_test.go
../fonoteka.go/plugins/golem15/fonoteka/classes/auth/oauth_store.go
../fonoteka.go/plugins/golem15/fonoteka/classes/auth/oauth_token_issuer.go
../fonoteka.go/plugins/golem15/fonoteka/classes/auth/api_token_manager.go
true
AUTH-05
AUTH-06
truths artifacts key_links
D-02: Token rejects JSON before ParseForm body-over-query parsing.
D-04: S256/client-secret comparisons are constant-time and code replay has one winner.
D-05: Wristband owns client authentication, PKCE verification, and atomic code exchange.
D-11: Issued access tokens retain the configured inv_ prefix.
path provides
wristband/token.go Client authentication and atomic authorization-code exchange
from to via pattern
wristband/token.go oauth_token_issuer.go single transaction-bound Tx WithinTx
Complete one atomic authorization-code exchange for the assembled pending-request slice from 08-03.

Purpose: Prove token parsing, client authentication, constant-time PKCE, issuance, and code-replay rules before browser consent wiring. Output: Token handler, issuer adapter, locked store transition, and deterministic/concurrent tests.

<execution_context> @/home/jin/.codex/get-shit-done/workflows/execute-plan.md @/home/jin/.codex/get-shit-done/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/08-oauth2-1-authorization-server/08-CONTEXT.md @.planning/phases/08-oauth2-1-authorization-server/08-RESEARCH.md @.planning/phases/08-oauth2-1-authorization-server/08-03-SUMMARY.md Task 1: Specify atomic code exchange with executable RED tests wristband/token.go, wristband/token_test.go, ../fonoteka.go/plugins/golem15/fonoteka/classes/auth/oauth_store.go, ../fonoteka.go/plugins/golem15/fonoteka/classes/auth/oauth_token_issuer.go .planning/phases/08-oauth2-1-authorization-server/08-CONTEXT.md .planning/phases/08-oauth2-1-authorization-server/08-PATTERNS.md wristband/authorize.go wristband/stores.go ../fonoteka.go/plugins/golem15/fonoteka/classes/auth/api_token_manager.go ../fonoteka.go/plugins/golem15/fonoteka/classes/auth/token_guard.go /media/nvme/dev/golem15/fonoteka/plugins/golem15/fonoteka/controllers/api/OAuthTokenController.php /media/nvme/dev/golem15/fonoteka/plugins/golem15/fonoteka/classes/auth/OAuthCodeManager.php /media/nvme/dev/golem15/fonoteka/plugins/golem15/fonoteka/tests/functional/OAuthTokenTest.php - JSON rejection, ParseForm body-over-query precedence, Basic override, cache headers, exact challenge, and grant dispatch are tested. - S256 code/client/redirect/resource binding and synchronized one-winner replay are tested. - `TestPhase8RedCodeExchange` is the sole selected failure with `PHASE8_RED:code-exchange`. D-18: extend the existing interfaces with compiling token stubs and add deterministic unit plus real-store adapter tests. Validate exact package/test/sentinel through `check-phase8-red.sh go` and `go test -json`; cover T-08-PKCE, CODE-REPLAY, SECRET-TIMING, SCOPE-CEILING, and REQUEST-LEAK, including synchronized concurrent exchange. Every unexpected failing JSON action/package/test, build/setup/panic/no-test event, or missing/duplicate sentinel must fail the RED command. scripts/check-phase8-red.sh go PHASE8_RED:code-exchange git.golem15.com/golem15/summercms/wristband TestPhase8RedCodeExchange -- go test -json ./wristband -run '^TestPhase8RedCodeExchange$' -count=1 - The selected RED test compiles/runs and is the only test fail event; its package is the only package fail event and emits the exact sentinel once. - Tests assert exact status/body/no-newline, `Cache-Control: no-store`, `Pragma: no-cache`, and `Basic realm="OAuth"` only for invalid confidential client. - Synchronized exchange proves exactly one success and one `invalid_grant`; syntax/setup/panic/no-test or any unrelated failure is rejected. The fail-closed RED suite specifies the full code-exchange contract without re-owning authorize behavior. Task 2: Implement atomic PKCE-bound code exchange wristband/token.go, wristband/token_test.go, ../fonoteka.go/plugins/golem15/fonoteka/classes/auth/oauth_store.go, ../fonoteka.go/plugins/golem15/fonoteka/classes/auth/oauth_token_issuer.go, ../fonoteka.go/plugins/golem15/fonoteka/classes/auth/api_token_manager.go wristband/token_test.go wristband/token.go wristband/crypto.go ../fonoteka.go/plugins/golem15/fonoteka/classes/auth/oauth_store.go ../fonoteka.go/plugins/golem15/fonoteka/classes/auth/api_token_manager.go ../fonoteka.go/plugins/golem15/fonoteka/models/api_token.go /media/nvme/dev/golem15/fonoteka/plugins/golem15/fonoteka/controllers/api/OAuthTokenController.php /media/nvme/dev/golem15/fonoteka/plugins/golem15/fonoteka/classes/auth/OAuthCodeManager.php - Token parsing/authentication precedes locked code lookup; code/client/redirect/resource/verifier bindings all match. - Code lock/consume, `inv_` access-token mint/stamp, and refresh creation commit atomically once. D-02: reject JSON before ParseForm, use body-over-query form values, and let Basic credentials override form credentials. D-03: apply configured code/access/refresh TTL and resource. D-04: compare fixed transforms with `subtle.ConstantTimeCompare`. D-05/D-06: keep grant policy and exact raw responses in wristband. D-07: lock/consume/mint/stamp/create refresh within one callback transaction. D-11: make the app issuer prefix config-backed while retaining exact `inv_`. D-17: run expired-only sweep on token entry. Preserve exact Basic challenge and cache headers. go test ./wristband -run '^Test(Token|PKCE|Code)' -count=1 && (cd ../fonoteka.go && go test ./plugins/golem15/fonoteka/classes/auth -run '^TestOAuth(Code|Issuer)' -count=1) - Exact parser cases cover JSON rejection, body-over-query values, Basic-over-form credentials, unsupported/missing grant, public/confidential authentication, and challenge/no-challenge branches. - Correct verifier exchanges once for an `inv_` access token and refresh token with configured lifetimes; wrong verifier/client/redirect/resource and repeated code return exact native errors without minting. - Real-Postgres synchronized exchange has exactly one winner; persisted code is consumed and token/client/collection/scope bindings are correct, with no raw code/secret/verifier logged or stored. One exact PKCE-bound code produces one inv_ access/refresh grant, and all validation/parser/replay failures are exact and tested.

<threat_model>

Trust Boundaries

Boundary Description
Connector → authorize/token Untrusted query/form/Basic input requests or redeems authority.
Tx → access-token store One-time code state becomes durable credentials.

STRIDE Threat Register

Threat ID Category Component Disposition Mitigation Plan
T-08-PKCE Spoofing/Elevation authorize/token mitigate Mandatory S256 syntax and constant-time comparison.
T-08-CODE-REPLAY Spoofing exchange mitigate Row lock, single transaction, concurrent one-winner test.
T-08-OPEN-REDIRECT Spoofing/Disclosure authorize mitigate Exact redirect validation before any redirect.
T-08-SECRET-TIMING Information Disclosure client auth mitigate Fixed transforms and constant-time compare.
T-08-SCOPE-CEILING Elevation authorize mitigate Requested ∩ client ceiling before persistence.
T-08-SC Tampering dependencies mitigate Standard library and existing app services only.
</threat_model>
- Focused wristband and issuer/store tests pass. - Complete race execution is reserved exclusively for Plan 08-10's final blocking checkpoint.

<success_criteria>

  • Authorize and token protocol behavior is exact, concurrency-safe, and app-agnostic.
  • The configured personal-token issuer produces the unchanged inv_ wire format. </success_criteria>
Create `.planning/phases/08-oauth2-1-authorization-server/08-04-SUMMARY.md` when done.