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 select a JWK signing key
What it means
NimbusJwtEncoder.selectJwk throws this when the JWKSource query succeeds but returns an empty key list — no JWK in the source matches the JWT's headers (algorithm, key use, key ID, etc.). Without a signing key the JWT cannot be encoded, so a JwtEncodingException is raised with the static message "Failed to select a JWK signing key".
Solutions
- Ensure the JWKSource contains at least one signing key supporting the requested algorithm: generate with e.g. com.nimbusds.jose.jwk.KeyUse.SIGNATURE and the matching KeyType.
- Match the algorithm in JwtEncoderParameters' JwsHeader to an available key's algorithm, or add the required key to the JWKSet.
- Verify each JWK has use = KeyUse.SIGNATURE (or no use restriction) so the JWKSelector matcher can match it.
- If headers carry a kid, confirm it exactly matches a getKeyID() of a key in the source (or omit kid).
- Print/log jwkSource.get(new JWKSelector(new JWKMatcher.Builder().build()), null) to see what keys are actually available and adjust the request.
Example fix
// before
RSAKey rsaKey = new RSAKey.Builder(publicKey).privateKey(privateKey).keyID("k1").build(); // no key use
JWKSet jwkSet = new JWKSet(rsaKey);
// after
RSAKey rsaKey = new RSAKey.Builder(publicKey).privateKey(privateKey).keyID("k1")
.keyUse(KeyUse.SIGNATURE).algorithm(JWSAlgorithm.RS256).build();
JWKSet jwkSet = new JWKSet(rsaKey);
// and request the same algorithm:
JwsHeader.with(JWSAlgorithm.RS256).build(); Defensive patterns
Strategy: validation
Validate before calling
// Before encoding, verify a key matching the requested algorithm exists in the source
JwsHeader header = params.getJwsHeaders();
String alg = header.getAlgorithm().getName();
List<JWK> matches = jwkSource.get(
new JWKSelector(new JWKMatcher.Builder().algorithm(alg).build()), null);
if (matches.isEmpty()) {
throw new IllegalStateException(
"No JWK for algorithm " + alg + "; JWKSet contains: "
+ jwkSource.get(new JWKSelector(new JWKMatcher.Builder().build()), null));
} Try / catch
try {
Jwt jwt = encoder.encode(params);
} catch (org.springframework.security.oauth2.jwt.JwtEncodingException ex) {
if (ex.getMessage().endsWith("Failed to select a JWK signing key")) {
log.error("No JWK matched headers alg={}; check JWKSet keys, key use, and kid",
params.getJwsHeaders().getAlgorithm());
}
throw ex;
} Prevention
- Generate JWKs with KeyUse.SIGNATURE and the algorithm you intend to request
- Keep the encoder's algorithm in JwsHeader.with(...) in sync with the keys in the JWKSource
- If using kid in headers, verify it exists in the JWKSet after rotation
- Assert at startup that JWKSet contains at least one signing key per supported algorithm
When it happens
Trigger: encode(JwtEncoderParameters) whose JWS header algorithm (e.g. RS256, ES256) or kid does not match any key in the configured JWKSet/JWKSource — e.g. source holds only an EC key while the parameters request RSA256, no "use":"sig" set, or the kid in headers doesn't exist in the key set.
Common situations: Mismatch between the JWKSet loaded into NimbusJwtEncoder and the JWSAlgorithm passed in JwsHeader.withAlgorithm(...); keys created without "use":"sig"; kid typos after key rotation; using an octet (symmetric) key where an asymmetric one is required or vice versa; empty/default-constructed JWKSet.
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/d974943895895ca0.
Report an issue: GitHub.
Appendix: source
Thrown at oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtEncoder.java:201
headers = addKeyIdentifierHeadersIfNecessary(headers, jwk);
String jws = serialize(headers, claims, jwk);
return new Jwt(jws, claims.getIssuedAt(), claims.getExpiresAt(), headers.getHeaders(), claims.getClaims());
}
private JWK selectJwk(JwsHeader headers) {
List<JWK> jwks;
try {
JWKSelector jwkSelector = new JWKSelector(createJwkMatcher(headers));
jwks = this.jwkSource.get(jwkSelector, null);
}
catch (Exception ex) {
throw new JwtEncodingException(String.format(ENCODING_ERROR_MESSAGE_TEMPLATE,
"Failed to select a JWK signing key -> " + ex.getMessage()), ex);
}
if (jwks.isEmpty()) {
throw new JwtEncodingException(
String.format(ENCODING_ERROR_MESSAGE_TEMPLATE, "Failed to select a JWK signing key"));
}
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);
}View on GitHub (pinned to 96852e8860)