alibaba/nacos · error · AccessException
Token issuer mismatch
Error message
Token issuer mismatch
What it means
Thrown by validateClaims when the token's 'iss' claim does not equal the configured issuer-uri, even after normalizing a single trailing slash on both sides. This catches tokens issued by a different/stale authority.
Source
Thrown at plugin-default-impl/nacos-oidc-auth-plugin/src/main/java/com/alibaba/nacos/plugin/auth/impl/oidc/token/JwtTokenValidator.java:253
}
}
}
}
// Validate issuer
String issuer = claims.getIssuer();
String expectedIssuer = config.getIssuerUri();
if (StringUtils.isNotBlank(expectedIssuer) && !expectedIssuer.equals(issuer)) {
// Handle trailing slash difference
String normalizedExpected = expectedIssuer.endsWith("/")
? expectedIssuer.substring(0, expectedIssuer.length() - 1)
: expectedIssuer;
String normalizedIssuer = issuer != null && issuer.endsWith("/")
? issuer.substring(0, issuer.length() - 1)
: issuer;
if (!normalizedExpected.equals(normalizedIssuer)) {
throw new AccessException("Token issuer mismatch");
}
}
}
/**
* Extract username from JWT claims.
*
* @param claims JWT claims
* @return username
*/
public String extractUsername(JWTClaimsSet claims) {
String usernameClaim = config.getUsernameClaim();
// Try configured claim first
Object username = claims.getClaim(usernameClaim);
if (username != null) {
return username.toString();
}View on GitHub (pinned to 9b989acdf1)
Solutions
- Set issuer-uri to exactly the IdP's canonical issuer (from /.well-known/openid-configuration 'issuer').
- Decode the token's 'iss' claim and compare verbatim with the configured issuer-uri.
- Ensure scheme (http/https) and host match exactly; only a single trailing slash is tolerated.
- If running multiple environments, use the correct issuer-uri per environment.
- Re-issue the token from the IdP whose issuer matches the config.
Example fix
# before nacos.plugin.auth.oidc.issuer-uri=https://idp.example.com/auth/realms/test # token iss = https://idp.example.com/auth/realms/prod # after nacos.plugin.auth.oidc.issuer-uri=https://idp.example.com/auth/realms/prod
Defensive patterns
Strategy: validation
Validate before calling
JWTClaimsSet preview = JWTClaimsSet.parse(new String(Base64.getUrlDecoder().decode(token.split("\\.")[1])));
String expected = config.getIssuerUri();
String iss = preview.getIssuer();
String norm(String s){ return s != null && s.endsWith("/") ? s.substring(0, s.length()-1) : s; }
if (expected != null && !expected.isBlank() && !norm(expected).equals(norm(iss))) {
// fix issuer-uri or reject token before validate()
} Try / catch
try {
validator.validate(token);
} catch (AccessException e) {
if ("Token issuer mismatch".equals(e.getMessage())) {
// 403 wrong_issuer; verify issuer-uri matches IdP discovery 'issuer'
}
throw e;
} Prevention
- Copy issuer-uri verbatim from the IdP's /.well-known/openid-configuration.
- Use per-environment issuer-uri to avoid cross-environment token reuse.
- Match scheme and host exactly; rely on the single-trailing-slash tolerance only as a fallback.
When it happens
Trigger: issuer-uri is non-blank, claims.getIssuer() differs from it, and normalizing trailing slashes on both does not make them equal.
Common situations: issuer-uri typo or wrong environment (e.g. test IdP token against prod issuer-uri); IdP changed its canonical issuer string; trailing-slash beyond the single-slash normalization; http vs https in the issuer.
Related errors
- Token has expired
- Token is not yet valid
- Token audience validation failed
- Token is empty
- Invalid token format
AI-assisted analysis of alibaba/nacos@9b989acdf1 (2026-08-14).
Data as JSON: /api/errors/74155b07e2c2fc5b.
Report an issue: GitHub.