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

Key provided is shorter than

Error message

Key provided is shorter than {expectedLength} bits, only {actualLength} bits provided

What it means

Blake2b signer enforces a minimum key length (MINIMUM_KEY_LENGTH_IN_BITS) because sodium_crypto_generichash requires a key between 16 and 64 bytes. Before signing, it converts the key contents to bits and throws InvalidKeyProvided::tooShort if the key supplies fewer bits than the configured minimum. This guards against silently using cryptographically weak keys.

Solutions

  1. Generate a key of at least the minimum bit length: sodium_crypto_generichash_keygen() (32 bytes) or random_bytes(32), and pass its binary contents in the Key.
  2. Measure the current key: 8 * strlen($key->contents()) and compare against Blake2b::MINIMUM_KEY_LENGTH_IN_BITS to see how short it is.
  3. Fix the configuration/env var that supplies the key so it contains the full secret (check for trimming, quoting, or truncation issues).
  4. For user-supplied secrets too short on their own, derive a proper-length key with sodium_crypto_generichash/hkdf before constructing the Key.

Example fix

// before
$key = new Key('short'); // 8 bits -> tooShort

// after
$key = new Key(sodium_crypto_generichash_keygen()); // 256 bits
Defensive patterns

Strategy: validation

Validate before calling

$bits = 8 * strlen($keyMaterial);
if ($bits < Blake2b::MINIMUM_KEY_LENGTH_IN_BITS) {
    throw new InvalidArgumentException(sprintf('Blake2b key must be at least %d bits, got %d', Blake2b::MINIMUM_KEY_LENGTH_IN_BITS, $bits));
}

Type guard

function isBlake2bKeySize(string $secret): bool
{
    return 8 * strlen($secret) >= 16 && 8 * strlen($secret) <= 64 * 8; // generichash allows 16..64 bytes
}

Try / catch

try {
    $signature = $signer->sign($payload, $key);
} catch (InvalidKeyProvided $e) {
    throw new ConfigurationException('Blake2b signing key is too short: ' . $e->getMessage(), previous: $e);
}

Prevention

When it happens

Trigger: Calling sign($payload, $key) (or verify(), which calls sign) with a Key whose contents() are shorter than the minimum bit length (e.g. an empty string, a 4-byte short secret, or a password of a few characters).

Common situations: Config files storing empty or placeholder secrets ('secret', 'changeme'); env vars trimmed or truncated; generating keys with random_bytes(8) instead of an adequate length; copying an HMAC-style key intended for a different algorithm.

Related errors


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

Appendix: source

Thrown at src/Signer/Blake2b.php:26

use function hash_equals;
use function sodium_crypto_generichash;
use function strlen;

final readonly class Blake2b implements Signer
{
    private const int MINIMUM_KEY_LENGTH_IN_BITS = 256;

    public function algorithmId(): string
    {
        return 'BLAKE2B';
    }

    public function sign(string $payload, Key $key): string
    {
        $actualKeyLength = 8 * strlen($key->contents());

        if ($actualKeyLength < self::MINIMUM_KEY_LENGTH_IN_BITS) {
            throw InvalidKeyProvided::tooShort(self::MINIMUM_KEY_LENGTH_IN_BITS, $actualKeyLength);
        }

        return sodium_crypto_generichash($payload, $key->contents());
    }

    public function verify(string $expected, string $payload, Key $key): bool
    {
        return hash_equals($expected, $this->sign($payload, $key));
    }
}

View on GitHub (pinned to 375813049c)