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 -> + ex.getMessage()
What it means
NimbusJwtEncoder.selectJwk queries the configured JWKSource with a JWKSelector built from the JWT headers; if the source itself throws any Exception while selecting keys, the encoder wraps it in JwtEncodingException with the message "Failed to select a JWK signing key -> <cause>". JWT encoding is aborted because no signing key could be obtained.
Solutions
- Read the appended cause message ("-> ...") in the JwtEncodingException to identify the root failure.
- Verify the JWKSource's jwks endpoint: it must be reachable and return a valid application/json JWK Set.
- Check that the encoder's JWKSource/decoder wiring matches the authorization server's actual JWKS (correct URI, key IDs, algorithms).
- If using a custom JWKSource, run it in isolation or add try/catch logging inside get() to surface the internal bug.
- Retry encoding after fixing connectivity; transient network errors to the JWKS endpoint are the most common cause.
Example fix
// before
JWKSource<SecurityContext> jwkSource = new RemoteJWKSet<>(new URL("http://wrong-host/jwks.json"));
// after
JWKSource<SecurityContext> jwkSource = new RemoteJWKSet<>(
new URL("https://auth.example.org/oauth2/jwks")); // reachable, valid JWKS Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-flight: confirm the JWKSource can produce a key for the intended algorithm
JWKSelector sel = new JWKSelector(new JWKMatcher.Builder().algorithm("RS256").publicOnly(true).build());
if (jwkSource.get(sel, null).isEmpty()) {
throw new IllegalStateException("JWKSource returned no RS256 signing key; check jwks endpoint/config");
} Try / catch
try {
Jwt jwt = encoder.encode(params);
} catch (org.springframework.security.oauth2.jwt.JwtEncodingException ex) {
if (ex.getMessage().contains("Failed to select a JWK signing key ->")) {
Throwable cause = ex.getCause();
log.error("JWK selection failed with root cause", cause);
}
throw new IllegalStateException("JWT encoding aborted: JWK source error", ex);
} Prevention
- Validate the jwks endpoint is reachable and returns valid JSON before startup
- Unwrap and log getCause() of JwtEncodingException for the real error
- For remote JWK sources, configure timeouts and retry on transient failures
- Unit-test custom JWKSource.get implementations against expected matchers
When it happens
Trigger: encode() with a jwkSource whose get(JWKSelector, context) throws — e.g. a remote JWKSource failing its HTTP fetch, a KeySourceException, a ClassCastException from a misconfigured source, or an exception inside a custom JWKSource implementation.
Common situations: RemoteJWKSet/URL-backed source pointed at an unreachable or wrong jwks-uri; authorization server returning 5xx during key lookup; custom JWKSource with a bug (NPE, unchecked cast); the nested cause message typically reveals a network or configuration problem.
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/ab6456ccd4d04b20.
Report an issue: GitHub.
Appendix: source
Thrown at oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtEncoder.java:197
JwtClaimsSet claims = parameters.getClaims();
JWK jwk = selectJwk(headers);
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);
View on GitHub (pinned to 96852e8860)