jwtk/jjwt · critical · WeakKeyException

The specified key byte array is bits which is not secure…

Error message

The specified key byte array is  bits which is not secure enough for any JWT HMAC-SHA algorithm.  The JWT JWA Specification (RFC 7518, Section 3.2) states that keys used with HMAC-SHA algorithms MUST have a size >= 256 bits (the key size must be greater than or equal to the hash output size).  Consider using the Jwts.SIG.HS256.key() builder (or HS384.key() or HS512.key()) to create a key guaranteed to be secure enough for your preferred HMAC-SHA algorithm.  See https://tools.ietf.org/html/rfc7518#section-3.2 for more information.

What it means

Keys.hmacShaKeyFor throws WeakKeyException when the supplied key byte array is shorter than 256 bits (32 bytes), which RFC 7518 §3.2 forbids for JWT HMAC-SHA algorithms. This is a deliberate security guard — weak keys make MAC forgery feasible.

Solutions

  1. Generate a key of at least 256 bits: Keys.secretKeyFor(SignatureAlgorithm.HS256) or Jwts.SIG.HS256.key().build()
  2. Use a random secret of >= 32 bytes, e.g. Base64 of 32+ random bytes
  3. Verify key length before calling: if (bytes.length < 32) fail at startup
  4. Persist the generated strong key securely (secret manager, vault) rather than a short string

Example fix

// before
SecretKey key = Keys.hmacShaKeyFor("secret".getBytes()); // WeakKeyException
// after
SecretKey key = Keys.secretKeyFor(io.jsonwebtoken.SignatureAlgorithm.HS256);
String encoded = Base64.getEncoder().encodeToString(key.getEncoded()); // store securely
Defensive patterns

Strategy: validation

Validate before calling

if (secretBytes == null || secretBytes.length < 32) {
    throw new IllegalStateException("JWT HMAC secret must be at least 256 bits (32 bytes)");
}

Try / catch

try {
    key = Keys.hmacShaKeyFor(secretBytes);
} catch (WeakKeyException e) {
    throw new IllegalStateException("Refusing weak JWT secret; generate with Keys.secretKeyFor(HS256)", e);
}

Prevention

When it happens

Trigger: Calling Keys.hmacShaKeyFor(bytes) where bytes.length * 8 < 512 bits fails the strongest checks and anything below 256 bits triggers this error — practically, passing a secret shorter than 32 bytes (e.g. "mysecret", a short password, or a truncated Base64 blob).

Common situations: Using a human-readable password as the JWT secret, hard-coded short demo secrets in production, or an env var silently cut off / partially loaded.

Related errors


AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09). Data as JSON: /api/errors/93c6286c099513b0. Report an issue: GitHub.

Appendix: source

Thrown at api/src/main/java/io/jsonwebtoken/security/Keys.java:83

        int bitLength = bytes.length * 8;

        //Purposefully ordered higher to lower to ensure the strongest key possible can be generated.
        if (bitLength >= 512) {
            return new SecretKeySpec(bytes, "HmacSHA512");
        } else if (bitLength >= 384) {
            return new SecretKeySpec(bytes, "HmacSHA384");
        } else if (bitLength >= 256) {
            return new SecretKeySpec(bytes, "HmacSHA256");
        }

        String msg = "The specified key byte array is " + bitLength + " bits which " +
                "is not secure enough for any JWT HMAC-SHA algorithm.  The JWT " +
                "JWA Specification (RFC 7518, Section 3.2) states that keys used with HMAC-SHA algorithms MUST have a " +
                "size >= 256 bits (the key size must be greater than or equal to the hash " +
                "output size).  Consider using the Jwts.SIG.HS256.key() builder (or HS384.key() " +
                "or HS512.key()) to create a key guaranteed to be secure enough for your preferred HMAC-SHA " +
                "algorithm.  See https://tools.ietf.org/html/rfc7518#section-3.2 for more information.";
        throw new WeakKeyException(msg);
    }

    /**
     * <p><b>Deprecation Notice</b></p>
     *
     * <p>As of JJWT 0.12.0, symmetric (secret) key algorithm instances can generate a key of suitable
     * length for that specific algorithm by calling their {@code key()} builder method directly. For example:</p>
     *
     * <pre><code>
     * {@link Jwts.SIG#HS256}.key().build();
     * {@link Jwts.SIG#HS384}.key().build();
     * {@link Jwts.SIG#HS512}.key().build();
     * </code></pre>
     *
     * <p>Call those methods as needed instead of this static {@code secretKeyFor} helper method - the returned
     * {@link KeyBuilder} allows callers to specify a preferred Provider or SecureRandom on the builder if
     * desired, whereas this {@code secretKeyFor} method does not. Consequently this helper method will be removed
     * before the 1.0 release.</p>

View on GitHub (pinned to fb71496164)