jwtk/jjwt · error · MalformedJwtException
Invalid Base64Url <name>: <value>
Error message
Invalid Base64Url <name>: <value>
What it means
Thrown as MalformedJwtException when a JWT segment (header, payload, etc.) cannot be Base64Url-decoded during parsing. The cause is attached, but for the 'payload' segment the value in the message is redacted to avoid leaking sensitive token contents (per jjwt issue #824).
Source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java:889
@Override
public Jwe<byte[]> parseEncryptedContent(CharSequence compact) throws JwtException {
return parse(compact).accept(Jwe.CONTENT);
}
@Override
public Jwe<Claims> parseEncryptedClaims(CharSequence compact) throws JwtException {
return parse(compact).accept(Jwe.CLAIMS);
}
protected byte[] decode(CharSequence base64UrlEncoded, String name) {
try {
InputStream decoding = this.decoder.decode(Streams.of(Strings.utf8(base64UrlEncoded)));
return Streams.bytes(decoding, "Unable to Base64Url-decode input.");
} catch (Throwable t) {
// Don't disclose potentially-sensitive information per https://github.com/jwtk/jjwt/issues/824:
String value = "payload".equals(name) ? RedactedConfidentialValue.REDACTED_VALUE : base64UrlEncoded.toString();
String msg = "Invalid Base64Url " + name + ": " + value;
throw new MalformedJwtException(msg, t);
}
}
protected Map<String, ?> deserialize(InputStream in, final String name) {
try {
Reader reader = Streams.reader(in);
JsonObjectDeserializer deserializer = new JsonObjectDeserializer(this.deserializer, name);
return deserializer.apply(reader);
} finally {
Objects.nullSafeClose(in);
}
}
}
View on GitHub (pinned to fb71496164)
Solutions
- Regenerate/retransmit the full, unmodified JWT string — do not trim or transform it.
- Ensure producers use Base64Url encoding (JJWT's builder does this automatically).
- Trim whitespace/newlines from the token before parsing.
- Decode the token manually (base64url) to inspect which segment is corrupt.
- Check for upstream systems rewriting the token (proxies, HTML escaping, log truncation).
Example fix
// before
String jwt = receivedToken.trim().substring(0, 100); // truncated -> MalformedJwtException
Jwts.parser().verifyWith(key).build().parse(jwt);
// after
String jwt = receivedToken.trim();
if (!jwt.chars().allMatch(c -> Character.isLetterOrDigit(c) || c == '.' || c == '-' || c == '_')) {
throw new IllegalArgumentException("Token contains invalid Base64Url characters");
}
Jwts.parser().verifyWith(key).build().parse(jwt); Defensive patterns
Strategy: try-catch
Validate before calling
String t = jwt == null ? "" : jwt.trim();
boolean shapeOk = t.chars().filter(c -> c == '.').count() >= 2
&& t.chars().allMatch(c -> Character.isLetterOrDigit(c) || c == '.' || c == '-' || c == '_');
if (!shapeOk) throw new IllegalArgumentException("Malformed JWT string"); Try / catch
try {
claims = Jwts.parser().verifyWith(key).build().parseSignedClaims(jwt.trim()).getPayload();
} catch (io.jsonwebtoken.MalformedJwtException e) {
// reject token; do not log the raw token (payload is redacted in the message)
} Prevention
- Never truncate, wrap, or transform JWT strings in logs or storage
- Trim whitespace before parsing
- Always use Base64Url (not standard Base64) when hand-assembling tokens
- Watch for intermediaries (proxies, HTML escaping) that mangle '+'/'=' characters
When it happens
Trigger: Calling parse/parseSignedClaims/parseSignedClaimsJws/parseContentClaim on a string that is not valid compact JWT serialization: corrupted token, URL-unsafe Base64 ('+' or '/' instead of '-' and '_'), truncated or padded segments, copying only part of the token.
Common situations: Token truncated by logging/truncating code, extra whitespace or newlines pasted in, hand-rolled encoder producing standard Base64 instead of Base64Url, tokens passed through systems that mangle characters (e.g. HTML decoding '+').
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Compact JWT strings MUST always have a Base64Url protected h
- JWS header does not contain a required 'alg' (Algorithm) hea
- JWEs do not support key management alg header value 'none' p
- The JWS header references signature algorithm 'none' yet the
- Unsecured JWSs (those with an alg header value of 'none') ma
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/eaae1d95cd0e4f9b.
Report an issue: GitHub.