dromara/Sa-Token · error · SaOAuth2AuthorizationCodeException
30110
30110
Error message
无效 code:
What it means
Thrown by SaOAuth2Template.checkCode when the authorization code cannot be found in the DAO (code 30110, SaOAuth2AuthorizationCodeException). Codes are short-lived, single-use server-issued credentials; a miss means the code was never issued, already consumed, expired, or lost (e.g. different DAO/Redis node).
Source
Thrown at sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/template/SaOAuth2Template.java:396
/**
* 获取 CodeModel,无效的 code 会返回 null
* @param code /
* @return /
*/
public CodeModel getCode(String code) {
return SaOAuth2Manager.getDao().getCode(code);
}
/**
* 校验 Code,成功返回 CodeModel,失败则抛出异常
* @param code /
* @return /
*/
public CodeModel checkCode(String code) {
CodeModel cm = SaOAuth2Manager.getDao().getCode(code);
if(cm == null) {
throw new SaOAuth2AuthorizationCodeException("无效 code: " + code)
.setAuthorizationCode(code)
.setCode(SaOAuth2ErrorCode.CODE_30110);
}
return cm;
}
/**
* 获取 Code,根据索引: clientId、loginId
* @param clientId /
* @param loginId /
* @return /
*/
public String getCodeValue(String clientId, Object loginId) {
return SaOAuth2Manager.getDao().getCodeValue(clientId, loginId);
}
// ----------------- Access-Token 相关 -----------------View on GitHub (pinned to ac2c7f6e94)
Solutions
- Confirm the code is sent exactly as issued and URL-encoded in the token request
- Redo the authorize flow to get a fresh code — codes are single-use and expire quickly (default ~5 min)
- If running multiple OAuth2 server nodes, ensure they share the same Redis DAO so codes are visible cluster-wide
Defensive patterns
Strategy: retry
Validate before calling
if (SaFoxUtil.isEmpty(code)) throw new IllegalArgumentException("code is empty");
if (SaOAuth2Manager.getDao().getCode(code) == null) { /* code dead -> restart flow */ } Try / catch
try { return saOAuth2Template.checkCode(code); } catch (SaOAuth2AuthorizationCodeException e) { redirectUserToAuthorize(); // get fresh code
return null; } Prevention
- Redeem the code exactly once, immediately after receiving it
- Use a shared Redis DAO so codes survive restarts and are visible to all nodes
When it happens
Trigger: Calling the token endpoint (/oauth2/token?grant_type=authorization_code) with a code that was already redeemed, has expired past its configured timeout, was truncated/URL-mangled, or when the server DAO was flushed/restarted with memory storage.
Common situations: Double submission of the token request (browser retry, duplicate HTTP call); front-end losing characters of the code due to missing URL encoding; dev server restart clearing in-memory code cache; multiple instances without shared Redis.
Related errors
AI-assisted analysis of dromara/Sa-Token@ac2c7f6e94 (2026-08-14).
Data as JSON: /api/errors/558905d36b79c625.
Report an issue: GitHub.