{"record":{"id":"74155b07e2c2fc5b","repo":"alibaba/nacos","slug":"token-issuer-mismatch","errorCode":null,"errorMessage":"Token issuer mismatch","messagePattern":"Token issuer mismatch","errorType":"exception","errorClass":"AccessException","httpStatus":null,"severity":"error","filePath":"plugin-default-impl/nacos-oidc-auth-plugin/src/main/java/com/alibaba/nacos/plugin/auth/impl/oidc/token/JwtTokenValidator.java","lineNumber":253,"sourceCode":"                    }\n                }\n            }\n        }\n        \n        // Validate issuer\n        String issuer = claims.getIssuer();\n        String expectedIssuer = config.getIssuerUri();\n        if (StringUtils.isNotBlank(expectedIssuer) && !expectedIssuer.equals(issuer)) {\n            // Handle trailing slash difference\n            String normalizedExpected = expectedIssuer.endsWith(\"/\")\n                ? expectedIssuer.substring(0, expectedIssuer.length() - 1)\n                : expectedIssuer;\n            String normalizedIssuer = issuer != null && issuer.endsWith(\"/\")\n                ? issuer.substring(0, issuer.length() - 1)\n                : issuer;\n            \n            if (!normalizedExpected.equals(normalizedIssuer)) {\n                throw new AccessException(\"Token issuer mismatch\");\n            }\n        }\n    }\n    \n    /**\n     * Extract username from JWT claims.\n     *\n     * @param claims JWT claims\n     * @return username\n     */\n    public String extractUsername(JWTClaimsSet claims) {\n        String usernameClaim = config.getUsernameClaim();\n        \n        // Try configured claim first\n        Object username = claims.getClaim(usernameClaim);\n        if (username != null) {\n            return username.toString();\n        }","sourceCodeStart":235,"sourceCodeEnd":271,"githubUrl":"https://github.com/alibaba/nacos/blob/9b989acdf181d00898f2e8839257bb2b2a3cefe3/plugin-default-impl/nacos-oidc-auth-plugin/src/main/java/com/alibaba/nacos/plugin/auth/impl/oidc/token/JwtTokenValidator.java#L235-L271","documentation":"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.","triggerScenarios":"issuer-uri is non-blank, claims.getIssuer() differs from it, and normalizing trailing slashes on both does not make them equal.","commonSituations":"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.","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."],"exampleFix":"# before\nnacos.plugin.auth.oidc.issuer-uri=https://idp.example.com/auth/realms/test\n# token iss = https://idp.example.com/auth/realms/prod\n\n# after\nnacos.plugin.auth.oidc.issuer-uri=https://idp.example.com/auth/realms/prod","handlingStrategy":"validation","validationCode":"JWTClaimsSet preview = JWTClaimsSet.parse(new String(Base64.getUrlDecoder().decode(token.split(\"\\\\.\")[1])));\nString expected = config.getIssuerUri();\nString iss = preview.getIssuer();\nString norm(String s){ return s != null && s.endsWith(\"/\") ? s.substring(0, s.length()-1) : s; }\nif (expected != null && !expected.isBlank() && !norm(expected).equals(norm(iss))) {\n    // fix issuer-uri or reject token before validate()\n}","typeGuard":null,"tryCatchPattern":"try {\n    validator.validate(token);\n} catch (AccessException e) {\n    if (\"Token issuer mismatch\".equals(e.getMessage())) {\n        // 403 wrong_issuer; verify issuer-uri matches IdP discovery 'issuer'\n    }\n    throw e;\n}","preventionTips":["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."],"tags":["oidc","jwt","issuer","claims"],"backgroundTag":null,"analyzedSha":"9b989acdf181d00898f2e8839257bb2b2a3cefe3","analyzedAt":"2026-08-14T07:17:31.569Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}