OAuth 2.1 makeover: PKCE-only, hashed tokens, real consent with scoped permissions - #68
Merged
Merged
Conversation
…h scoped permissions Replaces the secret-based OAuth connector flow with a spec-compliant OAuth 2.1 authorization server for MCP clients: - Discovery metadata (RFC 8414/9728) + dynamic client registration (RFC 7591): clients need only the MCP URL, no credentials to copy - Public clients with mandatory PKCE S256; client secrets removed - Auth codes, access tokens, and refresh tokens stored as SHA-256 digests only; 1h access tokens with rotating single-use refresh tokens (was: 90-day static tokens stored verbatim) - Consent page lists each requested privilege as a user-toggleable checkbox with a Deny option; tokens carry exactly what was approved - Strict scopes: no default-to-full-access, no claudeai escalation, static API-key fallback removed - 401s advertise resource metadata via WWW-Authenticate so MCP clients bootstrap the flow automatically - Flutter: Connected Apps screen (grants + revoke) replaces the client-secret / static-token copy screen - Firestore rules lock OAuth collections to Cloud Functions; users can read their own grant records - functions/test-oauth-flow.mjs: 36-check emulator e2e of the full flow (discovery → register → consent → PKCE exchange → scoped MCP calls → refresh rotation → revocation) Breaking: existing static API keys and legacy plaintext tokens no longer authenticate; users reconnect via the OAuth flow. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 tasks
nick-transition
added a commit
that referenced
this pull request
Jul 9, 2026
The deploy workflow only shipped hosting and functions, so rules changes (like the OAuth 2.1 lockdown in #68) never reached prod. firebase deploy --only firestore covers rules + indexes per firebase.json. Co-authored-by: Nick Stoddart <nickstoddart@Nicks-MacBook-Pro.local> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replaces the secret-based OAuth connector flow with a spec-compliant OAuth 2.1 authorization server for MCP clients (Claude.ai / Claude Desktop):
claudeaiscope escalation; every MCP tool enforces its scopeWWW-Authenticateon 401 — users paste only the MCP URLBreaking change
Existing static API keys and legacy plaintext OAuth tokens no longer authenticate. Users reconnect once via the new flow. Deploy needs both
--only functionsand--only firestore:rules.Test plan
functions/test-oauth-flow.mjs: 36-check emulator e2e — discovery, registration, consent page content, PKCE enforcement (missing/wrong verifier), single-use codes, scoped token issuance, hashed-at-rest verification, real MCP client connection with scope enforcement, refresh rotation + replay rejection, grant revocation killing live tokens (all passing)flutter analyzeclean on changed filestscbuild clean🤖 Generated with Claude Code