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

  1. Return a fresh access token via the refresh_token grant or re-run the authorization flow
  2. Verify the exact token value is transmitted (Authorization header, no truncation, no whitespace)
  3. Use a persistent shared DAO (Redis) across server instances and confirm the access-token timeout configuration
  4. 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

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.