{"record":{"id":"7da74cc2c3515fd9","repo":"jwtk/jjwt","slug":"provided-signature-is-actual-but-id-signatur","errorCode":null,"errorMessage":"Provided signature is ${actual} but ${id} signatures must be exactly ${expected} per [RFC 7518, Section 3.4 (validation)](https://www.rfc-editor.org/rfc/rfc7518.html#section-3.4).","messagePattern":"Provided signature is (.+?) but (.+?) signatures must be exactly (.+?) per \\[RFC 7518, Section 3\\.4 \\(validation\\)\\]\\(https://www\\.rfc-editor\\.org/rfc/rfc7518\\.html#section-3\\.4\\)\\.","errorType":"exception","errorClass":"io.jsonwebtoken.security.SignatureException","httpStatus":null,"severity":"error","filePath":"impl/src/main/java/io/jsonwebtoken/impl/security/EcSignatureAlgorithm.java","lineNumber":215,"sourceCode":"                    // mandated per https://www.rfc-editor.org/rfc/rfc7518.html#section-3.4 :\n                    if (signatureByteLength != concatSignature.length) {\n                        /*\n                         * If the expected size is not valid for JOSE, fall back to ASN.1 DER signature IFF the application\n                         * is configured to do so.  This fallback is for backwards compatibility ONLY (to support tokens\n                         * generated by early versions of jjwt) and backwards compatibility will be removed in a future\n                         * version of this library.  This fallback is only enabled if the system property is set to 'true' due to\n                         * the risk of CVE-2022-21449 attacks on early JVM versions 15, 17 and 18.\n                         */\n                        // TODO: remove for 1.0 (DER-encoding support is not in the JWT RFCs)\n                        if (concatSignature[0] == 0x30 &&\n                                \"true\".equalsIgnoreCase(System.getProperty(DER_ENCODING_SYS_PROPERTY_NAME))) {\n                            derSignature = concatSignature;\n                        } else {\n                            String msg = \"Provided signature is \" + Bytes.bytesMsg(concatSignature.length) + \" but \" +\n                                    getId() + \" signatures must be exactly \" + Bytes.bytesMsg(signatureByteLength) +\n                                    \" per [RFC 7518, Section 3.4 (validation)]\" +\n                                    \"(https://www.rfc-editor.org/rfc/rfc7518.html#section-3.4).\";\n                            throw new SignatureException(msg);\n                        }\n                    } else {\n                        //guard for JVM security bug CVE-2022-21449:\n                        if (!isValidRAndS(key, concatSignature)) {\n                            return false;\n                        }\n\n                        // Convert from concat to DER encoding since\n                        // 1) SHAXXXWithECDSAInP1363Format algorithms are only available on >= JDK 9 and\n                        // 2) the SignatureAlgorithm enum JCA alg names are all SHAXXXwithECDSA (which expects DER formatting)\n                        derSignature = transcodeConcatToDER(concatSignature);\n                    }\n\n                    sig.initVerify(key);\n                    return verify(sig, request.getPayload(), derSignature);\n\n                } catch (Exception e) {\n                    String msg = \"Unable to verify Elliptic Curve signature using provided ECPublicKey: \" + e.getMessage();","sourceCodeStart":197,"sourceCodeEnd":233,"githubUrl":"https://github.com/jwtk/jjwt/blob/fb71496164c71442d08adec4571d9616ed5e1b8d/impl/src/main/java/io/jsonwebtoken/impl/security/EcSignatureAlgorithm.java#L197-L233","documentation":"Per RFC 7518 Section 3.4, a JWS ECDSA signature must be the raw R||S concatenation of exactly 2*fieldSize bytes (64 for ES256, 96 for ES384, 132 for ES512). During verification the provided signature had a different byte length, so a SignatureException is thrown before parsing R and S. This typically means the signature was not produced in the JWS (concatenated) format.","triggerScenarios":"Passing a DER/ASN.1-encoded ECDSA signature (as output by java.security.Signature.sign() or OpenSSL by default) directly into the JWT, or passing a truncated/corrupted signature string to a parser's setSigningKey/verifyWith flow.","commonSituations":"Verifying a JWT signature produced by another library (node-jose, OpenSSL dgst) that emits DER format; hand-splitting base64url JWT parts and passing a damaged signature; storing signatures in a DB column that truncates bytes.","solutions":["Ensure the signature is the RFC 7518 raw R||S concat format, exactly 64/96/132 bytes depending on algorithm","If the source emits DER, transcode with EllipticCurveProvider.transcodeDerToConcat (or JJWT'stranscodeDERToConcat path) before verifying","Re-verify the base64url signature segment for truncation/corruption (check decoded length with Base64.getUrlDecoder())"],"exampleFix":"// before\nbyte[] sig = derSignatureFromOtherLib; // ASN.1 DER, wrong length\nparser.verifyWith(pubKey).parseSignedClaims(jwt); // fails\n// after\nbyte[] concat = io.jsonwebtoken.impl.security.EcSignatureAlgorithm.transcodeDERToConcat(derSignature, 64);\n// or better: only verify signatures produced in JWS concat format by the signing side","handlingStrategy":"validation","validationCode":"boolean isJwsConcatSignature(byte[] sig, int fieldSize) {\n  return sig != null && sig.length == fieldSize * 2; // 64 / 96 / 132\n}","typeGuard":null,"tryCatchPattern":"try {\n  Jws<Claims> jws = Jwts.parser().verifyWith(pubKey).build().parseSignedClaims(token);\n} catch (SignatureException e) {\n  if (e.getMessage().contains(\"must be exactly\")) {\n    throw new IllegalArgumentException(\"Signature not in RFC 7518 concat format\", e);\n  }\n  throw e;\n}","preventionTips":["Never feed java.security.Signature.sign() output directly into a JWS context — it is DER, not concat","Validate decoded signature length (64/96/132) before storing or transmitting tokens","When interoperating with OpenSSL/other libs, transcode DER to concat on the boundary"],"tags":["jwt","ecdsa","signature-format","rfc7518"],"backgroundTag":"invalid-argument-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"}