dromara/Sa-Token · error · SaOAuth2AccessTokenException
30106
30106
Error message
无效 access_token:
What it means
Thrown by SaOAuth2Template.checkAccessToken when the access token lookup in the DAO returns null (code 30106, SaOAuth2AccessTokenException). The token was never issued by this server, has expired, was revoked, or its storage was cleared.
Source
Thrown at sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/template/SaOAuth2Template.java:433
/**
* 获取 AccessTokenModel,无效的 AccessToken 会返回 null
* @param accessToken /
* @return /
*/
public AccessTokenModel getAccessToken(String accessToken) {
return SaOAuth2Manager.getDao().getAccessToken(accessToken);
}
/**
* 校验 Access-Token,成功返回 AccessTokenModel,失败则抛出异常
* @param accessToken /
* @return /
*/
public AccessTokenModel checkAccessToken(String accessToken) {
AccessTokenModel at = SaOAuth2Manager.getDao().getAccessToken(accessToken);
if(at == null) {
throw new SaOAuth2AccessTokenException("无效 access_token: " + accessToken)
.setAccessToken(accessToken)
.setCode(SaOAuth2ErrorCode.CODE_30106);
}
return at;
}
/**
* 获取 Access-Token 列表:此应用下 对 某个用户 签发的所有 Access-token
*
* @param clientId /
* @param loginId /
* @return /
*/
public List<String> getAccessTokenValueList(String clientId, Object loginId) {
return SaOAuth2Manager.getDao().getAccessTokenValueList_FromAdjustAfter(clientId, loginId);
}
/**View on GitHub (pinned to ac2c7f6e94)
Solutions
- Return a fresh access token via the refresh_token grant or re-run the authorization flow
- Verify the exact token value is transmitted (Authorization header, no truncation, no whitespace)
- Use a persistent shared DAO (Redis) across server instances and confirm the access-token timeout configuration
- If revoked unintentionally, check revokeToken/revoke by clientId+loginId calls in your code
Defensive patterns
Strategy: fallback
Validate before calling
AccessTokenModel at = SaOAuth2Manager.getDao().getAccessToken(token);
if (at == null) { token = refreshOrReauthorize(); } Try / catch
try { saOAuth2Template.checkAccessToken(token); } catch (SaOAuth2AccessTokenException e) { token = client.refreshAccessToken(); retry(request); } Prevention
- Track token expiry client-side and refresh proactively before it lapses
- Persist tokens via a shared DAO (Redis) in clustered deployments
When it happens
Trigger: Calling checkAccessToken (directly or via an API-gateway/filter that validates access tokens) with a fabricated, expired, revoked, or truncated token string.
Common situations: Token expired between calls (short timeout config); server restart with default in-memory DAO wiping all tokens; Redis flush/eviction; client sends the refresh token or client token where the access token belongs; token copied with whitespace/newline from logs.
Related errors
AI-assisted analysis of dromara/Sa-Token@ac2c7f6e94 (2026-08-14).
Data as JSON: /api/errors/214a898b5c086bda.
Report an issue: GitHub.