keycloak/keycloak · error · VerificationException

Missing expectedAudience

Error message

Missing expectedAudience

What it means

Thrown by AudienceCheck.test when the predicate was constructed with a null expectedAudience. Like RealmUrlCheck's null guard, this fails fast rather than silently passing a no-op audience check. The check requires a concrete expected audience to compare against the token's 'aud' claim.

Source

Thrown at core/src/main/java/org/keycloak/TokenVerifier.java:152

                if (tokenType.equalsIgnoreCase(t.getType())) return true;
            }
            throw new VerificationException("Token type is incorrect. Expected '" + tokenTypes.toString() + "' but was '" + t.getType() + "'");
        }
    }


    public static class AudienceCheck implements Predicate<JsonWebToken> {

        private final String expectedAudience;

        public AudienceCheck(String expectedAudience) {
            this.expectedAudience = expectedAudience;
        }

        @Override
        public boolean test(JsonWebToken t) throws VerificationException {
            if (expectedAudience == null) {
                throw new VerificationException("Missing expectedAudience");
            }

            String[] audience = t.getAudience();
            if (audience == null) {
                throw new VerificationException("No audience in the token");
            }

            if (t.hasAudience(expectedAudience)) {
                return true;
            }

            throw new VerificationException("Expected audience not available in the token");
        }
    }


    public static class IssuedForCheck implements Predicate<JsonWebToken> {

View on GitHub (pinned to 66c7e15a37)

Solutions

  1. Supply a non-null audience when constructing the check, typically the resource-server client id.
  2. If audience checking is not desired, do not add AudienceCheck to the verifier chain instead of passing null.
  3. Validate the config key for the expected audience before building the verifier.

Example fix

// before: audience config resolves to null
verifier.audience(config.get("clientId")); // null

// after: guard before applying the check
String aud = config.get("clientId");
if (aud != null) verifier.audience(aud);
Defensive patterns

Strategy: validation

Validate before calling

// Validate expected audience before constructing the check
String aud = config.get("expectedAudience");
if (aud == null) {
  throw new IllegalStateException("expectedAudience not configured");
}
TokenVerifier.create(token, AccessToken.class).audience(aud).verify();

Type guard

static boolean hasExpectedAudience(String aud) {
  return aud != null && !aud.isBlank();
}

Try / catch

try {
  verifier.audience(expectedAudience).verify();
} catch (VerificationException e) {
  if (e.getMessage().equals("Missing expectedAudience")) {
    // configuration bug — populate the audience and retry
  } else throw e;
}

Prevention

When it happens

Trigger: Constructing new TokenVerifier.AudienceCheck(null) or supplying a null expected audience through a builder/config path that resolves to null while the AudienceCheck remains active.

Common situations: A resource server that loads the expected audience from config but the config key is missing/empty, or building an AudienceCheck dynamically from a client-id that was not yet resolved.

Related errors


AI-assisted analysis of keycloak/keycloak@66c7e15a37 (2026-08-14). Data as JSON: /api/errors/559b9f91e7386889. Report an issue: GitHub.