scope Claim in a JWT Access Token
scope lists the OAuth scopes granted to a token as a single space delimited string. The encoding surprises people, because almost every other list in a JWT payload is a JSON array.
At a glance
- Claim
- scope (Scopes)
- Defined in
- RFC 8693 section 4.2
- Value type
- One JSON string containing space delimited scope values
- Required
- Optional in general. RFC 9068 says a JWT access token should carry it when the request included a scope parameter.
- Sample value
- "read:invoices write:invoices profile"
- In the decoder
- Shown under Custom claims as the single string it is, spaces and all, with no splitting applied.
In detail
The encoding comes straight from OAuth 2.0, where the scope request parameter has always been a space delimited list in a form encoded body. RFC 8693 kept that shape when it registered the claim, so the JWT holds one string. It is the only common claim where a list is not a JSON array, and code that iterates it without splitting on spaces first treats the whole grant as a single strange scope name.
Checking it means splitting on spaces and testing for membership, never substring matching. A naive contains test for read:invoices also matches read:invoices_archive, and a test for admin matches not_admin. Split first, compare whole values, and treat the result as a set: order carries no meaning and providers do not promise to preserve the order the client asked for.
The granted scope is not always the requested scope. An authorization server may return less than was asked for, because the user declined part of the consent or policy trimmed it, and it is allowed to do so silently. Anything that assumes the token carries exactly what the client requested will break the first time a user unticks a box on the consent screen.
The decoder shows scope under Custom claims exactly as encoded, one long string. That is genuinely the fastest way to answer why a request is being refused with insufficient scope, since you can read the granted values without adding logging anywhere. The token is decoded in your browser and nothing is uploaded, so a production access token is safe to look at here.
Examples
{
"iss": "https://auth.example.com",
"client_id": "reporting-job",
"scope": "read:invoices write:invoices profile"
}
// Correct: split, then compare whole values
const granted = new Set(payload.scope.split(" "));
if (!granted.has("write:invoices")) reject();Things that catch people out
- Expecting a JSON array. Some providers add a non standard array claim such as scp alongside it, but the registered scope claim is a space delimited string.
- Substring matching on the raw string. read:invoices matches read:invoices_archive, which grants more than intended.
- Assuming granted equals requested. The authorization server may return a narrower scope, so always read it from the token.
Try it: JWT Decoder
Paste a token to decode the header and payload, read the claims and expiry, and verify the signature in your browser. Nothing is uploaded.
JWT Decoder
LOCAL · Browser-OnlyDecode and inspect JSON Web Tokens without sending them to a server
Related JWT claims and algorithms
All jwt claims and algorithms →client_id Claim in a JWT Access Token
The client_id claim names the OAuth client an access token was issued to. How it differs from sub and azp, where it is required, and decoder behaviour.
aud (Audience) Claim in a JWT
The aud claim names who a token is for. Why every API must check it, how the string and array forms differ, and what the decoder shows.
act (Actor) Claim in a JWT
The act claim names the party acting on behalf of the subject. How nesting records a delegation chain, and why the decoder shows it as raw JSON.
may_act (Authorized Actor) Claim in a JWT
The may_act claim states which party may act on behalf of the subject. How it gates a token exchange, how it pairs with act, and what the decoder shows.
cnf (Confirmation) Claim in a JWT
The cnf claim binds a token to a key its holder must prove. How mTLS and DPoP use it, why it stops replay of a stolen token, and decoder limits.
email Claim in an OpenID Connect ID Token
The email claim carries the end user's email address. Why it must not be used as an account key, what scope returns it, and what the decoder shows.
Tools for this
- JWT Decoder Free online JWT decoder - decode and inspect JSON Web Tokens without sending them to a server