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

Thrown by Hmac::sign when the key material provided to the Signer is shorter than the minimum bits required by the HMAC algorithm variant (e.g. HS256 requires 128 bits, HS384 192, HS512 256, per RFC 7518). The library enforces this before calling hash_hmac to prevent use of weak keys.

Solutions

  1. Provide a key at least as long as required: HS256 >= 16 bytes, HS384 >= 24 bytes, HS512 >= 32 bytes
  2. Generate a strong secret, e.g. `base64_encode(random_bytes(32))` or `openssl rand -base64 32`
  3. Check the environment variable / config source actually contains the full secret (no truncation or quoting issues)
  4. Align the key length with the algorithm: pick a longer key for HS384/HS512

Example fix

// before
$key = InMemory::plainText('secret');
// after
$key = InMemory::plainText(base64_encode(random_bytes(32))); // 256 bits
Defensive patterns

Strategy: validation

Validate before calling

if (strlen($secret) * 8 < 256) { throw new InvalidArgumentException('HMAC key must be >= 256 bits for HS256+' ); }

Try / catch

try { $builder->signedWith($key); ... } catch (\Jose\Component\Signature\Exception\InvalidKeyProvided $e) { /* reject weak key at startup */ }

Prevention

When it happens

Trigger: Calling Hmac::sign() (directly or via the JWT Builder) with a Key whose contents are fewer bits than minimumBitsLengthForKey(); also triggered on verify() since it delegates to sign().

Common situations: Placeholder secrets like 'secret' in dev config, truncated environment variables, keys loaded from config files with whitespace-only or test values, upgrading from a laxer JWT library that accepted short secrets.

Related errors


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

Appendix: source

Thrown at src/Signer/Hmac.php:20

declare(strict_types=1);

namespace Lcobucci\JWT\Signer;

use Lcobucci\JWT\Signer;

use function hash_equals;
use function hash_hmac;
use function strlen;

abstract readonly class Hmac implements Signer
{
    final public function sign(string $payload, Key $key): string
    {
        $actualKeyLength   = 8 * strlen($key->contents());
        $expectedKeyLength = $this->minimumBitsLengthForKey();

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

        return hash_hmac($this->algorithm(), $payload, $key->contents(), true);
    }

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

    /**
     * @internal
     *
     * @return non-empty-string
     */
    abstract public function algorithm(): string;

    /**

View on GitHub (pinned to 375813049c)