patch feat/companion-app #9 / 15
aaronrene · 4 days ago · Jun 5, 2026 · Diff

Phase 3: companion OAuth native/public client (PKCE + loopback redirect)

Pure, I/O-free protocol core + token custody for the companion's native/public OAuth client (RFC 7636 PKCE S256-only, RFC 8252 loopback redirect, RFC 9207 iss optional-but-validated). No socket bound, no network, no real keychain I/O — all deferred to the Phase 5 shared bind gate (mirrors Phase 1/2 pure-then-bind).

- lib/companion-oauth-pkce.mjs: createPkcePair, computeCodeChallenge (Appendix B vector), createOAuthState/createNonce, buildAuthorizationUrl, validateRedirectUri, validateAuthorizationResponse (constant-time state + iss), buildTokenRequest/ buildRefreshRequest, validateTokenResponse, decideTokenRefresh. Provider-agnostic (endpoints/client_id/scopes injected): registers no client, alters no scopes. - lib/companion-token-custody.mjs: pure custody over an injected keychain adapter; JWT/refresh rotation + Phase 2 per-session loopback-token lifecycle. No real keychain calls; never logs a secret. - 7-tier suites for both modules (237 companion tests green); security tier is the centerpiece (S256 binding, no plain downgrade, constant-time state, RFC 8252 redirect allowlist, no client secret, code_verifier present, oversized/replay fail-closed, no secret in any output/reason/error). - docs/COMPANION-APP-PHASE-3-OAUTH-PKCE.md: threat model -> control map, RFC citations, custody/rotation rules, Phase 5 safe-bind checklist, and the separate server-side OAuth gate (web-session-equivalent scopes, hosted PKCE, iss emission).

sha256:c7e4193ed8fb8402ba382ccddde1f7f55974111a5c17d40dc94d0fd26802a378 sha
+57 symbols
sha256:edce1a04ce18a4316d7e6d15b912d337dde4954942090971574f061955291ea8 snapshot
+57
symbols added
0
dead code introduced
Semantic Changes 57 symbols
+ Companion App — Phase 3: OAuth Native/Public Client (PKCE + Loopback Redirect) section Companion App — Phase 3: OAuth Native/Public Client (PKCE + Loopback Redirect) L1–298
+ Scope decisions (owner-approved 2026-06-05) section 1. Scope decisions (owner-approved 2026-06-05) L69–118
+ 1 — Pure-then-bind (CONFIRMED) section D-P3.1 — Pure-then-bind (CONFIRMED) L71–80
+ 2 — Provider-agnostic core; client-registration boundary respected (CONFIRMED) section D-P3.2 — Provider-agnostic core; client-registration boundary respected (CONFIRMED) L80–107
+ 3 — RFC 9207 iss: optional-but-validated (CONFIRMED) section D-P3.3 — RFC 9207 iss: optional-but-validated (CONFIRMED) L107–118
+ Adversarial threat model → exact control section 2. Adversarial threat model → exact control L118–140
+ table section table L125–137
+ mjs section 3. Module contract — lib/companion-oauth-pkce.mjs L140–162
+ table section table L144–157
+ mjs section 4. Module contract — lib/companion-token-custody.mjs L162–189
+ RFC conformance section 5. RFC conformance L189–209
+ What Phase 5 must do to bind safely section 6. What Phase 5 must do to bind safely L209–246
+ Server-side OAuth gate (Phase 5 prerequisite) section 7. Server-side OAuth gate (Phase 5 prerequisite) L246–269
+ Test obligations satisfied (gate §10, 7 tiers × 2 modules) section 8. Test obligations satisfied (gate §10, 7 tiers × 2 modules) L269–290
+ table section table L273–282
+ Deferred (explicitly not Phase 3) section 9. Deferred (explicitly not Phase 3) L290–298
+ Simple summary section Simple summary L18–41
+ Technical summary section Technical summary L41–69
~ lib/companion-oauth-pkce.mjs .mjs 13 symbols added
+ buildAuthorizationUrl function function buildAuthorizationUrl L305–381
+ buildRefreshRequest function function buildRefreshRequest L546–587
+ buildTokenRequest function function buildTokenRequest L478–531
+ computeCodeChallenge function function computeCodeChallenge L154–164
+ constantTimeEqual function function constantTimeEqual L134–140
+ createNonce function function createNonce L195–197
+ createOAuthState function function createOAuthState L186–188
+ createPkcePair function function createPkcePair L175–179
+ decideTokenRefresh function function decideTokenRefresh L680–695
+ validateAuthorizationResponse function function validateAuthorizationResponse L407–457
+ validateRedirectUri function function validateRedirectUri L221–262
+ validateScopes function function validateScopes L269–277
+ validateTokenResponse function function validateTokenResponse L604–664
~ lib/companion-token-custody.mjs .mjs 14 symbols added
+ buildSessionMeta function function buildSessionMeta L110–132
+ clearLoopbackToken function async_function clearLoopbackToken L282–284
+ clearSession function async_function clearSession L241–245
+ createTokenCustody function function createTokenCustody L152–297
+ decide function async_function decide L251–260
+ getLoopbackToken function async_function getLoopbackToken L268–271
+ loadSession function async_function loadSession L209–234
+ requireAdapter function function requireAdapter L70–81
+ requireSecret function function requireSecret L89–94
+ rotateLoopbackToken function async_function rotateLoopbackToken L277–279
+ serializeMeta function function serializeMeta L156–168
+ storeLoopbackToken function async_function storeLoopbackToken L263–265
+ storeSession function async_function storeSession L174–185
+ updateAccessToken function async_function updateAccessToken L191–203
+ authorize method method authorize L35–49
+ makeSimulatedServer function function makeSimulatedServer L31–68
+ token method method token L50–66
+ timed function function timed L22–26
+ timed function function timed L10–13
+ get method method get L37–37
+ set method method set L37–37
+ delete method async_method delete L51–53
+ get method async_method get L45–47
+ makeAsyncKeychain function function makeAsyncKeychain L41–55
+ makeSyncKeychain function function makeSyncKeychain L18–35
+ set method async_method set L48–50

0 comments

No comments yet. Be the first to start the discussion.

To add a comment, use the Muse CLI: muse hub commit comment sha256:c7e4193ed8fb8402ba382ccddde1f7f55974111a5c17d40dc94d0fd26802a378 --body "your comment"