spring-projects/spring-security · error · BadJwtException
An error occurred while attempting to decode the Jwt…
Error message
An error occurred while attempting to decode the Jwt: Unsupported algorithm of + jwt.getHeader().getAlgorithm()
What it means
NimbusJwtDecoder.decode parses the token and rejects unauthenticated tokens: if the parsed JWT is a PlainJWT (alg=none), it throws BadJwtException 'Unsupported algorithm of none'. Spring Security never accepts unsigned JWTs since they provide no integrity.
Solutions
- Ensure you are sending a properly signed JWT (RS256/ES256 etc.) produced by the authorization server, not an unsigned token.
- Verify the client is pointing at the real token endpoint, not a stub returning unsigned tokens.
- Check the token has three segments with a real signature; decode the header to inspect the alg value.
- If you genuinely need unsigned JWT handling, use Nimbus directly — Spring Security intentionally rejects them.
Example fix
// before (client sending unsigned token) String token = base64Header + "." + base64Payload + "."; // alg=none // after String token = signedJws.serialize(); // alg=RS256 with signature
Defensive patterns
Strategy: validation
Validate before calling
String[] parts = token.split("\\.");
if (parts.length != 3) throw new IllegalArgumentException("not a JWS");
String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8);
if (headerJson.contains("\"alg\":\"none\"")) { /* reject: unsigned token */ } Type guard
boolean isSignedJwt(String token) {
String[] parts = token.split("\\.");
return parts.length == 3 && !parts[2].isEmpty();
} Try / catch
try { jwt = jwtDecoder.decode(token); }
catch (BadJwtException e) { /* return 401 invalid_token; alg=none is never acceptable */ } Prevention
- Never accept alg=none tokens anywhere in your stack
- Ensure clients fetch tokens from the real authorization server, not mocks/stubs
- Verify tokens have three segments with a non-empty signature before decoding
When it happens
Trigger: Calling NimbusJwtDecoder.decode(token) where JWTParser.parse returns a PlainJWT — i.e. a JWS header with alg=none and no signature segment content.
Common situations: Sending raw/unsecured tokens from dev tools or mock identity providers; tokens truncated/corrupted such that they parse as unsecured; confusion with non-JWT opaque tokens passed to a JWT decoder; attackers sending alg=none tokens (this throw is the correct security behavior).
Related errors
- Invalid jwk parameter in JWS Header.
- An error occurred while attempting to decode the Jwt
- An error occurred while attempting to decode the Jwt…
- An error occurred while attempting to decode the Jwt…
- An error occurred while attempting to decode the Jwt: +…
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/1468f44bbbd17455.
Report an issue: GitHub.
Appendix: source
Thrown at oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoder.java:143
* @param claimSetConverter the {@link Converter} to use
*/
public void setClaimSetConverter(Converter<Map<String, Object>, Map<String, Object>> claimSetConverter) {
Assert.notNull(claimSetConverter, "claimSetConverter cannot be null");
this.claimSetConverter = claimSetConverter;
}
/**
* Decode and validate the JWT from its compact claims representation format.
* @param token the JWT value
* @return a validated {@link Jwt}
* @throws JwtException when the token is malformed or otherwise invalid
*/
@Override
public Jwt decode(String token) throws JwtException {
JWT jwt = parse(token);
if (jwt instanceof PlainJWT) {
this.logger.trace("Failed to decode unsigned token");
throw new BadJwtException("Unsupported algorithm of " + jwt.getHeader().getAlgorithm());
}
Jwt createdJwt = createJwt(token, jwt);
return validateJwt(createdJwt);
}
private JWT parse(String token) {
try {
return JWTParser.parse(token);
}
catch (Exception ex) {
this.logger.trace("Failed to parse token", ex);
if (ex instanceof ParseException) {
throw new BadJwtException(String.format(DECODING_ERROR_MESSAGE_TEMPLATE, "Malformed token"), ex);
}
throw new BadJwtException(String.format(DECODING_ERROR_MESSAGE_TEMPLATE, ex.getMessage()), ex);
}
}
View on GitHub (pinned to 96852e8860)