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
- 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.
- Measure the current key: 8 * strlen($key->contents()) and compare against Blake2b::MINIMUM_KEY_LENGTH_IN_BITS to see how short it is.
- Fix the configuration/env var that supplies the key so it contains the full secret (check for trimming, quoting, or truncation issues).
- 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
- Always generate Blake2b keys with sodium_crypto_generichash_keygen() (32 bytes).
- Never use short human passwords directly as keys; derive with HKDF/argon2 first if a passphrase must be used.
- Add a startup/config check asserting strlen($secret) >= minimum bytes before constructing the Key.
- Keep secrets in env/config without trimming or truncation; verify length at deploy time.
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
- The length of the provided key is different than
- <SodiumException message>
- The type of the provided key is not
- The curve of the provided key is not
- Key provided is shorter than
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)