spring-projects/spring-security · error · JwtEncodingException
Failed to encode the JWT due to signing error: Unable to…
Error message
Failed to encode the JWT due to signing error: Unable to convert '+ header +' JOSE header to a URI
What it means
NimbusJwtEncoder.convertAsURI(String header, URL) converts URL-valued JOSE headers (jku, x5u) to java.net.URI and wraps any conversion failure in a JwtEncodingException. java.net.URL.toURI() throws URISyntaxException when the URL is not a well-formed, RFC 2396-compliant URI (e.g. contains spaces or illegal characters). The library rejects the header rather than emitting a token with an invalid URI header.
Solutions
- Print/validate the URL before passing it: new URI(url.toString()) in a test reproduces the exact URISyntaxException and offending character.
- URL-encode path segments before constructing the URL (URLEncoder.encode or UriComponentsBuilder).
- Fix the source value in configuration/environment — spaces and illegal characters must be removed or percent-encoded.
- Verify placeholder substitution so the header never receives raw '${...}' strings.
Example fix
// before
URL jku = new URL(baseUrl + "/keys dir/jwks.json");
// after
URL jku = UriComponentsBuilder.fromHttpUrl(baseUrl)
.pathSegment("keys", "jwks.json")
.build().toUri().toURL(); Defensive patterns
Strategy: validation
Validate before calling
// validate before setting a URL JOSE header
try {
new URI(jkuUrl.toString());
} catch (URISyntaxException ex) {
throw new IllegalArgumentException("jku header value is not a valid URI", ex);
} Try / catch
try {
token = jwtEncoder.encode(params);
} catch (JwtEncodingException ex) {
if (ex.getMessage().endsWith("JOSE header to a URI")) {
throw new IllegalArgumentException("Fix the URL-valued JOSE header (jku/x5u): " + ex.getCause().getMessage(), ex);
}
throw ex;
} Prevention
- Construct URLs with UriComponentsBuilder/URI rather than string concatenation.
- Percent-encode all dynamic path/query segments.
- Externalize URL-valued header values to validated config and validate at load time.
- Check for unsubstituted placeholders and spaces in environment-derived values.
When it happens
Trigger: Calling JwsHeader.with(...).jwk(url) / x5u(url) (or .header(name, urlValue) for URL headers) where the URL was built from unvalidated user input or config containing spaces, unencoded reserved characters, or a malformed string parsed leniently by URL but rejected by URI.
Common situations: jku values assembled by string concatenation without URL-encoding a tenant or filename segment; config entries like 'https://issuer.example.com/keys dir/jwks.json' containing a space; trailing characters copied from docs; environment-specific placeholders left unsubstituted ('${jwks-url}').
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
Related errors
- Failed to encode the JWT due to signing error: Unable to…
- An error occurred while attempting to decode the Jwt: +…
- An error occurred while attempting to decode the Jwt…
- Could not coerce + source + into a URI String
- Failed to encode the JWT due to signing error: Failed to…
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/eb555dc0e3a6f987.
Report an issue: GitHub.
Appendix: source
Thrown at oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtEncoder.java:421
Map<String, Object> customClaims = new HashMap<>();
claims.getClaims().forEach((name, value) -> {
if (!JWTClaimsSet.getRegisteredNames().contains(name)) {
customClaims.put(name, value);
}
});
if (!customClaims.isEmpty()) {
customClaims.forEach(builder::claim);
}
return builder.build();
}
private static URI convertAsURI(String header, URL url) {
try {
return url.toURI();
}
catch (Exception ex) {
throw new JwtEncodingException(String.format(ENCODING_ERROR_MESSAGE_TEMPLATE,
"Unable to convert '" + header + "' JOSE header to a URI"), ex);
}
}
/**
* Creates a builder for constructing a {@link NimbusJwtEncoder} using the provided.
* @param publicKey the {@link RSAPublicKey} and @Param privateKey the
* {@link RSAPrivateKey} to use for signing JWTs
* @return a {@link RsaKeyPairJwtEncoderBuilder}
* @since 7.0
*/
public static RsaKeyPairJwtEncoderBuilder withKeyPair(RSAPublicKey publicKey, RSAPrivateKey privateKey) {
return new RsaKeyPairJwtEncoderBuilder(publicKey, privateKey);
}
/**
* Creates a builder for constructing a {@link NimbusJwtEncoder} using the provided.
* @param publicKey the {@link ECPublicKey} and @param privateKey theView on GitHub (pinned to 96852e8860)