alibaba/spring-ai-alibaba · error · BizException
InvalidRefreshToken
InvalidRefreshToken
Error message
Refresh token is invalid.
What it means
Thrown by AccountServiceImpl.refreshToken when tokenManager.getAccountIdFromRefreshToken(...) returns null, i.e. the presented refresh token does not resolve to an account id. This happens when the token is expired, already used/rotated (it is deleted on each refresh), signed with a different secret, or simply malformed.
Source
Thrown at spring-ai-alibaba-admin/spring-ai-alibaba-admin-server-core/src/main/java/com/alibaba/cloud/ai/studio/core/base/service/impl/AccountServiceImpl.java:133
accountEntity.setDefaultWorkspaceId(workspace.getWorkspaceId());
String key = getAccountCacheKey(accountEntity.getAccountId());
redisManager.put(key, accountEntity);
String accountId = accountEntity.getAccountId();
return createTokenResponse(accountId);
}
/**
* Refreshes access token using refresh token
* @param refreshTokenRequest Refresh token request
* @return New token response
*/
@Override
public TokenResponse refreshToken(RefreshTokenRequest refreshTokenRequest) {
String accountId = tokenManager.getAccountIdFromRefreshToken(refreshTokenRequest.getRefreshToken());
if (accountId == null) {
throw new BizException(ErrorCode.INVALID_REFRESH_TOKEN.toError());
}
TokenResponse response = createTokenResponse(accountId);
tokenManager.deleteRefreshToken(refreshTokenRequest.getRefreshToken());
return response;
}
@Override
public TokenResponse login(Oauth2User oauth2User) {
if (oauth2User == null || StringUtils.isBlank(oauth2User.getUserId())) {
throw new BizException(ErrorCode.OAUTH2_USER_NOT_FOUND.toError());
}
String accountId;
AccountEntity accountEntity = getAccountByName(oauth2User.getUserId());
if (accountEntity == null) {
Account account = new Account();
account.setUsername(oauth2User.getUserId());View on GitHub (pinned to f82da0b50f)
Solutions
- Have the user re-authenticate (call login again) to obtain a fresh access/refresh token pair.
- Ensure the client refreshes exactly once per refresh token: persist the new pair atomically and never reuse the old token.
- Verify all app instances share the same JwtConfigProperties secret/key configuration.
- If refreshes fail consistently due to short lifetime, increase the refresh-token TTL in JwtConfigProperties.
Example fix
// before: blindly reusing a possibly consumed token
POST /token/refresh {"refreshToken": oldRefreshToken}
// after: rotate to the newly returned pair and fall back to login on failure
try {
const r = await api.refresh(refreshToken);
saveTokens(r.accessToken, r.refreshToken);
} catch (e) {
await api.login(username, password);
} Defensive patterns
Strategy: fallback
Validate before calling
// before calling the API, reject obviously unusable tokens
if (refreshToken == null || refreshToken.isBlank()) { /* go straight to login */ } Try / catch
try {
TokenResponse resp = accountService.refreshToken(req);
saveTokens(resp);
} catch (BizException e) {
if ("InvalidRefreshToken".equals(e.getCode())) {
forceReLogin(); // refresh token is single-use/expired; only login recovers
} else { throw e; }
} Prevention
- Treat refresh tokens as single-use: persist the new pair immediately and never retry with the old one.
- Keep JwtConfigProperties secret identical across all instances/environments sharing tokens.
- Handle refresh proactively before access-token expiry to avoid downtime-induced expiry.
- On failure, always fall back to full login rather than looping refresh retries.
When it happens
Trigger: POSTing to the token-refresh endpoint with a refresh token that has expired, was already redeemed by a previous refreshToken call (single-use: it is deleted via tokenManager.deleteRefreshToken after issue), a token issued under a different jwt secret, or a truncated/corrupted token string.
Common situations: Client retrying a refresh after a network timeout so the token was already consumed; clock skew or long app downtime letting the refresh token expire; changing JwtConfigProperties.secret between environments (dev token used in prod); load-balanced instances with mismatched JWT secrets.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09).
Data as JSON: /api/errors/1280d7388e80b255.
Report an issue: GitHub.