spring-projects/spring-security · error · JwtEncodingException

Failed to encode the JWT due to signing error: Failed to sig

Error message

Failed to encode the JWT due to signing error: Failed to sign the JWT -> + ex.getMessage()

What it means

NimbusJwtEncoder wraps JOSEException thrown by nimbus-jose-jwt's SignedJWT.sign() into a JwtEncodingException with this message. It means the JWS was fully constructed (header + claims) but the actual cryptographic signing operation failed, e.g. the signer rejected the key or algorithm at sign time. The library throws it rather than letting a raw JOSEException escape, so callers always see JwtEncodingException from encode().

Source

Thrown at oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtEncoder.java:221

		}
		if (jwks.size() == 1) {
			return jwks.get(0);
		}
		return this.jwkSelector.convert(jwks);
	}

	private String serialize(JwsHeader headers, JwtClaimsSet claims, JWK jwk) {
		JWSHeader jwsHeader = convert(headers);
		JWTClaimsSet jwtClaimsSet = convert(claims);

		JWSSigner jwsSigner = this.jwsSigners.computeIfAbsent(jwk, NimbusJwtEncoder::createSigner);

		SignedJWT signedJwt = new SignedJWT(jwsHeader, jwtClaimsSet);
		try {
			signedJwt.sign(jwsSigner);
		}
		catch (JOSEException ex) {
			throw new JwtEncodingException(
					String.format(ENCODING_ERROR_MESSAGE_TEMPLATE, "Failed to sign the JWT -> " + ex.getMessage()), ex);
		}
		return signedJwt.serialize();
	}

	private static @Nullable JWKMatcher createJwkMatcher(JwsHeader headers) {
		JwsAlgorithm algorithm = headers.getAlgorithm();
		Assert.notNull(algorithm, "JWS header algorithm must not be null");
		JWSAlgorithm jwsAlgorithm = JWSAlgorithm.parse(algorithm.getName());

		if (JWSAlgorithm.Family.RSA.contains(jwsAlgorithm) || JWSAlgorithm.Family.EC.contains(jwsAlgorithm)) {
			// @formatter:off
			return new JWKMatcher.Builder()
					.keyType(KeyType.forAlgorithm(jwsAlgorithm))
					.keyID(headers.getKeyId())
					.keyUses(KeyUse.SIGNATURE, null)
					.algorithms(jwsAlgorithm, null)
					.x509CertSHA256Thumbprint(Base64URL.from(headers.getX509SHA256Thumbprint()))

View on GitHub (pinned to 96852e8860)

Solutions

  1. Verify the JWK in your JWKSource matches the JwsAlgorithm: RSA key for RS256/RS384/RS512, EC P-256/384/521 key for ES256/384/512, symmetric key for HS256/384/512.
  2. For HS256/384/512, ensure the symmetric secret is at least as long as the hash output (256/384/512 bits): generate with a secure random generator, not a short passphrase.
  3. Read the underlying JOSEException message (it is appended and available via getCause()) — it names the exact key/algorithm constraint violated.
  4. Regenerate key material if it was truncated, hand-edited, or exported incorrectly (e.g. Base64-decoding mistakes in an OctetSequenceKey).

Example fix

// before
String secret = "short-secret";
SecretKey key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
// after
byte[] secretBytes = new byte[32];
new SecureRandom().nextBytes(secretBytes);
SecretKey key = new SecretKeySpec(secretBytes, "HmacSHA256");
Defensive patterns

Strategy: try-catch

Validate before calling

// before encode
JWK jwk = ...; // resolved key
if ("oct".equals(jwk.getKeyType().getValue())
        && jwk instanceof OctetSequenceKey osk
        && osk.getSecretBytes().length * 8 < algorithmBitLength(headers.getAlgorithm())) {
    throw new IllegalStateException("Symmetric key too short for " + headers.getAlgorithm());
}

Try / catch

try {
    jwt = jwtEncoder.encode(params);
} catch (JwtEncodingException ex) {
    logger.error("JWT signing failed: {}", ex.getCause() != null ? ex.getCause().getMessage() : ex.getMessage(), ex);
    throw new IllegalStateException("Token signing misconfiguration", ex);
}

Prevention

When it happens

Trigger: Calling NimbusJwtEncoder.encode(JwtEncoderParameters) where the resolved JWSSigner fails during sign(): a JWK whose key material is malformed or too short for the algorithm (e.g. RSA key smaller than 2048 bits for RS256), a MAC algorithm whose secret is shorter than the required minimum (e.g. HS256 secret < 256 bits), or a signer built for an algorithm that does not match the key supplied via JWKSource.

Common situations: Dev environments using truncated or hardcoded secrets for HS256; generating RSA keys with 1024 bits for legacy reasons; swapping a signing key in a config server without regenerating key material; using an OctetSequenceKey built from a passphrase string instead of a full-entropy random key; algorithm changed in JwsHeader but the JWK in the JWKSource is for a different key type.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10). Data as JSON: /api/errors/0ab0b131b1533093. Report an issue: GitHub.