{"record":{"id":"057aed413b5b726c","repo":"apereo/cas","slug":"unable-to-verify-jwt-assertion-with-any-of-the-con-057aed","errorCode":null,"errorMessage":"Unable to verify JWT assertion with any of the configured JSON web keys","messagePattern":"Unable to verify JWT assertion with any of the configured JSON web keys","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"support/cas-server-support-oidc-core-api/src/main/java/org/apereo/cas/oidc/token/OidcAccessTokenJwtBearerGrantRequestExtractor.java","lineNumber":152,"sourceCode":"            Set.of(OidcConstants.ISS, OidcConstants.AUD, OAuth20Constants.CLAIM_SUB, OAuth20Constants.CLAIM_EXP),\n            Set.of());\n        jwtClaimsSetVerifier.verify(JWTClaimsSet.parse(claims.getClaimsMap()), new SimpleSecurityContext());\n        return claims;\n    }\n\n    protected String verifyAssertion(final String assertion, final List<PublicJsonWebKey> jsonWebKeys) {\n        for (val jsonWebKey : jsonWebKeys) {\n            try {\n                val verified = EncodingUtils.verifyJwsSignature(jsonWebKey.getPublicKey(), assertion);\n                val verifiedAssertion = new String(verified, StandardCharsets.UTF_8);\n                LOGGER.trace(\"Successfully verified JWT assertion with key id [{}]\", jsonWebKey.getKeyId());\n                return verifiedAssertion;\n            } catch (final Exception e) {\n                LOGGER.debug(\"Failed to verify JWT assertion via key id [{}]: [{}]. Moving on to the next key\",\n                    jsonWebKey.getKeyId(), e.getMessage());\n            }\n        }\n        throw new IllegalArgumentException(\"Unable to verify JWT assertion with any of the configured JSON web keys\");\n    }\n\n    protected AccessTokenRequestContext extractInternal(\n        final WebContext context,\n        final AccessTokenRequestContext tokenRequestContext) {\n        return tokenRequestContext;\n    }\n\n    protected static boolean isAllowedToGenerateRefreshToken() {\n        return true;\n    }\n\n    @Override\n    public boolean supports(final WebContext context) {\n        val grantType = getConfigurationContext().getObject().getRequestParameterResolver()\n            .resolveRequestParameter(context, OAuth20Constants.GRANT_TYPE).orElse(StringUtils.EMPTY);\n        val assertion = getConfigurationContext().getObject().getRequestParameterResolver()\n            .resolveRequestParameter(context, OAuth20Constants.ASSERTION).orElse(StringUtils.EMPTY);","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-oidc-core-api/src/main/java/org/apereo/cas/oidc/token/OidcAccessTokenJwtBearerGrantRequestExtractor.java#L134-L170","documentation":"OidcAccessTokenJwtBearerGrantRequestExtractor.verifyAssertion throws this when a JWT bearer (RFC 7523) assertion sent to the token endpoint cannot be verified against any of the configured JSON web keys. Each candidate key is tried and the final failure is reported only after all keys are exhausted, so the assertion's signature is untrusted.","triggerScenarios":"A private_key_jwt / jwt-bearer grant request supplies a client_assertion whose signature, issuer, audience, or expiry fails validation for every JSON web key available to CAS (client JWKS or trust store); each attempt throws and is caught, then this is thrown.","commonSituations":"Client signs assertion with a key not present in its JWKS; assertion 'aud' doesn't match the token endpoint/issuer; clock skew makes assertion expired; client rotated keys but CAS cached an old JWKS.","solutions":["Ensure the assertion is signed with a private key whose public counterpart is published in the client's JWKS","Set the assertion 'aud' to the CAS issuer or token endpoint URL as configured","Check assertion 'exp'/'nbf' and system clock skew on the client","Force a JWKS refresh / verify the client's jwks_uri serves the current key set","Enable debug logging for OidcAccessTokenJwtBearerGrantRequestExtractor to see the per-key failure reason"],"exampleFix":"// before: assertion built with wrong audience\nJWTParser.parse(assertion).getJWTClaimsSet().getAudience() == [\"https://wrong-aud\"]\n// after: audience must match CAS issuer/token endpoint\nbuilder.audience(\"https://cas.example.org/cas/oidc\")","handlingStrategy":"try-catch","validationCode":"var claims = SignedJWT.parse(assertion).getJWTClaimsSet();\nif (!issuer.equals(claims.getIssuer()) || !expectedAud.containsAll(claims.getAudience()) || new Date().after(claims.getExpirationTime())) {\n    throw new IllegalStateException(\"Client assertion will not verify: check issuer, audience, expiry\");\n}","typeGuard":null,"tryCatchPattern":"try { extractor.verifyAssertion(context, assertion); } catch (IllegalArgumentException e) { throw new InvalidClientException(\"client assertion verification failed: \" + e.getMessage()); }","preventionTips":["Sign client assertions with keys published in the client's JWKS","Set assertion aud to the CAS token endpoint or issuer","Sync clocks (NTP) between client and CAS","Refresh cached JWKS after client key rotation"],"tags":["oidc","jwt","signature-verification","authentication"],"backgroundTag":"jwt-verification-failed","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"}