{"record":{"id":"f20042032d2e02dd","repo":"jwtk/jjwt","slug":"jwe-header-epk-value-is-not-an-elliptic-curve-publ","errorCode":null,"errorMessage":"JWE Header epk value is not an Elliptic Curve Public JWK. Value: ${epk}","messagePattern":"JWE Header epk value is not an Elliptic Curve Public JWK\\. Value: (.+?)","errorType":"exception","errorClass":"io.jsonwebtoken.security.InvalidKeyException","httpStatus":null,"severity":"error","filePath":"impl/src/main/java/io/jsonwebtoken/impl/security/EcdhKeyAlgorithm.java","lineNumber":221,"sourceCode":"        return result;\n    }\n\n    @Override\n    public SecretKey getDecryptionKey(DecryptionKeyRequest<PrivateKey> request) throws SecurityException {\n\n        Assert.notNull(request, \"Request cannot be null.\");\n        JweHeader header = Assert.notNull(request.getHeader(), \"Request JweHeader cannot be null.\");\n        PrivateKey privateKey = Assert.notNull(request.getKey(), \"Decryption PrivateKey cannot be null.\");\n        ParameterReadable reader = new RequiredParameterReader(header);\n        PublicJwk<?> epk = reader.get(DefaultJweHeader.EPK);\n\n        AbstractCurve curve = assertCurve(privateKey);\n        Assert.stateNotNull(curve, \"Internal implementation state: Curve cannot be null.\");\n        Class<?> epkClass = curve instanceof ECCurve ? EcPublicJwk.class : OctetPublicJwk.class;\n        if (!epkClass.isInstance(epk)) {\n            String msg = \"JWE Header \" + DefaultJweHeader.EPK + \" value is not an Elliptic Curve \" +\n                    \"Public JWK. Value: \" + epk;\n            throw new InvalidKeyException(msg);\n        }\n        if (!curve.contains(epk.toKey())) {\n            String msg = \"JWE Header \" + DefaultJweHeader.EPK + \" value does not represent \" +\n                    \"a point on the expected curve. Value: \" + epk;\n            throw new InvalidKeyException(msg);\n        }\n\n        final SecretKey derived = deriveKey(request, epk.toKey(), privateKey);\n\n        DecryptionKeyRequest<SecretKey> unwrapReq = new DefaultDecryptionKeyRequest<>(request.getPayload(),\n                null, request.getSecureRandom(), header, request.getEncryptionAlgorithm(), derived);\n\n        return WRAP_ALG.getDecryptionKey(unwrapReq);\n    }\n}\n","sourceCodeStart":203,"sourceCodeEnd":237,"githubUrl":"https://github.com/jwtk/jjwt/blob/fb71496164c71442d08adec4571d9616ed5e1b8d/impl/src/main/java/io/jsonwebtoken/impl/security/EcdhKeyAlgorithm.java#L203-L237","documentation":"This error means the `epk` (ephemeral public key) JWK found in the JWE protected header is not an Elliptic Curve Public JWK of the type the recipient key's curve requires (an EcPublicJwk for standard EC curves, or an OctetPublicJwk for OkP/Edwards curves). During ECDH key agreement decryption, getDecryptionKey validates that the sender's ephemeral key material is a proper EC public JWK before deriving the shared key; if it is absent, malformed, or the wrong JWK family, an InvalidKeyException is thrown.","triggerScenarios":"Decrypting a JWE that was produced with an ECDH-ES key-management algorithm whose protected header contains an `epk` value that is missing, not a JSON object, not a JWK with a proper `kty`/`crv`, or whose curve family mismatches the recipient key (e.g. an octet key pair epk when decrypting with an EC P-256 private key).","commonSituations":"Hand-rolled token producers that omit or mangle the epk header; a sender and recipient using different curve families (EC vs OKP); tokens tampered with or truncated; using a recipient key type that does not match how the token was encrypted.","solutions":["Verify the sender encrypts with the matching ECDH-ES algorithm and curve for your recipient key (e.g. ECDH-ES+A256KW with an EC key on the same curve).","Inspect the JWE protected header and confirm the `epk` field is a complete EC/OKP public JWK with kty and crv.","Regenerate the token with a maintained jjwt (or other spec-compliant) producer rather than hand-assembling headers.","Confirm the recipient PrivateKey curve family matches the epk curve family (EcPublicJwk vs OctetPublicJwk)."],"exampleFix":"// before: encrypting with a mismatched recipient key type\nKeysbuilder kb = new KeysBuilder(spec); // recipient key is an EC key but token built for OKP\n// after\nSecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256); // or use the EC key with ECDH-ES\nString jwe = Jwts.builder().setHeader(...).encryptWith(key, Jwts.KEY.Alg.ECDH_ES_A256KW, A256GCM);","handlingStrategy":"validation","validationCode":"Object epk = header.get(\"epk\");\nboolean ok = epk instanceof Map && ((Map<?,?>) epk).get(\"kty\") instanceof String\n    && (((String)((Map<?,?>)epk).get(\"kty\")).equals(\"EC\") || ((String)((Map<?,?>)epk).get(\"kty\")).equals(\"OKP\"));\nif (!ok) throw new IllegalArgumentException(\"JWE header missing a valid EC/OKP epk JWK\");","typeGuard":"boolean isEcPublicJwk(Object o) {\n  return o instanceof Map && \"EC\".equals(((Map<?,?>)o).get(\"kty\")) && ((Map<?,?>)o).containsKey(\"crv\");\n}","tryCatchPattern":"try {\n  Jwe<Claims> jwe = Jwts.parser().decryptWith(ecPrivateKey).build().parseEncryptedClaims(token);\n} catch (InvalidKeyException e) {\n  // epk header invalid or off-curve: reject token / request re-encryption\n}","preventionTips":["Always encrypt with a maintained jjwt producer so epk is generated correctly","Match the recipient key curve family to the key-management algorithm","Never hand-edit JWE header values"],"tags":["jwe","jwk","ecdh","invalid-key"],"backgroundTag":"invalid-key-format","analyzedSha":"fb71496164c71442d08adec4571d9616ed5e1b8d","analyzedAt":"2026-09-09T00:33:09.982Z","contentChangedAt":"2026-09-09T00:33:09.982Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}