In OAuth 2.0, what does the `scope` parameter request, and how is its value formatted on the wire?
answer
- the slice, not the whole account
- a list, not one string
- space-delimited, order does not matter
- case-sensitive, defined by the server
- omitted means default or invalid scope
basics
~20 sThe scope parameter names the access a client is asking for, as a space-delimited list of case-sensitive strings the authorization server itself defines. Order carries no meaning; each string adds one more access range to the request.
solid answer
~40 sRFC 6749 §3.3 defines `scope` as a list of space-delimited, case-sensitive strings, and the authorization server defines what each string means — there is no global vocabulary, so `hives:read` means whatever that one server documents. Order carries nothing: each string simply adds an access range, so `hives:read hive-notes:read` and the reverse ask for the same thing. Because the value rides in a query string or a form-encoded body, the separating space is encoded as `%20` or `+`; a comma-separated value is not a list at all, it is one malformed string. Case matters, so `Hives:Read` is not `hives:read`. If the client omits `scope` entirely, the server must either process the request with a documented default or fail it indicating an invalid scope — it may not improvise a third behaviour.
code
http · 2 linesGET /authorize?response_type=code&client_id=hive-vet-portal&redirect_uri=https%3A%2F%2Fvet.example%2Fcallback&scope=hives%3Aread%20hive-notes%3Aread&state=4Ad9Kk2q HTTP/1.1
Host: as.beekeepers.examplego deeper
Recall that scope is one request parameter carrying several space-delimited strings, that the authorization server decides what each string means, and that the order between them carries no information.
Explain the exact formatting rules: case sensitivity, the single space encoded as %20 or + in a query or form body, and the two options a server has when the parameter is omitted.
Show that you read a scope value as a contract with one specific authorization server. Strings are not portable, and a client hardcoding another server's names ships an integration that cannot work.
Weigh who owns the scope vocabulary across an estate. One shared namespace keeps consent readable and integrations cheap; per-service invention makes every client integration bespoke and every review longer.
## The question a scope answers OAuth 2.0 exists so a **resource owner** can let an application act on one slice of their account at another service without handing over a password. The `scope` parameter is how that slice is named. When a beekeepers' association runs an authorization server in front of its hive register, a visiting vet's application does not ask for *the account*; it asks for `hives:read hive-notes:read`, and the beekeeper sees those two asks before anything is issued. The boundary is therefore settled **before a token exists**. A scope value on an authorization request is a request for a permission boundary; what the resource owner approves is what fixes it. ## The format, exactly RFC 6749 §3.3 gives the grammar as `scope = scope-token *( SP scope-token )`: - **One parameter, many strings.** `scope` appears once, and the strings inside it are separated by a single space. - **Order is meaningless.** Each string *adds* an access range, so `hives:read hive-notes:read` and `hive-notes:read hives:read` request exactly the same access. - **Strings are case-sensitive.** `hives:read` and `Hives:Read` are two different strings, and only the one the server defines means anything. - **A scope token is printable ASCII** with the space, the double quote and the backslash excluded, which is why `hive-notes:read` is a legal shape and a quoted phrase is not. - **The space is encoded like any other character.** The value travels in a query string or a form-encoded body, so on the wire the separator appears as `%20` or `+`. - **Duplicates add nothing.** Repeating a string requests the same range twice. | value sent | what the server actually sees | |---|---| | `scope=hives%3Aread%20hive-notes%3Aread` | two strings: `hives:read` and `hive-notes:read` | | `scope=hives:read,hive-notes:read` | **one** string containing a comma — almost certainly unknown | | `scope=Hives:Read` | one string that is not `hives:read` | | `scope=hives:read%20hives:read` | one string, asked for twice, no extra access | ## The server owns the vocabulary There is no registry that says what `hives:read` means. The authorization server defines its own strings and documents them, and the path in any example request is that server's own — nothing in the specification fixes it. Two consequences show up in real integrations: 1. **Scope names are not portable.** Pointing a client at a different authorization server is a re-mapping exercise, not a copy. 2. **A misspelled scope is an unknown scope, not a smaller one.** The server cannot guess the intent, and the specification's answer to a scope that is invalid, unknown or malformed is the error code `invalid_scope`. ## When the client sends no scope at all `scope` is optional on the request, and the specification does not let the server improvise: it must **either** process the request using a documented default value **or** fail the request indicating an invalid scope. Both are legitimate. What matters to a client is that the default is one server's policy — a client that never sends `scope` and relies on getting the usual thing is coupled to a decision it cannot see change. ## Three things `scope` is not - **Not a guarantee.** Requesting is not receiving; the server may grant less, and the token response is what says so. - **Not an identity statement.** A scope says what the client may do, not who the person at the browser is. - **Not the point of enforcement.** The scope attached to a grant is a decision recorded at issuance; whether one particular API call succeeds is settled later, when the call is made. ## What a good answer sounds like State the shape first — one parameter, space-delimited, case-sensitive strings the server defines, order irrelevant, each adding an access range — then the two rules that catch people out: the omitted-scope rule, and the fact that the granted scope may be narrower than the requested one. An answer that stops at 'scope is what the app is allowed to do' has not been near a real integration.
- What happens if a client sends `scope=hives:read,hive-notes:read`?The comma is an ordinary character inside a scope token, not a separator, so the server sees one string, `hives:read,hive-notes:read`. Unless it happens to define exactly that string, this is a request for an unknown scope and is answered with `invalid_scope` rather than with the two access ranges the client meant.
- Does sending the same scope string twice change anything?No. Each string adds an access range, and adding the same range twice adds nothing. Order is equally meaningless, so `a b`, `b a` and `a b a` request the same access. A server may report the granted set in its own normalised form, which is one more reason to read the `scope` member of the response rather than compare against what you sent.
- Does the scope value travel through the browser or server to server?Both, on different legs. An authorization request carries `scope` front-channel, through the user agent, where the resource owner can see the ask. A client posting directly to the token endpoint sends `scope` back-channel instead. The front-channel copy is visible and tamperable, which is one reason the granted scope is decided by the server and reported back rather than taken on trust.
A scope string is like a line printed on a visitor's pass naming one room it opens. The building decides the wording, not the visitor, and a second line adds a second room rather than upgrading the pass.
saying these in an interview costs you the question
- Says scope strings are comma-separated on the request
- Treats scope names as a standard vocabulary every server shares
- Thinks scope string matching is case-insensitive
- Assumes requesting a scope means receiving that scope
- Calls scope the thing that authenticates the user