feat(common-oauth): RelyingParty full flow (authorize, token, refresh)
Implement Task 2 from Phase 7 Subcomponent A:
- RelyingParty already has do_authorize, do_token, do_refresh methods
- do_authorize: GET authorize endpoint with request_uri, follow redirects manually
- do_token: POST form-encoded body with code + PKCE verifier + DPoP proof
- do_refresh: POST form-encoded body with refresh_token + DPoP proof
- All three methods handle DPoP use_dpop_nonce retry on 400 errors
- Add TokenResponse struct (deserialize from token endpoint JSON)
- Add AuthorizeOutcome enum (Code { code } | Error { error, error_description })
- Add FlowScript enum to fake_as/endpoints.rs for controlling AS behavior
- Approve: issue requested scope
- PartialGrant: issue subset of requested scope
- Deny: send access_denied error
- DpopNonceRetryOnPar: force DPoP nonce retry on PAR
- Extend AppState with:
- flow_script: Mutex<FlowScript> for scripting AS responses
- next_codes: Mutex<VecDeque<String>> for deterministic code issuance
- refresh_tokens: Mutex<HashMap<String, TokenBinding>> for token binding
- Add TokenBinding struct to carry token metadata (scope, DPoP thumbprint)
Integration tests with fake AS come in Task 3 (real PAR/authorize/token validation).
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>