When a client redeems a refresh token at the token endpoint, what may its scope parameter ask for?
answer
- one direction only
- the grant is a ceiling
- omitted means the original grant
- narrow freely, widen never
- measured against what was originally granted
basics
~20 sOnly scopes inside the grant the resource owner originally gave. RFC 6749 says the requested scope on a refresh MUST NOT include any scope not originally granted, and that omitting it is treated as asking for the original grant. A client may narrow, never widen.
solid answer
~50 sThe refresh request is a form POST to the token endpoint with `grant_type=refresh_token`, the `refresh_token` itself, and an optional `scope`. RFC 6749 section 6 fixes what that `scope` may hold: it **MUST NOT include any scope not originally granted by the resource owner**, and if it is omitted the server treats the request as asking for exactly the original grant. So the parameter is a way to ask for **less**, never more - an attempt to widen is rejected rather than quietly trimmed, and widening is something only the resource owner can do, by consenting again. The reference point is always the original grant, not the scope of the token you are replacing, so narrowing on one refresh does not permanently shrink what later refreshes may ask for. A confidential client also authenticates itself on this request, and the authorization server checks that the refresh token was issued to that same client.
code
http · 5 linesPOST /token HTTP/1.1
Host: as.marina.example
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA&scope=tides.readgo deeper
Recall the direction: a refresh can ask for the same permissions or fewer, never more. Widening needs the resource owner, not the token endpoint.
State both halves of the rule - must not exceed the original grant, and omission equals the original grant - and know that over-asking is refused rather than trimmed.
Show you use narrowing deliberately: a component doing exposed work gets an access token cut down to it, without forfeiting the rest of the grant for later refreshes.
Treat the grant as the consent boundary across the estate. If clients can widen anywhere on the refresh path, the consent record stops being a boundary and becomes a starting point.
## The request Redeeming a refresh token is a back-channel form POST to the **token endpoint** carrying three things: - `grant_type=refresh_token` - which grant is being exercised; - `refresh_token` - the credential itself; - `scope` - optional, and the subject of this question. The authorization server validates the refresh token, and - this is easy to skip - **checks that the refresh token was issued to the client making the request**. A confidential client authenticates itself on the same request, so that binding is checkable rather than assumed. ## The rule on scope RFC 6749 section 6 states it in two halves, and both are load-bearing: 1. the requested scope **MUST NOT include any scope not originally granted by the resource owner**; 2. if the `scope` parameter is **omitted**, the request is treated as asking for a scope **equal to the one originally granted**. Read together: a refresh can only move in one direction. Down is allowed, up is not, and saying nothing means "the same as before". This is not an arbitrary restriction. The refresh token is a durable stand-in for a consent decision a human made once. If a client could enlarge its permissions by asking for more on refresh, that consent would be a starting point rather than a boundary, and the resource owner would have authorized something they never saw. Widening requires going back to the resource owner; the refresh path deliberately has no room for it. RFC 9700 section 4.14.2 reinforces the same boundary from the issuer's side: refresh tokens must be bound to the scope and resource servers the resource owner consented to. ## What happens when a client over-asks The request is refused rather than silently trimmed to what is permitted. RFC 6749 defines `invalid_scope` for a requested scope that exceeds what the resource owner granted, and the error response is an HTTP 400 carrying that code. Two practical consequences: - a client cannot probe for extra permissions by asking and seeing what comes back; - a client that copies a hard-coded scope list into its refresh path, without checking it against what was actually granted, breaks the refresh entirely rather than degrading - and it breaks at renewal time, long after the integration looked healthy. ## Why you would deliberately ask for less Narrowing is not a curiosity; it is the one active use of the parameter. - **Least privilege per task.** A background job in the marina application that only republishes tide times can refresh down to a read scope, so the token it carries around cannot alter a berth booking even if it is mishandled. - **Separating risky work.** A client that holds a broad grant can mint a narrow access token for the component doing the exposed work, keeping the broad one out of that component's hands. - **Shrinking what a leak is worth.** The narrower the access token, the less a stolen copy buys inside its lifetime. The reference point is what makes this safe to do casually: because the specification measures every request against the scope **originally granted**, asking for less today does not forfeit the rest. A later refresh may ask for the original grant again. ## The shape of the exchange A client refreshing down to a single read scope sends only what it needs and receives an access token issued for exactly that. The response is an ordinary token response, so it carries `access_token`, `token_type`, its own `expires_in`, and - because the server is free to issue one - possibly a new `refresh_token`. The `scope` member appears in the response when what was issued differs from what the client asked for. ## What this question is not about The scope value's own syntax, how scopes are designed for an API, and asking a resource owner to consent to more are separate subjects with their own owners. What belongs here is narrower and more checkable: on the refresh path, the grant is a ceiling, silence means the whole grant, and the ceiling is the original grant rather than the token you are replacing.
- If a client narrows scope on one refresh, has it given up the rest of the grant?No. RFC 6749 measures the requested scope against the scope **originally granted by the resource owner**, not against the token being replaced, so a later refresh may ask for the full original grant again. Narrowing shapes the access token that is issued now; it does not rewrite the consent behind the refresh token.
- What does the authorization server do with a refresh request that asks for a wider scope?It refuses it rather than trimming it. RFC 6749 defines `invalid_scope` for a requested scope that exceeds what the resource owner granted, returned in a 400 error response. Silent trimming would let a client discover the boundary by probing, and would hide a client-side bug until something else broke.
- Besides the refresh token itself, what does the authorization server check on this request?That the refresh token is valid and that it was issued to the client now presenting it. A confidential client authenticates on the same request, so the binding can be verified rather than trusted; without that check a stolen refresh token would be redeemable by anyone who could reach the token endpoint.
saying these in an interview costs you the question
- Thinks a refresh request can ask for scopes beyond the grant
- Believes an omitted scope means an empty or minimal scope
- Says the server silently trims an over-wide request instead of refusing
- Measures the request against the last token rather than the original grant
- Assumes narrowing once permanently reduces the grant
- Forgets the server checks the refresh token belongs to this client