{"record":{"id":"1b96c61d5348c25b","repo":"apache/pulsar","slug":"unsupported-issuer","errorCode":"UNSUPPORTED_ISSUER","errorMessage":"Issuer not allowed: ","messagePattern":"Issuer not allowed: ","errorType":"exception","errorClass":"AuthenticationException","httpStatus":null,"severity":"error","filePath":"pulsar-broker-auth-oidc/src/main/java/org/apache/pulsar/broker/authentication/oidc/OpenIDProviderMetadataCache.java","lineNumber":232,"sourceCode":"    /**\n     * Verify the issuer url, as required by the OpenID Connect spec:\n     *\n     * Per the OpenID Connect Discovery spec, the issuer value returned MUST be identical to the\n     * Issuer URL that was directly used to retrieve the configuration information. This MUST also\n     * be identical to the iss Claim value in ID Tokens issued from this Issuer.\n     * https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationValidation\n     *\n     * @param issuer - the issuer used to retrieve the metadata\n     * @param metadata - the OpenID Provider Metadata\n     * @param isK8s - whether the issuer is represented by the Kubernetes API server. This affects error reporting.\n     * @throws AuthenticationException if the issuer does not exactly match the metadata issuer\n     */\n    private void verifyIssuer(@NonNull String issuer, OpenIDProviderMetadata metadata,\n                              boolean isK8s) throws AuthenticationException {\n        if (!issuer.equals(metadata.getIssuer())) {\n            if (isK8s) {\n                authenticationProvider.incrementFailureMetric(AuthenticationExceptionCode.UNSUPPORTED_ISSUER);\n                throw new AuthenticationException(\"Issuer not allowed: \" + issuer);\n            } else {\n                authenticationProvider.incrementFailureMetric(AuthenticationExceptionCode.ISSUER_MISMATCH);\n                throw new AuthenticationException(String.format(\"Issuer URL mismatch: [%s] should match [%s]\",\n                        issuer, metadata.getIssuer()));\n            }\n        }\n    }\n}\n","sourceCodeStart":214,"sourceCodeEnd":241,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker-auth-oidc/src/main/java/org/apache/pulsar/broker/authentication/oidc/OpenIDProviderMetadataCache.java#L214-L241","documentation":"OpenIDProviderMetadataCache.verifyIssuer() compares the issuer being configured/looked up with the issuer claim in the fetched OpenID Provider metadata. For the Kubernetes API-server path (isK8s=true) it increments UNSUPPORTED_ISSUER and throws AuthenticationException(\"Issuer not allowed: <issuer>\") when they differ, meaning the issuer is not acceptable to use. In the normal path the same mismatch throws an 'Issuer URL mismatch' with ISSUER_MISMATCH instead.","triggerScenarios":"Calling loadOpenIDProviderMetadataForIssuer() or getOpenIDProviderMetadataForKubernetesApiServer() where the requested issuer string does not exactly equal the \"issuer\" field of the metadata document the provider/API server returned — e.g. trailing-slash differences (https://issuer/ vs https://issuer), http vs https, host/port or path differences, or a Kubernetes cluster whose API server advertises a different --service-account-issuer than the one the broker expects.","commonSituations":"Kubernetes: the apiserver flag --service-account-issuer was changed or set to an internal URL while the broker is configured with the external URL (or vice versa); trailing slash or case mismatch between the configured issuer and the IdP's discovery document; switching IdP environments (dev/prod) without updating the issuer; DNS/ingress causing the advertised issuer host to differ from the configured one.","solutions":["Compare the configured issuer with the \"issuer\" field of the provider metadata (curl <issuer>/.well-known/openid-configuration) and fix the broker configuration to match exactly, including scheme, host, port, path and trailing slash.","In Kubernetes, align the broker's expected issuer with the API server's --service-account-issuer value (kubectl get --raw /.well-known/openid-configuration | jq -r .issuer).","If the API server advertises the wrong issuer, correct --service-account-issuer (and --service-account-jwks-uri if applicable) and restart the API server.","Remove trailing slashes / normalize the issuer string so both sides are byte-identical."],"exampleFix":"// before (broker.conf)\noidcIssuer=https://kubernetes.default.svc.cluster.local/\n// after — must equal the apiserver's advertised issuer exactly (no trailing slash)\noidcIssuer=https://kubernetes.default.svc.cluster.local","handlingStrategy":"validation","validationCode":"advertised=$(curl -fsSL \"$ISSUER/.well-known/openid-configuration\" | jq -r .issuer)\n[ \"$advertised\" = \"$ISSUER\" ] && echo OK || echo \"Configured '$ISSUER' != advertised '$advertised'\"","typeGuard":null,"tryCatchPattern":"try {\n    metadata = metadataCache.loadOpenIDProviderMetadataForIssuer(issuer);\n} catch (AuthenticationException e) {\n    if (e.getMessage().startsWith(\"Issuer not allowed: \")) {\n        // fetch advertised issuer from discovery and fix configuration to match exactly\n    }\n}","preventionTips":["Copy the issuer string byte-for-byte from the IdP's /.well-known/openid-configuration (watch trailing slashes, http/https, ports).","In Kubernetes, derive the issuer from the API server's advertised discovery document rather than hardcoding it.","Keep dev/prod issuer configuration separated and validated at deploy time."],"tags":["oidc","issuer-validation","kubernetes","configuration","authentication"],"backgroundTag":"issuer-mismatch","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}