{"record":{"id":"f9930dae3e79325e","repo":"theonedev/onedev","slug":"inconsistent-issuer-in-provider-metadata-and-id-to","errorCode":null,"errorMessage":"Inconsistent issuer in provider metadata and ID token","messagePattern":"Inconsistent issuer in provider metadata and ID token","errorType":"exception","errorClass":"AuthenticationException","httpStatus":null,"severity":"error","filePath":"server-plugin/server-plugin-sso-openid/src/main/java/io/onedev/server/plugin/sso/openid/OpenIdConnector.java","lineNumber":220,"sourceCode":"\t\t\treturn (Boolean)jsonValue;\n\t\t} else if (jsonValue instanceof JSONArray) {\n\t\t\tJSONArray jsonArray = (JSONArray) jsonValue;\n\t\t\tif (!jsonArray.isEmpty())\n\t\t\t\treturn (Boolean) jsonArray.iterator().next();\n\t\t\telse\n\t\t\t\treturn null;\n\t\t} else {\n\t\t\treturn null;\n\t\t}\n\t}\n\t\n\tprotected SsoAuthenticated processTokenResponse(OIDCTokenResponse tokenResponse) {\n\t\ttry {\n\t\t\tJWT idToken = tokenResponse.getOIDCTokens().getIDToken();\n\t\t\tJWTClaimsSet claims = idToken.getJWTClaimsSet();\n\t\t\t\n\t\t\tif (!claims.getIssuer().equals(getCachedProviderMetadata().getIssuer()))\n\t\t\t\tthrow new AuthenticationException(_T(\"Inconsistent issuer in provider metadata and ID token\"));\n\t\t\t\n\t\t\tDateTime now = new DateTime();\n\t\t\t\n\t\t\tif (claims.getIssueTime() != null && claims.getIssueTime().after(now.plusSeconds(10).toDate()))\n\t\t\t\tthrow new AuthenticationException(_T(\"Invalid issue date of ID token\"));\n\t\t\t\n\t\t\tif (claims.getExpirationTime() != null && now.toDate().after(claims.getExpirationTime()))\n\t\t\t\tthrow new AuthenticationException(_T(\"ID token was expired\"));\n\n\t\t\tSession.get().setAttribute(SESSION_ATTR_ID_TOKEN, idToken.serialize());\n\n\t\t\tString subject = claims.getSubject();\n\t\t\tString email = StringUtils.trimToNull(claims.getStringClaim(\"email\"));\n\n\t\t\tBoolean emailVerified = claims.getBooleanClaim(\"email_verified\");\n\t\t\tif (emailVerified == null)\n\t\t\t\temailVerified = claims.getBooleanClaim(\"emailVerified\");\n\t\t\tif (emailVerified != null && !emailVerified)","sourceCodeStart":202,"sourceCodeEnd":238,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-plugin/server-plugin-sso-openid/src/main/java/io/onedev/server/plugin/sso/openid/OpenIdConnector.java#L202-L238","documentation":"Thrown by OpenIdConnector.processTokenResponse when the 'iss' (issuer) claim of the received ID token does not equal the issuer advertised in the provider's discovery metadata (getCachedProviderMetadata().getIssuer()). This per OIDC spec validation prevents token substitution or misconfigured provider endpoints from yielding tokens minted by a different issuer.","triggerScenarios":"After exchanging the authorization code, the ID token's iss claim differs from the well-known configuration issuer — e.g. connector points at a discovery URL whose metadata issuer uses a different scheme/host/path than the token endpoint actually issuing tokens.","commonSituations":"Provider behind a proxy reached via different hostnames (internal vs external URL); http vs https mismatch in the well-known URL; issuer with/without trailing path (realm name) misconfigured; switching from HTTP to HTTPS on the identity provider without updating connector settings; older provider versions omitting the issuer check nuances.","solutions":["Make the connector's provider metadata (well-known/discovery) URL exactly match the issuer URL in the token (scheme, host, port, path).","Fix reverse-proxy configuration so the provider emits its public (external) URL as issuer and OneDev uses that same URL.","Avoid mixing http/https or localhost vs FQDN between discovery URL and the provider's real issuer.","Update the provider (e.g. Keycloak realm URL) config in the OneDev SSO connector after any provider URL change."],"exampleFix":"// before: discovery via internal host\nwellKnownConfiguration: \"http://keycloak.internal:8080/realms/myrealm/.well-known/openid-configuration\"\n// after: use the same public issuer the token carries\nwellKnownConfiguration: \"https://sso.example.com/realms/myrealm/.well-known/openid-configuration\"","handlingStrategy":"validation","validationCode":"// Before configuring, fetch discovery metadata and compare with expected issuer:\nvar meta = HttpResource.retrieve(wellKnownUrl);\nSystem.out.println(meta.toJSONObject().get(\"issuer\")); // must match token 'iss' exactly","typeGuard":null,"tryCatchPattern":"try {\n    auth = connector.handleAuthResponse(...);\n} catch (AuthenticationException e) {\n    if (e.getMessage().contains(\"Inconsistent issuer\")) {\n        // fix provider metadata URL to match the token issuer, then retry\n    }\n}","preventionTips":["Use the provider's public issuer URL (scheme/host/path) verbatim in connector settings.","After changing provider URLs (http->https, new domain), update the connector.","Fix reverse proxies so the provider advertises its external URL as issuer.","Test with a discovery fetch and compare issuer to a decoded ID token."],"tags":["oidc","sso","issuer-mismatch","token-validation"],"backgroundTag":"jwt-issuer-mismatch","analyzedSha":"d44925c47c37992c828ea673a5f9620539bc3ff2","analyzedAt":"2026-09-06T07:18:27.995Z","contentChangedAt":"2026-09-06T07:18:27.995Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}