apache/pulsar · critical · IllegalArgumentException

Issuer URL does not use https, but must:

Error message

Issuer URL does not use https, but must: 

What it means

An IllegalArgumentException thrown by validateIssuers during initialize when an entry in allowedTokenIssuers does not start with https:// and requireHttps is true (the default). The provider refuses to start rather than trusting tokens over insecure issuer URLs, which could allow token forgery via plaintext-protected metadata endpoints.

Source

Thrown at pulsar-broker-auth-oidc/src/main/java/org/apache/pulsar/broker/authentication/oidc/AuthenticationProviderOpenID.java:500

     * the plugin to authenticate any token. Thus, it fails initialization if the configuration is
     * missing. Each issuer URL should use the HTTPS scheme. The plugin fails initialization if any
     * issuer url is insecure, unless requireHttps is false.
     * @param allowedIssuers - issuers to validate
     * @param requireHttps - whether to require https for issuers.
     * @param allowEmptyIssuers - whether to allow empty issuers. This setting only makes sense when kubernetes is used
     *                   as a fallback issuer.
     * @return the validated issuers
     * @throws IllegalArgumentException if the allowedIssuers is empty, or contains insecure issuers when required
     */
    private Set<String> validateIssuers(Set<String> allowedIssuers, boolean requireHttps, boolean allowEmptyIssuers) {
        if (allowedIssuers == null || (allowedIssuers.isEmpty() && !allowEmptyIssuers)) {
            throw new IllegalArgumentException("Missing configured value for: " + ALLOWED_TOKEN_ISSUERS);
        }
        for (String issuer : allowedIssuers) {
            if (!issuer.toLowerCase().startsWith("https://")) {
                log.warn().attr("issuer", issuer).log("Allowed issuer is not using https scheme");
                if (requireHttps) {
                    throw new IllegalArgumentException("Issuer URL does not use https, but must: " + issuer);
                }
            }
        }
        return allowedIssuers;
    }

    /**
     * Validate the configured allow list of allowedAudiences. The allowedAudiences must be set because
     * JWT must have an audience claim.
     * See https://openid.net/specs/openid-connect-basic-1_0.html#IDTokenValidation.
     * @param allowedAudiences
     * @return the validated audiences
     */
    String[] validateAllowedAudiences(Set<String> allowedAudiences) {
        if (allowedAudiences == null || allowedAudiences.isEmpty()) {
            throw new IllegalArgumentException("Missing configured value for: " + ALLOWED_AUDIENCES);
        }
        return allowedAudiences.toArray(new String[0]);

View on GitHub (pinned to 820761864e)

Solutions

  1. Change the issuer URL to use the https:// scheme in authenticationProviderOpenID.allowedTokenIssuers
  2. Serve the identity provider behind TLS (reverse proxy or ingress with a certificate)
  3. For local testing only, explicitly disable the https requirement in the provider configuration
  4. Remove the http:// entry if it is stale and keep only valid HTTPS issuers

Example fix

// before
authenticationProviderOpenID.allowedTokenIssuers=http://keycloak.internal:8080/realms/pulsar
// after
authenticationProviderOpenID.allowedTokenIssuers=https://keycloak.internal/realms/pulsar
Defensive patterns

Strategy: validation

Validate before calling

// Check every issuer uses https before applying config
Set<String> issuers = parseCsv(config.getString("authenticationProviderOpenID.allowedTokenIssuers"));
for (String issuer : issuers) {
    if (!issuer.toLowerCase().startsWith("https://")) {
        throw new IllegalStateException("Issuer must use https: " + issuer);
    }
}

Try / catch

try {
    provider.initialize(config);
} catch (IllegalArgumentException e) {
    if (e.getMessage().startsWith("Issuer URL does not use https")) {
        throw new IllegalStateException("Fix issuer URLs to https:// in allowedTokenIssuers: " + e.getMessage(), e);
    }
    throw e;
}

Prevention

When it happens

Trigger: allowedTokenIssuers contains an issuer like http://idp.example.com or a bare hostname such as idp.example.com while the requireHttps setting is enabled (default).

Common situations: Local development IdPs (Keycloak, Dex) configured with http:// URLs deployed to production config; issuer copied from documentation without the scheme; values like localhost:8081 lacking https://; older IdP deployments on plain HTTP.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/94dd4d6174f72e7a. Report an issue: GitHub.