jwtk/jjwt · error · io.jsonwebtoken.security.InvalidKeyException
JWE Header epk value does not represent a point on the expec
Error message
JWE Header epk value does not represent a point on the expected curve. Value: ${epk} What it means
During ECDH-ES decryption, after confirming the header's `epk` is the right JWK type, jjwt checks that the ephemeral public key's point actually lies on the recipient key's curve (curve.contains(epk.toKey())). If the point is off-curve, the key material is invalid and decryption is aborted with an InvalidKeyException, since continuing would allow invalid-curve attacks.
Source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/security/EcdhKeyAlgorithm.java:226
Assert.notNull(request, "Request cannot be null.");
JweHeader header = Assert.notNull(request.getHeader(), "Request JweHeader cannot be null.");
PrivateKey privateKey = Assert.notNull(request.getKey(), "Decryption PrivateKey cannot be null.");
ParameterReadable reader = new RequiredParameterReader(header);
PublicJwk<?> epk = reader.get(DefaultJweHeader.EPK);
AbstractCurve curve = assertCurve(privateKey);
Assert.stateNotNull(curve, "Internal implementation state: Curve cannot be null.");
Class<?> epkClass = curve instanceof ECCurve ? EcPublicJwk.class : OctetPublicJwk.class;
if (!epkClass.isInstance(epk)) {
String msg = "JWE Header " + DefaultJweHeader.EPK + " value is not an Elliptic Curve " +
"Public JWK. Value: " + epk;
throw new InvalidKeyException(msg);
}
if (!curve.contains(epk.toKey())) {
String msg = "JWE Header " + DefaultJweHeader.EPK + " value does not represent " +
"a point on the expected curve. Value: " + epk;
throw new InvalidKeyException(msg);
}
final SecretKey derived = deriveKey(request, epk.toKey(), privateKey);
DecryptionKeyRequest<SecretKey> unwrapReq = new DefaultDecryptionKeyRequest<>(request.getPayload(),
null, request.getSecureRandom(), header, request.getEncryptionAlgorithm(), derived);
return WRAP_ALG.getDecryptionKey(unwrapReq);
}
}
View on GitHub (pinned to fb71496164)
Solutions
- Ensure both parties use the same named curve (crv) for the recipient key and epk.
- Re-encrypt the token with a compliant library; do not manually edit header values.
- If attacks are a concern, this error is jjwt correctly rejecting an invalid-curve input — audit the token source.
- Verify no base64url corruption of the compact token (wrong padding/characters) when transporting it.
Example fix
// before: recipient key on P-384 while sender encrypts with P-256 ECPrivateKey key = (ECPrivateKey) Keys.privateKeyFor(SignatureAlgorithm.ES384); // after: use matching curves on both sides ECPrivateKey key = (ECPrivateKey) Keys.privateKeyFor(SignatureAlgorithm.ES256);
Defensive patterns
Strategy: validation
Validate before calling
String crv = (String) ((Map<?,?>) header.get("epk")).get("crv");
if (!expectedCurveId.equals(crv)) throw new IllegalArgumentException("epk curve mismatch: " + crv); Type guard
boolean isPointOnExpectedCurve(Object epk, String expectedCrv) {
return epk instanceof Map && expectedCrv.equals(((Map<?,?>)epk).get("crv"));
} Try / catch
try {
Jwe<Claims> jwe = Jwts.parser().decryptWith(privateKey).build().parseEncryptedClaims(token);
} catch (InvalidKeyException e) {
// treat as invalid/tampered token: reject and log the curve mismatch
} Prevention
- Use the same named curve on sender and recipient
- Never accept tokens from producers that skip curve validation
- Guard tokens in transit against corruption (integrity-checked channels)
When it happens
Trigger: Decrypting a JWE whose `epk` header decodes to a point not on the recipient's named curve — e.g. coordinates crafted or corrupted, an epk generated for a different curve (P-256 epk with P-384 recipient key), or truncated/byte-mangled x/y or raw x coordinates.
Common situations: Sender and recipient disagree on the curve (crv mismatch); tokens produced by non-compliant libraries that do not validate curve membership; deliberate invalid-curve attack attempts; corrupted tokens in transit.
Related errors
- Unable to determine JWA-standard Elliptic Curve for ${type}k
- JWE Header epk value is not an Elliptic Curve Public JWK. Va
- PublicKeys may not be used to decrypt data. PublicKeys are u
- Invalid RSA key algorithm name.
- RSASSA-PSS keys may not be used for ${keyType}, only digital
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/1ad489e827abd87f.
Report an issue: GitHub.