ASVS 5.0 V10.3.2 requires the resource server to enforce authorization decisions based on the claims in the access token that define delegated authorization. When sub, scope and authorization_details are present, they must be part of the decision. It is a Level 2 requirement.
Why it matters
A valid token only proves that someone authenticated and a client was granted something. What the client may do is in the scope. If an API checks the signature and then lets any valid token call any endpoint, a token granted profile.read can delete data.
Delegation has two parts: what the client is allowed (scope) and for whom (sub). Both must be checked.
How to implement it
Map each operation to a required scope and check the user's own permissions as well.
function requireScope(needed: string) {
return (req, res, next) => {
const granted = String(req.auth.scope ?? "").split(" ");
if (!granted.includes(needed)) return res.status(403).set(
"WWW-Authenticate", 'Bearer error="insufficient_scope", scope="' + needed + '"').end();
next();
};
}
app.get("/orders", requireScope("orders.read"), listOrdersFor); // uses req.auth.sub
app.post("/orders", requireScope("orders.write"), createOrder);
Scope is a ceiling on the client, not a grant to the user. The token holder must also own or be permitted to touch the object. A token with orders.read for user 1 must not read user 2's orders.
Where authorization_details is used (for example a payment of a given amount to a given payee), compare each field of the request to the granted details.
How to test it
Get a token with only a read scope and attempt each write endpoint. Expect 403 with insufficient_scope. Then use a token for user 1 against user 2's object IDs. Expect denial.
Common mistakes
- Treating a valid token as full access.
- Checking scope but never tying the data to
sub. - Splitting the scope string loosely so
readmatchesreadwrite.
Quick check
Does scope replace the user's own permission check?
No. Scope limits the client. The user's rights on the specific object still apply.