apache/pulsar · error · AuthenticationException
UNSUPPORTED_ISSUER
UNSUPPORTED_ISSUER
Error message
Issuer not allowed:
What it means
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.
Source
Thrown at pulsar-broker-auth-oidc/src/main/java/org/apache/pulsar/broker/authentication/oidc/OpenIDProviderMetadataCache.java:232
/**
* Verify the issuer url, as required by the OpenID Connect spec:
*
* Per the OpenID Connect Discovery spec, the issuer value returned MUST be identical to the
* Issuer URL that was directly used to retrieve the configuration information. This MUST also
* be identical to the iss Claim value in ID Tokens issued from this Issuer.
* https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationValidation
*
* @param issuer - the issuer used to retrieve the metadata
* @param metadata - the OpenID Provider Metadata
* @param isK8s - whether the issuer is represented by the Kubernetes API server. This affects error reporting.
* @throws AuthenticationException if the issuer does not exactly match the metadata issuer
*/
private void verifyIssuer(@NonNull String issuer, OpenIDProviderMetadata metadata,
boolean isK8s) throws AuthenticationException {
if (!issuer.equals(metadata.getIssuer())) {
if (isK8s) {
authenticationProvider.incrementFailureMetric(AuthenticationExceptionCode.UNSUPPORTED_ISSUER);
throw new AuthenticationException("Issuer not allowed: " + issuer);
} else {
authenticationProvider.incrementFailureMetric(AuthenticationExceptionCode.ISSUER_MISMATCH);
throw new AuthenticationException(String.format("Issuer URL mismatch: [%s] should match [%s]",
issuer, metadata.getIssuer()));
}
}
}
}
View on GitHub (pinned to 820761864e)
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.
Example fix
// before (broker.conf) oidcIssuer=https://kubernetes.default.svc.cluster.local/ // after — must equal the apiserver's advertised issuer exactly (no trailing slash) oidcIssuer=https://kubernetes.default.svc.cluster.local
Defensive patterns
Strategy: validation
Validate before calling
advertised=$(curl -fsSL "$ISSUER/.well-known/openid-configuration" | jq -r .issuer) [ "$advertised" = "$ISSUER" ] && echo OK || echo "Configured '$ISSUER' != advertised '$advertised'"
Try / catch
try {
metadata = metadataCache.loadOpenIDProviderMetadataForIssuer(issuer);
} catch (AuthenticationException e) {
if (e.getMessage().startsWith("Issuer not allowed: ")) {
// fetch advertised issuer from discovery and fix configuration to match exactly
}
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Function authentication provider %s must implement Kubernete
- Invalid broker configuration. Authentication must be enabled
- No athenz domain name specified
- Invalid allowed offset for athenz role token verification sp
- Allowed offset for athenz role token verification must not b
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/1b96c61d5348c25b.
Report an issue: GitHub.