Skip to content

feat(oauth): Let users narrow granted scopes on consent - #128404

Open
sentry-junior[bot] wants to merge 1 commit into
masterfrom
feat/oauth-consent-scope-selection
Open

sentry-junior[bot] wants to merge 1 commit into
masterfrom
feat/oauth-consent-scope-selection

Conversation

@sentry-junior

@sentry-junior sentry-junior Bot commented Oct 21, 2026

Copy link
Copy Markdown
Contributor

Backend half of letting users pick which requested permissions an OAuth app actually gets on the consent screen. This is progressive enhancement: the consent page can start sending a selection whenever it's ready, and nothing changes for callers that don't.

API change

POST /api/0/oauth/authorize/ and POST /api/0/oauth/device/ now accept an optional scopes: string[] on the decision body (shared through ConsentDecisionSerializer).

  • Omitted or null: every requested scope is granted. This is the current behavior, so existing clients are unaffected.
  • Present: only that subset is granted. The narrowed list flows into ApiAuthorization, ApiGrant.scope_list, the implicit ApiToken, and ApiDeviceCode.scope_list. Device token exchange already issues tokens from that last field.
  • Unknown scope strings fail serializer validation with a 400 and leave the prepared transaction or device consent in place.
  • Scopes the app didn't request are rejected. In the authorize flow this redirects to the callback with invalid_scope, the same way org-selection failures already redirect. In the device flow it returns a 400 on scopes and the request stays pending, so the user can correct it.

The token endpoint already returns the real granted scope, as RFC 6749 §5.1 requires. Clients that let users narrow should read that value instead of assuming they got the full set.

Behavior notes

  • A selection can only remove scopes. Moving a resource from write down to read only works when the client requested both, which is what the MCP server does. Allowing a downgrade to a scope the app didn't ask for (for example, granting project:read when only project:write was requested) is left for a follow-up.
  • If a user narrows their grant, hasExistingConsent is false the next time the app requests the full set, so they see the consent screen again. That seems right, and there's a test for it.
  • Required vs optional scopes, and the consent-page UI, are separate follow-ups. Frontend changes go in their own PR.
  • The legacy Django template views are unchanged and keep granting everything.

via evan.purkhiser.

--

View Junior Session [Sentry]

Authorize and device consent decisions accept an optional scopes list. When present, only that subset of the requested scopes is persisted to the authorization, grant, implicit token, or device code. Omitting it keeps the existing grant-everything behavior, so current clients are unaffected.

Selections outside the requested scopes are rejected: authorize redirects with invalid_scope, device returns a 400 and keeps the request pending.

Co-Authored-By: Evan Purkhiser <evan.purkhiser@sentry.io>
@sentry-junior
sentry-junior Bot requested a review from a team as a code owner October 21, 2026 18:34
@github-actions github-actions Bot added the Scope: Backend Automatically applied to PRs that change backend components label Oct 21, 2026
@getsantry

getsantry Bot commented Nov 12, 2026

Copy link
Copy Markdown
Contributor

This issue has gone three weeks without activity. In another week, I will close it.

But! If you comment or otherwise update it, I will reset the clock, and if you remove the label Waiting for: Community, I will leave it alone ... forever!


"A weed is but an unloved flower." ― Ella Wheeler Wilcox 🥀

@getsantry getsantry Bot added the Stale label Nov 12, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: Backend Automatically applied to PRs that change backend components Stale

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants