---
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.