dromara/Sa-Token · error · SaOAuth2AccessTokenScopeException
30108
30108
Error message
该 access_token 不具备 scope:
What it means
Thrown by checkAccessTokenScope when a valid access token does not include one of the scopes being enforced (code 30108, SaOAuth2AccessTokenScopeException). The token exists but was granted a narrower scope set than the API requires, so access is denied at the scope level rather than the token level.
Source
Thrown at sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/template/SaOAuth2Template.java:477
return true;
} catch (SaOAuth2AccessTokenException e) {
return false;
}
}
/**
* 校验:指定 Access-Token 是否具有指定 Scope 列表,如果不具备则抛出异常
* @param accessToken Access-Token
* @param scopes 需要校验的权限列表
*/
public void checkAccessTokenScope(String accessToken, String... scopes) {
AccessTokenModel at = checkAccessToken(accessToken);
if(SaFoxUtil.isEmptyArray(scopes)) {
return;
}
for (String scope : scopes) {
if(! at.scopes.contains(scope)) {
throw new SaOAuth2AccessTokenScopeException("该 access_token 不具备 scope:" + scope)
.setAccessToken(accessToken)
.setScope(scope)
.setCode(SaOAuth2ErrorCode.CODE_30108);
}
}
}
/**
* 获取 Access-Token 所代表的LoginId
* @param accessToken Access-Token
* @return LoginId
*/
public Object getLoginIdByAccessToken(String accessToken) {
return checkAccessToken(accessToken).loginId;
}
/**
* 获取 Access-Token 所代表的 clientIdView on GitHub (pinned to ac2c7f6e94)
Solutions
- Include the required scope in the authorize request: /oauth2/authorize?...&scope=userinfo,order
- Add the missing scope to the client's allow-scope configuration on the OAuth2 server so it can be requested/granted
- Verify scope name spelling and separator (sa-token uses commas) match between the API check and the granted token
Example fix
// before String url = server + "/oauth2/authorize?response_type=code&client_id=1001&redirect_uri=..."; // no scope // after String url = server + "/oauth2/authorize?response_type=code&client_id=1001&redirect_uri=...&scope=userinfo,order";
Defensive patterns
Strategy: try-catch
Validate before calling
AccessTokenModel at = saOAuth2Template.getAccessToken(token); boolean hasScope = at != null && java.util.Arrays.asList(scopes).stream().allMatch(s -> at.scopes.contains(s));
Try / catch
try { saOAuth2Template.checkAccessTokenScope(token, "userinfo"); } catch (SaOAuth2AccessTokenScopeException e) { return status(403, "missing scope: " + e.getScope()); } Prevention
- Request the full scope set the APIs will need at authorize time
- Keep a single constant list of scope names shared by client and server code
When it happens
Trigger: Calling an API protected with SaOAuth2Util.checkAccessToken(token, "userinfo") (or StpUtil with scope checks) when the authorize request that minted the token did not include 'userinfo' in its scope parameter.
Common situations: New API endpoint requires a scope the client never requests; user unchecked a scope on the consent page; client's configured allow-scopes on the server omit the needed scope; scopes string case or separator mismatch (comma vs space).
Related errors
AI-assisted analysis of dromara/Sa-Token@ac2c7f6e94 (2026-08-14).
Data as JSON: /api/errors/6ae553b682fb3289.
Report an issue: GitHub.