spring-projects/spring-security · error · JwtEncodingException
Failed to encode the JWT due to signing error: Failed to…
Error message
Failed to encode the JWT due to signing error: Failed to create a JWS Signer -> + ex.getMessage()
What it means
NimbusJwtEncoder.createSigner() calls the nimbus-jose-jwt JWS signer factory to build a JWSSigner for the selected JWK and wraps any JOSEException in a JwtEncodingException. This fires before signing ever starts: the factory cannot construct a signer for the given key type/algorithm combination at all. It typically means the JWK's key type is incompatible with the requested JWS algorithm or the key material is invalid.
Solutions
- Check the wrapped exception via getCause(): it states why the signer could not be created (unsupported algorithm/key pair).
- Align the JwsAlgorithm in JwsHeader (or EncoderParameters claims) with the key type your JWKSource actually serves — inspect the JWK with jwk.getKeyType() and jwk.getAlgorithm().
- Rebuild the JWK ensuring required parameters exist: for RSAKey provide modulus+exponent (or KeyPair), for ECKey provide curve+point, for OctetSequenceKey provide a full-length secret.
- Test the JWK standalone with new NimbusRS256Signer / JWSAlgorithmFactory to confirm it can sign before wiring it into the JWKSource.
Example fix
// before
JWKSource<SecurityContext> jwkSource = (jwkSelector, ctx) ->
List.of(rsaKey); // algorithm requested: ES256
// after
ECKey ecKey = new ECKeyGenerator(Curve.P_256).keyID("k1").generate();
JWKSource<SecurityContext> jwkSource = (jwkSelector, ctx) ->
jwkSelector.select(List.of(ecKey)); // matches ES256 Defensive patterns
Strategy: validation
Validate before calling
// before registering the JWKSource
JWSAlgorithm alg = (JWSAlgorithm) jwsHeader.getAlgorithm();
if (!JWSAlgorithm.Family.SIGNATURE.contains(alg)
|| !jwk.getKeyType().getValue().equals(expectedKeyTypeFor(alg))) {
throw new IllegalStateException("JWK type " + jwk.getKeyType() + " unsupported for " + alg);
} Try / catch
try {
return jwtEncoder.encode(parameters);
} catch (JwtEncodingException ex) {
throw new TokenSigningException("Signer creation failed for JWK " + jwkId, ex.getCause());
} Prevention
- Derive the JwsHeader algorithm from the JWK itself (jwk.getAlgorithm()) instead of hardcoding it.
- Validate loaded keys at boot: attempt JWS_SIGNER_FACTORY.createJWSSigner(jwk) in a health check.
- When rotating keys, regenerate the full key pair/secret rather than editing individual JWK fields.
- Restrict your JWKSource selector to keys matching the required algorithm.
When it happens
Trigger: NimbusJwtEncoder.encode(...) where the JWKSource resolves a JWK that the JWSAlgorithmFactory cannot handle: e.g. requesting ES256 while the resolved JWK is an RSAKey, an OctetSequenceKey with an empty/invalid secret bytes, or a JWK missing required fields (no modulus/exponent, no EC curve parameter) so createJWSSigner throws.
Common situations: JWKSource returning keys of a different type than the configured jwsAlgorithm; hand-rolled JWK JSON parsed with missing parameters; OctetSequenceKey built with a null or too-short secret; changing the algorithm in JwtEncoderParameters without updating the keystore; loading keys from a vault/KMS where the export drops required fields.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- Failed to encode the JWT due to signing error: Failed to…
- Failed to encode the JWT due to signing error: Failed to…
- Failed to select a key since there are multiple for the…
- Failed to encode the JWT due to signing error: Failed to…
- Failed to encode the JWT due to signing error: Unable to…
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/38c9df38a7f23ed1.
Report an issue: GitHub.
Appendix: source
Thrown at oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtEncoder.java:283
}
JwsHeader.Builder headersBuilder = JwsHeader.from(headers);
if (!StringUtils.hasText(headers.getKeyId()) && StringUtils.hasText(jwk.getKeyID())) {
headersBuilder.keyId(jwk.getKeyID());
}
if (!StringUtils.hasText(headers.getX509SHA256Thumbprint()) && jwk.getX509CertSHA256Thumbprint() != null) {
headersBuilder.x509SHA256Thumbprint(jwk.getX509CertSHA256Thumbprint().toString());
}
return headersBuilder.build();
}
private static JWSSigner createSigner(JWK jwk) {
try {
return JWS_SIGNER_FACTORY.createJWSSigner(jwk);
}
catch (JOSEException ex) {
throw new JwtEncodingException(String.format(ENCODING_ERROR_MESSAGE_TEMPLATE,
"Failed to create a JWS Signer -> " + ex.getMessage()), ex);
}
}
private static JWSHeader convert(JwsHeader headers) {
JwsAlgorithm algorithm = headers.getAlgorithm();
Assert.notNull(algorithm, "JWS header algorithm must not be null");
JWSHeader.Builder builder = new JWSHeader.Builder(JWSAlgorithm.parse(algorithm.getName()));
if (headers.getJwkSetUrl() != null) {
builder.jwkURL(convertAsURI(JoseHeaderNames.JKU, headers.getJwkSetUrl()));
}
Map<String, Object> jwk = headers.getJwk();
if (!CollectionUtils.isEmpty(jwk)) {
try {
builder.jwk(JWK.parse(jwk));
}View on GitHub (pinned to 96852e8860)