{"record":{"id":"6ab8ba3cdcb50733","repo":"apereo/cas","slug":"jwt-audience-is-invalid","errorCode":null,"errorMessage":"JWT audience is invalid","messagePattern":"JWT audience is invalid","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"support/cas-server-support-oidc-vc/src/main/java/org/apereo/cas/vc/presentation/OidcVerifiableCredentialPresentationResponseEndpointController.java","lineNumber":464,"sourceCode":"            val numericDate = new BigDecimal(value.toString());\n            val components = numericDate.divideAndRemainder(BigDecimal.ONE);\n            return Instant.ofEpochSecond(components[0].longValueExact(),\n                components[1].movePointRight(9).longValueExact());\n        } catch (final ArithmeticException exception) {\n            throw new IllegalArgumentException(\"JWT time claim is invalid\", exception);\n        }\n    }\n\n    private static List<String> readAudience(final Map<String, Object> claims) {\n        val audience = claims.get(\"aud\");\n        if (audience instanceof final String value) {\n            return List.of(value);\n        }\n        if (audience instanceof final List<?> values\n            && values.stream().allMatch(String.class::isInstance)) {\n            return values.stream().map(String.class::cast).toList();\n        }\n        throw new IllegalArgumentException(\"JWT audience is invalid\");\n    }\n\n    private static String requiredStringClaim(final Map<String, Object> claims, final String name) {\n        val value = claims.get(name);\n        if (!(value instanceof final String stringValue) || stringValue.isBlank()) {\n            throw new IllegalArgumentException(\"JWT string claim is missing or invalid\");\n        }\n        return stringValue;\n    }\n\n    private static boolean constantTimeEquals(final String left, final String right) {\n        return MessageDigest.isEqual(left.getBytes(StandardCharsets.UTF_8), right.getBytes(StandardCharsets.UTF_8));\n    }\n\n    private static ResponseEntity<Map<String, Object>> buildResponse(final HttpStatus status,\n                                                                     final Map<String, Object> body) {\n        return ResponseEntity.status(status)\n            .cacheControl(CacheControl.noStore())","sourceCodeStart":446,"sourceCodeEnd":482,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-oidc-vc/src/main/java/org/apereo/cas/vc/presentation/OidcVerifiableCredentialPresentationResponseEndpointController.java#L446-L482","documentation":"readAudience normalizes the JWT 'aud' claim to a list of strings, accepting a single string or a list of all-strings. Anything else (non-string values, mixed list, null with wrong shape) throws IllegalArgumentException(\"JWT audience is invalid\").","triggerScenarios":"validateKeyBindingJwt reads 'aud' from the key-binding JWT and finds a claim that is neither a String nor a List whose elements are all Strings — e.g. aud as a number, object, or list containing non-strings.","commonSituations":"Client libraries encoding aud as an object or nested list; manually crafted key-binding JWTs with a numeric client_id; serialization frameworks turning single aud into an unexpected type.","solutions":["Set 'aud' in the key-binding JWT to either a single string or an array of strings","Decode the JWT and inspect the aud claim's JSON type","Fix the JWT-building library/config that emits the malformed audience"],"exampleFix":"// before\nclaims.setAudience(12345); // numeric audience\n// after\nclaims.setAudience(\"https://cas.example.org/cas/oidc\"); // string audience","handlingStrategy":"validation","validationCode":"Object aud = claims.get(\"aud\");\nboolean ok = aud instanceof String || (aud instanceof List<?> l && l.stream().allMatch(String.class::isInstance));","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always set aud as string or array of strings","Verify token payload with a decoder before sending","Pin the JWT library's claim-typing behavior"],"tags":["jwt","audience","claims","validation"],"backgroundTag":"invalid-argument-value","analyzedSha":"e7288fc434b4f4505b8452e1a57e8fb3111bb863","analyzedAt":"2026-09-08T15:39:16.015Z","contentChangedAt":"2026-09-08T15:39:16.015Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}