{"record":{"id":"c8bc310d0d3af1b6","repo":"apereo/cas","slug":"proof-nonce-s-is-invalid-or-missing","errorCode":null,"errorMessage":"Proof nonce %s is invalid or missing","messagePattern":"Proof nonce (.+?) is invalid or missing","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"support/cas-server-support-oidc-vc/src/main/java/org/apereo/cas/oidc/vc/issuer/proof/OidcVerifiableCredentialJwtProofValidator.java","lineNumber":60,"sourceCode":"        verifyAudience(signedJwt);\n        verifyFreshness(signedJwt);\n        val nonce = verifyNonce(signedJwt);\n\n        val claims = signedJwt.getJWTClaimsSet();\n        return new VerifiableCredentialProofResult(\n            \"jwt\",\n            claims.getJWTID(),\n            claims.getSubject(),\n            holderJwk,\n            nonce\n        );\n    }\n\n    protected @Nullable String verifyNonce(final SignedJWT signedJwt) throws Exception {\n        val claims = signedJwt.getJWTClaimsSet();\n        val nonce = claims.getStringClaim(\"nonce\");\n        if (nonce == null || !oidcVerifiableCredentialNonceService.exists(nonce)) {\n            throw new IllegalArgumentException(\"Proof nonce %s is invalid or missing\".formatted(nonce));\n        }\n        return nonce;\n    }\n\n    protected void verifySignature(final SignedJWT signedJwt, final JWK holderJwk) throws Exception {\n        JWSVerifier verifier = null;\n        if (holderJwk instanceof final RSAKey rsaKey) {\n            verifier = new RSASSAVerifier(rsaKey);\n        } else if (holderJwk instanceof final ECKey ecKey) {\n            verifier = new ECDSAVerifier(ecKey);\n        }\n        if (verifier == null || !signedJwt.verify(verifier)) {\n            throw new IllegalArgumentException(\"Proof JWT signature validation failed\");\n        }\n    }\n\n    protected void verifyAudience(final SignedJWT signedJwt) throws ParseException {\n        val audiences = signedJwt.getJWTClaimsSet().getAudience();","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-oidc-vc/src/main/java/org/apereo/cas/oidc/vc/issuer/proof/OidcVerifiableCredentialJwtProofValidator.java#L42-L78","documentation":"Thrown by OidcVerifiableCredentialJwtProofValidator.verifyNonce when the proof JWT presented during a credential request has no 'nonce' claim, or the nonce it carries does not exist in the OidcVerifiableCredentialNonceService store (issued challenge not found / already consumed / expired). Nonces bind the proof to a specific credential offer to prevent replay.","triggerScenarios":"Submitting a credential request whose proof JWT omits the nonce claim; using a nonce that was never issued by the credential endpoint; reusing a nonce that was deleted after first use; nonce store (in-memory) lost due to server restart or multi-node deployment without shared storage.","commonSituations":"Clients skip the c_nonce round trip and build proofs without requesting a challenge first; load-balanced CAS nodes each with their own in-memory nonce service; nonce reused from a previous credential request; clock/store expiry before the proof is submitted.","solutions":["Request a fresh c_nonce from the credential endpoint and include it as the 'nonce' claim in the proof JWT before submitting.","Never reuse a nonce; fetch a new one for each credential request.","Configure a shared/persistent nonce store (e.g. ticket-registry-backed) when running multiple CAS nodes.","Ensure the proof is submitted promptly, before the nonce expires or is evicted."],"exampleFix":"// before\nJWTClaimsSet claims = new JWTClaimsSet.Builder().issuer(holderId).build(); // no nonce\n// after\nJWTClaimsSet claims = new JWTClaimsSet.Builder().issuer(holderId).claim(\"nonce\", cNonce).build();","handlingStrategy":"validation","validationCode":"String nonce = claims.getStringClaim(\"nonce\");\nif (nonce == null || !nonceService.exists(nonce)) {\n    throw new IllegalStateException(\"Obtain a fresh c_nonce before building the proof\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    validator.validate(signedJwt, holderJwk);\n} catch (IllegalArgumentException e) {\n    // fetch a new c_nonce and rebuild the proof\n}","preventionTips":["Always request a c_nonce immediately before building the proof and use it exactly once.","Use a shared nonce store across all CAS nodes.","Never cache or replay nonces across requests."],"tags":["oidc","verifiable-credentials","nonce","jwt","replay-protection"],"backgroundTag":"record-not-found","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"}