jwtk/jjwt · error · UnsupportedJwtException
Unsecured JWSs (those with an alg header value of 'none') ar
Error message
Unsecured JWSs (those with an alg header value of 'none') are disallowed by default as mandated by https://www.rfc-editor.org/rfc/rfc7518.html#section-3.6. If you wish to allow them to be parsed, call the JwtParserBuilder.unsecured() method, but please read the security considerations covered in that method's JavaDoc before doing so. Header: ${header} What it means
Unsecured JWSs (alg='none') are rejected by default as mandated by RFC 7518 Section 3.6. jjwt refuses to parse them unless the application explicitly opts in by calling JwtParserBuilder.unsecured(); when alg is 'none' and the parser is not in unsecured mode, an UnsupportedJwtException carrying the offending header is thrown.
Source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java:414
// Compact Serialization and is the approach taken by CMS [RFC6211].)
//
final String alg = Strings.clean(header.getAlgorithm());
if (!Strings.hasText(alg)) {
String msg = tokenized instanceof TokenizedJwe ? MISSING_JWE_ALG_MSG : MISSING_JWS_ALG_MSG;
throw new MalformedJwtException(msg);
}
final boolean unsecured = Jwts.SIG.NONE.getId().equalsIgnoreCase(alg);
final CharSequence base64UrlDigest = tokenized.getDigest();
final boolean hasDigest = Strings.hasText(base64UrlDigest);
if (unsecured) {
if (tokenized instanceof TokenizedJwe) {
throw new MalformedJwtException(JWE_NONE_MSG);
}
// Unsecured JWTs are disabled by default per the RFC:
if (!this.unsecured) {
String msg = UNSECURED_DISABLED_MSG_PREFIX + header;
throw new UnsupportedJwtException(msg);
}
if (hasDigest) {
throw new MalformedJwtException(JWS_NONE_SIG_MISMATCH_MSG);
}
if (header.containsKey(DefaultProtectedHeader.CRIT.getId())) {
String msg = String.format(CRIT_UNSECURED_MSG, header);
throw new MalformedJwtException(msg);
}
} else if (!hasDigest) { // something other than 'none'. Must have a digest component:
String fmt = tokenized instanceof TokenizedJwe ? MISSING_JWE_DIGEST_MSG_FMT : MISSING_JWS_DIGEST_MSG_FMT;
String msg = String.format(fmt, alg);
throw new MalformedJwtException(msg);
}
// ----- crit assertions -----
if (header instanceof ProtectedHeader) {
Set<String> crit = Collections.nullSafe(((ProtectedHeader) header).getCritical());
Set<String> supportedCrit = this.critical;
String b64Id = DefaultJwsHeader.B64.getId();View on GitHub (pinned to fb71496164)
Solutions
- If you intentionally need unsecured tokens, build the parser with Jwts.parser().unsecured() ... (read the method's security JavaDoc first).
- Prefer securing tokens: re-issue them signed with a real algorithm (e.g. HS256/RS256) and parse with verifyWith(key).
- If unsecured tokens are unexpected, treat this as an upstream issuer problem and reject the token.
- For local/dev testing only, enable unsecured parsing in a non-production parser instance.
Example fix
// before Jws<Claims> jws = Jwts.parser().build().parseSignedClaims(noneToken); // after (only if truly intended) JwtParser parser = Jwts.parser().unsecured().build(); Jwt<Header, Claims> jwt = parser.parse(noneToken);
Defensive patterns
Strategy: validation
Validate before calling
String headerJson = new String(java.util.Base64.getUrlDecoder().decode(token.split("\\.")[0]), java.nio.charset.StandardCharsets.UTF_8);
boolean unsecured = headerJson.contains("alg\":\"none\"");
JwtParser p = unsecured ? Jwts.parser().unsecured().build() : Jwts.parser().verifyWith(key).build(); Try / catch
try { return parser.parse(token); }
catch (io.jsonwebtoken.UnsupportedJwtException e) { throw new InvalidTokenException("Unsecured JWS rejected", e); } Prevention
- Sign tokens in production; avoid alg=none entirely
- If unsecured tokens are required, enable them explicitly with JwtParserBuilder.unsecured() and read its security notes
- Keep production and dev parser configurations separate
- Reject unsigned tokens at trust boundaries
When it happens
Trigger: Calling parse(), parseSignedClaims(), or parseSignedContent() on a 3-segment JWS whose header is "alg":"none" while the parser was built without JwtParserBuilder.unsecured().
Common situations: Parsing tokens minted by legacy systems or dev environments that use unsigned JWTs; testing with hand-made none-alg tokens; migrating from libraries that allowed none by default; misconfiguration where the parser was not built with .unsecured().
Related errors
- The JWS header references signature algorithm 'none' yet the
- Unsecured JWSs (those with an alg header value of 'none') ma
- Unexpected content JWS.
- Unexpected Claims JWS.
- Both 'signWith' and 'encryptWith' cannot be specified. Choos
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/dbb20b438867ccfd.
Report an issue: GitHub.