--- phase: 08-oauth2-1-authorization-server plan: 01 type: execute wave: 1 depends_on: [] files_modified: - wristband/server.go - wristband/stores.go - wristband/crypto.go - wristband/register.go - wristband/registration_test.go - scripts/check-phase8-red.sh autonomous: true requirements: [AUTH-05, AUTH-06] must_haves: truths: - "D-01: The app-agnostic standard-library wristband package serves exact RFC 8414 metadata and validates RFC 7591 registration without zitadel/oidc." - "D-06: PHP-minimal response shapes and configurable metadata fields are wristband defaults with no response hooks." - "D-02: Registration is JSON-only, and D-21: its body is bounded at 64 KiB before decoding with endpoint-native errors." - "D-04: Client-secret checks use constant-time fixed transforms and DCR cap/sweep behavior is deterministic under concurrency." artifacts: - path: "wristband/server.go" provides: "Options, exact metadata writer, and app-agnostic server contract" - path: "wristband/register.go" provides: "RFC 7591 validation, issuance, cap, sweep, and bounded handler" - path: "scripts/check-phase8-red.sh" provides: "Fail-closed RED verifier rejecting syntax/setup/missing-test failures" key_links: - from: "wristband/register.go" to: "wristband.Backend.WithinTx" via: "serialized sweep, cap check, and create" pattern: "WithinTx" --- Define and implement the framework-only discovery and dynamic-registration contract before app persistence or routing. Purpose: Keep D-01's protocol engine small and app-agnostic while making the RED phase executable and diagnostic. Output: `wristband` metadata/DCR contracts, deterministic tests, crypto helpers, and the shared RED verifier. ## Phase Goal **As a** connector implementer, **I want to** exercise discovery and registration against a deterministic OAuth engine, **so that** the app adapter can persist and mount an already proven wire contract. @/home/jin/.codex/get-shit-done/workflows/execute-plan.md @/home/jin/.codex/get-shit-done/templates/summary.md @.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-PATTERNS.md @.planning/phases/08-oauth2-1-authorization-server/08-VALIDATION.md Task 1: Create compiling RED discovery and registration contracts wristband/server.go, wristband/stores.go, wristband/registration_test.go, scripts/check-phase8-red.sh - Metadata is the exact unwrapped 11-field document with recorded order, content type, and cache header. - Public and confidential DCR validate PHP-compatible URI, grant, response, auth-method, cap, sweep, and 65,536-byte rules. - Test failures use `PHASE8_RED:registration` only for missing behavior; syntax, build, setup, missing-test, panic, and unrelated failures are rejected. D-06: define the exported options, typed records, transaction-scoped Backend/Tx contracts, handler signatures, and deterministic clock/random seams with compiling stubs. D-18: add behavior tests that compile and intentionally fail through `PHASE8_RED:registration` assertions. Create `scripts/check-phase8-red.sh` to run the supplied command, require a nonzero result and the requested marker, and fail if output contains `build failed`, `setup failed`, `syntax error`, `no tests to run`, `no test files`, or a panic. Include named T-08-DCR-FLOOD, T-08-SECRET-TIMING, and T-08-REQUEST-LEAK cases. Commit RED separately. scripts/check-phase8-red.sh registration go test ./wristband -run 'Test(Metadata|Register|Registration)' -count=1 The tests compile, the named tests execute, and the verifier accepts only the expected missing-behavior RED marker. Task 2: Implement exact metadata, DCR, bounds, and cryptography wristband/server.go, wristband/stores.go, wristband/crypto.go, wristband/register.go, wristband/registration_test.go - Fixed SHA-256 transforms use `crypto/subtle.ConstantTimeCompare`; raw client secrets are returned once and never persisted/logged. - Sweep, cap check, and create occur within one backend transaction; concurrent registrations cannot cross the cap. - Oversized and malformed registration input returns exact `invalid_client_metadata` bytes without a house envelope. D-01: use only `crypto/rand`, `crypto/sha256`, `crypto/subtle`, `encoding/base64`, `encoding/json`, `net/http`, and `net/url`; add no dependency. D-03: model configurable TTLs, cap 200, stale age 24h, issuer/resource/endpoints, and `RegisterMaxBytes: 65536`. D-05: keep all protocol rules in wristband and import no fonoteka/GORM code. D-06: use a local no-newline exact JSON writer with no response hooks. D-07: use only the transaction-scoped interfaces. D-17: expose expired-row and unconsented-client sweep operations without timers/goroutines. D-21: apply `http.MaxBytesReader` before JSON decode. Strip control characters and cap names at 120 characters. go test ./wristband -run 'Test(Metadata|Register|Registration)' -count=1 Framework discovery and DCR tests pass with exact bytes, atomic cap behavior, bounded decoding, hash-only persistence, and no app-tier imports. ## Trust Boundaries | Boundary | Description | |----------|-------------| | Connector → wristband | Untrusted metadata/DCR requests cross into protocol parsing. | | wristband → Backend | Protocol state crosses into an app-provided transaction. | ## STRIDE Threat Register | Threat ID | Category | Component | Disposition | Mitigation Plan | |-----------|----------|-----------|-------------|-----------------| | T-08-DCR-FLOOD | Denial of Service | register handler/store | mitigate | 64 KiB cap, serialized client cap, stale sweep, concurrency tests. | | T-08-SECRET-TIMING | Information Disclosure | crypto/client secret | mitigate | Fixed SHA-256 transforms and `subtle.ConstantTimeCompare`. | | T-08-REQUEST-LEAK | Information Disclosure | handler/tests | mitigate | Hash-only records and no sensitive-value logging. | | T-08-SC | Tampering | dependencies | mitigate | No package install; stdlib-only import audit. | - `go test ./wristband -count=1` - `go list -deps ./wristband | rg 'fonoteka|gorm.io'` returns no matches. - Exact metadata and DCR behavior is green in a self-contained framework package. - RED verification cannot pass on mere file presence, compile errors, missing tests, or unrelated failures. - DCR is bounded, concurrency-safe, and secret-safe before app integration. Create `.planning/phases/08-oauth2-1-authorization-server/08-01-SUMMARY.md` when done.