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

  1. Regenerate/retransmit the full, unmodified JWT string — do not trim or transform it.
  2. Ensure producers use Base64Url encoding (JJWT's builder does this automatically).
  3. Trim whitespace/newlines from the token before parsing.
  4. Decode the token manually (base64url) to inspect which segment is corrupt.
  5. 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

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


AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09). Data as JSON: /api/errors/eaae1d95cd0e4f9b. Report an issue: GitHub.