alibaba/nacos · warning · AccessException
Token has expired
Error message
Token has expired
What it means
Thrown by validateClaims when the JWT 'exp' claim is absent or is in the past. The validator treats a missing expiration as expired (fails closed) and compares the present time against exp with no built-in clock-skew grace.
Source
Thrown at plugin-default-impl/nacos-oidc-auth-plugin/src/main/java/com/alibaba/nacos/plugin/auth/impl/oidc/token/JwtTokenValidator.java:206
return claims;
} catch (Exception e) {
LOGGER.warn("Token validation failed even after JWKS refresh: {}", e.getMessage());
throw new AccessException("Token signature verification failed");
}
}
/**
* Perform additional claims validation.
*
* @param claims JWT claims
* @throws AccessException if validation fails
*/
private void validateClaims(JWTClaimsSet claims) throws AccessException {
// Validate expiration
Date expirationTime = claims.getExpirationTime();
if (expirationTime == null || expirationTime.before(new Date())) {
throw new AccessException("Token has expired");
}
// Validate not before (if present)
Date notBeforeTime = claims.getNotBeforeTime();
if (notBeforeTime != null && notBeforeTime.after(new Date())) {
throw new AccessException("Token is not yet valid");
}
// Validate audience (if client ID is configured)
String clientId = config.getClientId();
if (StringUtils.isNotBlank(clientId)) {
List<String> audience = claims.getAudience();
if (audience != null && !audience.isEmpty() && !audience.contains(clientId)) {
// Check if 'azp' (authorized party) matches
String azp = (String) claims.getClaim("azp");
if (!clientId.equals(azp)) {
String message = String.format(
"Token audience mismatch. Expected: %s, Got: %s, azp: %s",View on GitHub (pinned to 9b989acdf1)
Solutions
- Have the client refresh/renew the access token and resend.
- Synchronize clocks (NTP) on the Nacos server and the IdP to eliminate skew.
- If the IdP allows, increase the token TTL or implement a refresh-token flow client-side.
- Ensure the IdP includes an 'exp' claim in issued tokens.
- Confirm the server system time and timezone are correct.
Example fix
// before: token reused after expiry, no refresh
validator.validate(staleToken); // exp in the past
// after: refresh before reuse
if (tokenExpiredLocally(staleToken)) {
staleToken = oidcClient.refresh(refreshToken);
}
validator.validate(staleToken); Defensive patterns
Strategy: validation
Validate before calling
import java.util.Base64; import java.util.Date; import com.nimbusds.jwt.JWTClaimsSet;
JWTClaimsSet preview = JWTClaimsSet.parse(new String(Base64.getUrlDecoder().decode(token.split("\\.")[1])));
Date exp = preview.getExpirationTime();
if (exp == null || exp.before(new Date())) {
// refresh token, do not call validate()
} Try / catch
try {
validator.validate(token);
} catch (AccessException e) {
if ("Token has expired".equals(e.getMessage())) {
// 401 token_expired; client must refresh
}
throw e;
} Prevention
- Implement a refresh-token flow client-side so tokens are renewed before exp.
- Synchronize clocks (NTP) on Nacos and the IdP.
- Ensure the IdP always includes an exp claim.
When it happens
Trigger: claims.getExpirationTime() returns null (no exp claim), or exp.before(new Date()) is true at validation time.
Common situations: Token genuinely expired (TTL elapsed); clock skew between the Nacos server and the IdP causes premature expiry; the IdP issues long-lived tokens but the client cached one past its exp; missing exp claim in a non-conformant token.
Related errors
- Token is not yet valid
- Token audience validation failed
- Token issuer mismatch
- Token is empty
- Invalid token format
AI-assisted analysis of alibaba/nacos@9b989acdf1 (2026-08-14).
Data as JSON: /api/errors/e87bdc0adcadd4ae.
Report an issue: GitHub.