ASVS 5.0 V10.2.3 requires the OAuth client to request only the scopes, or other authorization parameters, that it needs. It is a Level 3 requirement. Least privilege applies to what your app asks for as much as to what it grants.
Why it matters
A token is only as dangerous as its scope. If your app asks for repo or full mailbox access when it reads one profile field, any token theft or app compromise has that reach. Over-broad scopes also put off careful customers during consent review.
How to implement it
List every API call the client makes, then map each to the smallest scope that allows it.
// Ask for what the feature needs, nothing more
const BASE_SCOPES = ["openid", "profile"];
const CALENDAR_SCOPES = ["calendar.read"];
function scopesFor(features: Set<string>) {
return features.has("calendar") ? [...BASE_SCOPES, ...CALENDAR_SCOPES] : BASE_SCOPES;
}
Request additional scopes incrementally, at the moment a user first uses a feature, rather than all up front. Review scope lists in code review, and re-check them when features are removed. Where the server supports it, use authorization_details for narrow, specific grants.
How to test it
Capture the authorization request. Diff the scope value against a documented list and fail the build on additions. Then remove each scope in turn in a test tenant and see which calls break. A scope whose removal breaks nothing was never needed.
Common mistakes
- Copying a scope string from a tutorial.
- Requesting write access for a read only feature.
- Asking for
offline_accesswithout a refresh flow that uses it.
Quick check
When should an app ask for an extra scope?
When the user first uses the feature that needs it, not at first sign in.