lcobucci/jwt · error · Lcobucci\JWT\Signer\InvalidKeyProvided

The type of the provided key is not

Error message

The type of the provided key is not "{expectedType}", "{actualType}" provided

What it means

Ecdsa's guardAgainstIncompatibleKey verifies that the OpenSSL key material given to the signer is actually an EC key (OPENSSL_KEYTYPE_EC). If openssl_pkey_get_details() reports a different key type (RSA, DSA, Ed25519, DH), the signer throws InvalidKeyProvided::incompatibleKeyType naming the expected and actual key types. Each concrete ECDSA signer requires an EC key on its expected curve.

Solutions

  1. Generate a proper EC key on the required curve, e.g. openssl ecparam -name prime256v1 -genkey -noout -out ec-private.pem (use secp384r1 for ES384, secp521r1 for ES512).
  2. Inspect the loaded key with openssl_pkey_get_details(openssl_pkey_get_private($pem)) and confirm ['type'] === OPENSSL_KEYTYPE_EC before passing it to the signer.
  3. Point your configuration at the correct EC key file — the current path likely contains an RSA key.
  4. If migrating algorithms, re-sign tokens with the new EC key pair and update verifiers accordingly instead of reusing RSA keys.

Example fix

// before
$signer = new Es256();
$key = new Key(file_get_contents('rsa-private.pem')); // RSA key -> incompatibleKeyType

// after
shell_exec('openssl ecparam -name prime256v1 -genkey -noout -out ec-private.pem');
$key = new Key(file_get_contents('ec-private.pem')); // EC key on P-256
Defensive patterns

Strategy: validation

Validate before calling

$details = openssl_pkey_get_details(openssl_pkey_get_private($pem));
if (($details['type'] ?? null) !== OPENSSL_KEYTYPE_EC) {
    throw new InvalidArgumentException('ECDSA signers require an EC key; got type ' . ($details['type'] ?? 'unknown'));
}

Type guard

function isEcKeyString(string $pem): bool
{
    $key = openssl_pkey_get_private($pem);
    if ($key === false) {
        return false;
    }
    return (openssl_pkey_get_details($key)['type'] ?? null) === OPENSSL_KEYTYPE_EC;
}

Try / catch

try {
    $token = $config->builder()->getToken($signer, $key);
} catch (InvalidKeyProvided $e) {
    throw new ConfigurationException('Signing key incompatible with ECDSA signer: ' . $e->getMessage(), previous: $e);
}

Prevention

When it happens

Trigger: Constructing an ECDSA signer (e.g. Es256, Es384, Es512) and calling sign/verify with a Key built from an RSA (or other) PEM/KEY string; passing an openssl key resource whose details['type'] !== OPENSSL_KEYTYPE_EC.

Common situations: Swapping signing algorithms (e.g. from RS256 to ES256) without regenerating the key pair; loading the wrong PEM file from disk; a config pointing at a shared RSA certificate; automated key rotation that injects a mismatched key.

Related errors


AI-assisted analysis of lcobucci/jwt@375813049c (2026-09-14). Data as JSON: /api/errors/6d9bc89aabc2a203. Report an issue: GitHub.

Appendix: source

Thrown at src/Signer/Ecdsa.php:39

            $this->createSignature($key, $payload),
            $this->pointLength(),
        );
    }

    final public function verify(string $expected, string $payload, Key $key): bool
    {
        return $this->verifySignature(
            $this->converter->toAsn1($expected, $this->pointLength()),
            $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) {

View on GitHub (pinned to 375813049c)