Key points
- Scopes are coarse-grained capabilities; the resource server is the authority on what each scope means.
- Display scopes on the consent screen so users see what they're approving (the Google / GitHub consent UX).
- Request the minimum scopes your app needs — every excess scope is excess blast radius if a token leaks.
- OIDC reserves: openid (required), profile, email, address, phone, offline_access.
- Scopes ≠ permissions — fine-grained authorization (which row, which tenant) belongs in claims or a policy engine, not scopes.
What are OAuth scopes?
Scopes are the strings an OAuth 2.0 client asks for at authorization time to declare what it intends to do with the resulting access token. read:repo, write:user, mail.send, https://www.googleapis.com/auth/drive.readonly — these are all scopes.
The authorization server displays them on the consent screen ("This app wants to read your repos and send email as you"). If the user approves, the access token is minted with those scopes embedded, and the resource server enforces them on every API call.
How they're used
- Client requests an authorization URL with
scope=openid profile email https://api.acme.com/invoices.read. - User consents (or admin pre-consents for workforce apps).
- Token endpoint returns an access token whose
scopeclaim contains the granted scopes (possibly a subset of what was requested). - Resource server checks: does this token have the scope required for this endpoint?
Scopes vs permissions vs roles
A common mistake is to treat scopes as a fine-grained permission system. They aren't.
| | Scopes | App-level permissions | | --- | --- | --- | | Granularity | Coarse (read vs write, by resource type) | Fine (which document, which row, which tenant) | | Authority | Authorization server + resource server | Application + policy engine | | Audience | The user (consent screen) and the API | Internal RBAC/ABAC |
For real authorization, combine scopes (what kind of action) with claims (sub, tenant, roles) and a policy engine (RBAC/ABAC/ReBAC).
Best practices
- Least privilege — request the smallest set of scopes. Don't ask for
adminifread:profileworks. - Incremental authorization — ask for advanced scopes only when the user reaches the feature that needs them.
- Document scopes clearly in your developer portal — what each one grants, examples, recovery if revoked.
- Map scopes to API endpoints with middleware, not ad-hoc
ifstatements.
Editorial note
If your API has 50 scopes, you're probably trying to encode app-level permissions in OAuth — move that into your authorization layer (Cedar, OPA, Oso) and keep scopes coarse.
