lcobucci/jwt · error · Lcobucci\JWT\Signer\InvalidKeyProvided
The length of the provided key is different than
Error message
The length of the provided key is different than {expectedLength} bits, {actualLength} bits provided What it means
After confirming the key is an EC key, Ecdsa's guardAgainstIncompatibleKey compares the key's bit length (details['bits']) with the length required by the concrete signer via expectedKeyLength() (256 for ES256, 384 for ES384, 512 for ES512). A mismatch throws InvalidKeyProvided::incompatibleKeyLength, because an ECDSA signature scheme is bound to a specific curve/key size.
Solutions
- Match the curve to the algorithm: prime256v1 for ES256 (256 bits), secp384r1 for ES384 (384 bits), secp521r1 for ES512 (521 bits — note the signer's expected length semantics).
- Check the actual key size: openssl_pkey_get_details(openssl_pkey_get_private($pem))['bits'] and compare with the signer's expectedKeyLength().
- Regenerate the key pair with the correct curve: openssl ecparam -name secp384r1 -genkey -noout -out key.pem.
- Or instantiate the signer matching the key you already have (Es256 for a 256-bit key, etc.) instead of changing keys.
Example fix
// before
$signer = new Es384();
$key = new Key(file_get_contents('p256-key.pem')); // 256 bits -> incompatibleKeyLength
// after
shell_exec('openssl ecparam -name secp384r1 -genkey -noout -out p384-key.pem');
$signer = new Es384();
$key = new Key(file_get_contents('p384-key.pem')); // 384 bits Defensive patterns
Strategy: validation
Validate before calling
$details = openssl_pkey_get_details(openssl_pkey_get_private($pem));
if (($details['bits'] ?? 0) !== $signer::expectedBits()) { // e.g. 256 for Es256
throw new InvalidArgumentException(sprintf('Key is %d bits; signer requires %d bits', $details['bits'] ?? 0, $signer::expectedBits()));
} Type guard
function keyMatchesEcdsaBits(string $pem, int $expectedBits): bool
{
$key = openssl_pkey_get_private($pem);
$details = $key === false ? null : openssl_pkey_get_details($key);
return ($details['bits'] ?? -1) === $expectedBits;
} Try / catch
try {
$signature = $signer->sign($payload, $key);
} catch (InvalidKeyProvided $e) {
throw new ConfigurationException('ECDSA key length mismatch: ' . $e->getMessage(), previous: $e);
} Prevention
- Map algorithm to curve explicitly (ES256->prime256v1, ES384->secp384r1, ES512->secp521r1) and document it next to key generation commands.
- Never share one EC key pair among signers of different curve sizes.
- Check ['bits'] from openssl_pkey_get_details immediately after loading or rotating keys.
- Add a CI check that validates every configured signing key's type/curve/bits against its signer.
When it happens
Trigger: Using e.g. an ES384 signer with a P-256 (256-bit) key, or an ES256 signer with a P-521 key — sign() or verify() resolves the key details and calls guardAgainstIncompatibleKey($type, $bits).
Common situations: Generating an EC key without matching the curve to the algorithm (openssl ecparam default curve differs from the signer's expectation); switching the JWT algorithm in config from ES256 to ES384 without regenerating keys; hardcoding one key pair for multiple signers.
Related errors
- The curve of the provided key is not
- Key provided is shorter than
- The type of the provided key is not
- Invalid signature length.
- Invalid data. Should start with a sequence.
AI-assisted analysis of lcobucci/jwt@375813049c (2026-09-14).
Data as JSON: /api/errors/304d176ec88e9f32.
Report an issue: GitHub.
Appendix: source
Thrown at src/Signer/Ecdsa.php:48
$payload,
$key,
);
}
/** {@inheritDoc} */
final protected function guardAgainstIncompatibleKey(int $type, int $lengthInBits): void
{
if ($type !== OPENSSL_KEYTYPE_EC) {
throw InvalidKeyProvided::incompatibleKeyType(
self::KEY_TYPE_MAP[OPENSSL_KEYTYPE_EC],
self::KEY_TYPE_MAP[$type] ?? 'unknown',
);
}
$expectedKeyLength = $this->expectedKeyLength();
if ($lengthInBits !== $expectedKeyLength) {
throw InvalidKeyProvided::incompatibleKeyLength($expectedKeyLength, $lengthInBits);
}
}
/** {@inheritDoc} */
final protected function guardAgainstIncompatibleCurve(?string $curveName): void
{
$expectedCurve = $this->expectedCurve();
if ($curveName !== $expectedCurve) {
throw InvalidKeyProvided::incompatibleKeyCurve($expectedCurve, $curveName ?? 'unknown');
}
}
/**
* @internal
*
* @return positive-int
*/View on GitHub (pinned to 375813049c)