fix(oauth): default absent authorize scope so consent completes (BUG-2088)#921
Merged
Merged
Conversation
…2088) An OAuth authorize request may legally omit `scope` (RFC 6749 §3.1.2; our advertised scopes_supported is only advisory). Claude Code does. When it does, ar.GetRequestedScopes() is empty, renderConsent shows zero capability-tier radios, and clicking Authorize dead-ends the /authorize/decide POST with "capability_tier must be 'read', 'write', or 'admin'". Default an absent scope to the requesting client's registered scopes (DCR seeds pad:read/pad:write), falling back to pad:read pad:write. A missing/unknown client_id is left untouched so fosite emits its normal invalid_client error. The default is set on BOTH r.Form (feeds NewAuthorizeRequest → the consent tier radios) AND r.URL.RawQuery: renderConsent builds the consent form's hidden authorize fields from r.URL.Query(), and /authorize/decide rebuilds the AuthorizeRequest from those hidden fields — so without the URL update the decide POST would reconstruct a scope-less request and reject the chosen tier one step later. Regression test drives the full GET-consent → POST-decide → code flow, extracting the scope from the rendered hidden field so it fails if the field goes missing. Claude-Session: https://claude.ai/code/session_015yuBJQYfDj95cgX3DaD8SF
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.
Problem
A user connecting Claude Code to Pad Cloud gets an authorize URL with no
scopeparameter, and clicking Authorize dead-ends on:{"error":{"code":"invalid_request","message":"capability_tier must be 'read', 'write', or 'admin'"}}scopeis optional per RFC 6749 §3.1.2, and our advertisedscopes_supported(both.well-knowndocs) is only advisory — a client may legally omit it. Claude Code does. Nothing on the server defaults it, so:ar.GetRequestedScopes()is empty →renderConsentcomputescanRead/canWrite/canAdminall false → the "What it can do" fieldset renders zero tier radios./oauth/authorize/decidewithcapability_tierempty →parseConsentPayloadrejects it with the error above.Fix
When the authorize request has no
scope, default it to the requesting client's registered scopes (DCR already seedspad:read pad:write), falling back topad:read pad:write. A missing/unknownclient_idis left untouched so fosite emits its normalinvalid_clienterror.The default is set on both:
r.Form— feedsNewAuthorizeRequest→ the consent tier radios, andr.URL.RawQuery—renderConsentbuilds the consent form's hidden authorize fields fromr.URL.Query(), and/authorize/deciderebuilds theAuthorizeRequestfrom those hidden fields. Without the URL update the decide POST reconstructs a scope-less request and rejects the chosen tier one step later.Testing
TestOAuth_Authorize_DefaultsScopeWhenOmitteddrives the full GET-consent → POST-decide → code flow, extracting the scope from the rendered hidden field (fails if the field goes missing) and asserting an authorization code is issued.OAuth/Consentsuite +go build ./...green.r.URL.RawQueryhalf of the fix.Notes
&scope=pad:read%20pad:writeto the authorize URL before authorizing.Fixes BUG-2088.
https://claude.ai/code/session_015yuBJQYfDj95cgX3DaD8SF