Because write implies read, there are only two meaningful states, and the token response says which one you got:
Why the examples ask for both, when write already implies read.Requesting
scope=media:write on its own works and grants exactly the same access — you are not required to list both. We show media:read media:write for two practical reasons:- It matches what comes back. The token response always reports
media:read media:writewhen write is granted. Asking for the same string you will be handed makes a request-versus-response comparison trivial, which matters because checking the returned scope is the defence against a silent downgrade. - It is what OAuth expects.
scopeis a space-delimited list of everything you want, so listing both is the conventional form and what a stock library will produce.
Which one do you need?
If your app only displays things, ask formedia:read. If it scrobbles, marks items watched, rates, or changes lists, ask for media:write.
Requesting write when you only read is not harmful, but it makes your consent screen ask for more than you need, and some users decline on that basis. Ask for what you use.
Requesting a scope
Pass it on the authorize URL, space-separated (so%20-encoded in a query string):
Two ways to silently get a read-only token
Both of these produce a working token that cannot write, with no error at any point in the flow. The failure shows up much later, as a403 on your first write — usually in production, usually from a user report.
The separator is more forgiving than the spelling. Because the check is for the presence of
media:write rather than a parse of the list, a separator mistake like media:read,media:write still grants write — the token is in there either way.That asymmetry is worth knowing so you debug in the right place: if writes are failing, suspect the spelling or case of media:write, not your delimiter. Send the space-separated form regardless — it is what the spec calls for and what we will keep supporting.scope field in the token response and compare it to what you asked for.
403 into an obvious configuration bug on your own machine.
How scope is enforced
Enforcement is by request shape rather than by a per-endpoint list:- A
GETwith no request body needsmedia:read. - Everything else needs
media:write— every other method, every request that carries a body, and all of/scrobbleand/checkineven onGET.
403 and an insufficient_scope error, along with a WWW-Authenticate header naming the scope required.
Changing scope later
You cannot widen a grant by refreshing. On the refresh grant:- a narrower scope is ignored and the original is reissued
- a wider scope is rejected with
invalid_scope
See also
OAuth flow
Where the
scope parameter goes.Tokens and refresh
Why refreshing cannot change your scope.
Migrating from V1
Scopes are new in V2 — what that means when you port existing code.
Errors
The full error vocabulary, including
insufficient_scope.