apache/pulsar · critical · IOException

No secret key was provided for token authentication

Error message

No secret key was provided for token authentication

What it means

During provider initialization, getValidationKey looks for a token validation key in the configuration: first tokenSecretKey (symmetric), then tokenPublicKey (asymmetric). If neither property is set (blank), it throws this IOException because the provider has no key with which to verify token signatures.

Source

Thrown at pulsar-broker-common/src/main/java/org/apache/pulsar/broker/authentication/AuthenticationProviderToken.java:300

            Optional<String> firstEntry = list.stream().findFirst().map(Object::toString);
            return firstEntry.orElse(null);
        }
    }

    /**
     * Try to get the validation key for tokens from several possible config options.
     */
    private Key getValidationKey(ServiceConfiguration conf) throws IOException {
        String tokenSecretKey = (String) conf.getProperty(confTokenSecretKeySettingName);
        String tokenPublicKey = (String) conf.getProperty(confTokenPublicKeySettingName);
        if (StringUtils.isNotBlank(tokenSecretKey)) {
            final byte[] validationKey = AuthTokenUtils.readKeyFromUrl(tokenSecretKey);
            return AuthTokenUtils.decodeSecretKey(validationKey);
        } else if (StringUtils.isNotBlank(tokenPublicKey)) {
            final byte[] validationKey = AuthTokenUtils.readKeyFromUrl(tokenPublicKey);
            return AuthTokenUtils.decodePublicKey(validationKey, publicKeyAlg);
        } else {
            throw new IOException("No secret key was provided for token authentication");
        }
    }

    private String getTokenRoleClaim(ServiceConfiguration conf) throws IOException {
        String tokenAuthClaim = (String) conf.getProperty(confTokenAuthClaimSettingName);
        if (StringUtils.isNotBlank(tokenAuthClaim)) {
            return tokenAuthClaim;
        } else {
            return Claims.SUBJECT;
        }
    }

    private SignatureAlgorithm getPublicKeyAlgType(ServiceConfiguration conf) throws IllegalArgumentException {
        String tokenPublicAlg = (String) conf.getProperty(confTokenPublicAlgSettingName);
        if (StringUtils.isNotBlank(tokenPublicAlg)) {
            try {
                return SignatureAlgorithm.forName(tokenPublicAlg);
            } catch (SignatureException ex) {

View on GitHub (pinned to 820761864e)

Solutions

  1. Set tokenSecretKey in broker.conf/standalone.conf to the base64-encoded secret key (or data: URL) used to sign tokens, e.g. tokenSecretKey=data:;base64,<key>.
  2. For asymmetric setups, set tokenPublicKey (and tokenPublicKeyAlg for non-RS256 algorithms) instead.
  3. Verify the property names are spelled correctly and the values are non-blank after config loading.
  4. Generate a key if none exists: bin/pulsar tokens create-secret-key --output my-secret.key --base64.

Example fix

// before (broker.conf)
# tokenSecretKey=
// after
tokenSecretKey=data:;base64,base64EncodedSecretKeyHere
Defensive patterns

Strategy: validation

Validate before calling

// Fail fast at deploy time before starting the broker:
String secretKey = (String) conf.getProperty("tokenSecretKey");
String publicKey = (String) conf.getProperty("tokenPublicKey");
if ((secretKey == null || secretKey.isBlank()) && (publicKey == null || publicKey.isBlank())) {
    throw new IllegalStateException(
        "Token auth requires either tokenSecretKey or tokenPublicKey in the configuration");
}

Try / catch

try {
    authenticationProvider.initialize(conf);
} catch (IOException e) {
    if (e.getMessage().contains("No secret key was provided")) {
        throw new IllegalStateException("Set tokenSecretKey or tokenPublicKey in broker.conf before enabling token auth", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: The broker/client configuration sets authenticationProvider=org.apache.pulsar.broker.authentication.AuthenticationProviderToken (or the client sets the token auth provider) but neither tokenSecretKey nor tokenPublicKey is provided at initialize time.

Common situations: Enabling token authentication without supplying the secret key file/URL; key property name misspelled in conf; key file path exists but the property value is empty after env-var substitution; copying a config template that left the key fields blank.

Understand the failure class

Related errors


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