{"record":{"id":"559b9f91e7386889","repo":"keycloak/keycloak","slug":"missing-expectedaudience","errorCode":null,"errorMessage":"Missing expectedAudience","messagePattern":"Missing expectedAudience","errorType":"exception","errorClass":"VerificationException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/keycloak/TokenVerifier.java","lineNumber":152,"sourceCode":"                if (tokenType.equalsIgnoreCase(t.getType())) return true;\n            }\n            throw new VerificationException(\"Token type is incorrect. Expected '\" + tokenTypes.toString() + \"' but was '\" + t.getType() + \"'\");\n        }\n    }\n\n\n    public static class AudienceCheck implements Predicate<JsonWebToken> {\n\n        private final String expectedAudience;\n\n        public AudienceCheck(String expectedAudience) {\n            this.expectedAudience = expectedAudience;\n        }\n\n        @Override\n        public boolean test(JsonWebToken t) throws VerificationException {\n            if (expectedAudience == null) {\n                throw new VerificationException(\"Missing expectedAudience\");\n            }\n\n            String[] audience = t.getAudience();\n            if (audience == null) {\n                throw new VerificationException(\"No audience in the token\");\n            }\n\n            if (t.hasAudience(expectedAudience)) {\n                return true;\n            }\n\n            throw new VerificationException(\"Expected audience not available in the token\");\n        }\n    }\n\n\n    public static class IssuedForCheck implements Predicate<JsonWebToken> {\n","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/keycloak/keycloak/blob/66c7e15a3788de7764f07dd2558275a02770e16d/core/src/main/java/org/keycloak/TokenVerifier.java#L134-L170","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Supply a non-null audience when constructing the check, typically the resource-server client id.","If audience checking is not desired, do not add AudienceCheck to the verifier chain instead of passing null.","Validate the config key for the expected audience before building the verifier."],"exampleFix":"// before: audience config resolves to null\nverifier.audience(config.get(\"clientId\")); // null\n\n// after: guard before applying the check\nString aud = config.get(\"clientId\");\nif (aud != null) verifier.audience(aud);","handlingStrategy":"validation","validationCode":"// Validate expected audience before constructing the check\nString aud = config.get(\"expectedAudience\");\nif (aud == null) {\n  throw new IllegalStateException(\"expectedAudience not configured\");\n}\nTokenVerifier.create(token, AccessToken.class).audience(aud).verify();","typeGuard":"static boolean hasExpectedAudience(String aud) {\n  return aud != null && !aud.isBlank();\n}","tryCatchPattern":"try {\n  verifier.audience(expectedAudience).verify();\n} catch (VerificationException e) {\n  if (e.getMessage().equals(\"Missing expectedAudience\")) {\n    // configuration bug — populate the audience and retry\n  } else throw e;\n}","preventionTips":["Never pass null to AudienceCheck; omit the check instead.","Resolve the consuming client/resource id before building the verifier.","Fail fast at startup if the expected-audience config key is missing."],"tags":["jwt","verification","audience","config"],"backgroundTag":null,"analyzedSha":"66c7e15a3788de7764f07dd2558275a02770e16d","analyzedAt":"2026-08-14T01:36:42.651Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}