keycloak/keycloak · error · VerificationException
Failed to parse JWT
Error message
Failed to parse JWT
What it means
Thrown by TokenVerifier.parse() when constructing new JWSInput(tokenString) raises a JWSInputException. This means the string could not even be interpreted as a JWS compact serialization — typically malformed base64url, wrong segment count, or an unparseable header. The original JWSInputException is chained as the cause. This fires before any JSON deserialization of the payload (a separate, later check handles payload reading).
Source
Thrown at core/src/main/java/org/keycloak/TokenVerifier.java:408
* Add check for verifying that token issuedFor (azp claim) is the expected value
*
* @param expectedIssuedFor issuedFor, which needs to be in the target token. Can't be null
* @return This token verifier
*/
public TokenVerifier<T> issuedFor(String expectedIssuedFor) {
return this.replaceCheck(IssuedForCheck.class, true, new IssuedForCheck(expectedIssuedFor));
}
public TokenVerifier<T> parse() throws VerificationException {
if (jws == null) {
if (tokenString == null) {
throw new VerificationException("Token not set");
}
try {
jws = new JWSInput(tokenString);
} catch (JWSInputException e) {
throw new VerificationException("Failed to parse JWT", e);
}
try {
token = jws.readJsonContent(clazz);
} catch (JWSInputException e) {
throw new VerificationException("Failed to read access token from JWT", e);
}
}
return this;
}
public T getToken() throws VerificationException {
if (token == null) {
parse();
}
return token;
}View on GitHub (pinned to 66c7e15a37)
Solutions
- Inspect the chained JWSInputException cause for the precise parse stage that failed.
- Verify the token has exactly two '.' separators and uses base64url alphabet (A–Z, a–z, 0–9, -, _) with no padding issues.
- Ensure the token is not URL-encoded when passed to the verifier; strip 'Bearer ' prefix and any surrounding whitespace.
- If the value is not a JWT at all, route it to the appropriate validator instead of TokenVerifier.
Example fix
// before: header includes 'Bearer ' prefix or is URL-encoded
TokenVerifier.create(rawHeader, AccessToken.class).verify();
// after: normalize the token string first
String token = rawHeader;
if (token.startsWith("Bearer ")) token = token.substring(7);
token = URLDecoder.decode(token, StandardCharsets.UTF_8);
TokenVerifier.create(token, AccessToken.class).verify(); Defensive patterns
Strategy: validation
Validate before calling
// Normalize the token string before parsing
static String normalize(String raw) {
if (raw == null) return null;
if (raw.startsWith("Bearer ")) raw = raw.substring(7);
return raw.trim();
}
String token = normalize(header);
if (token == null || token.split("\\.").length != 3) {
// not a compact JWS — reject before parsing
}
TokenVerifier.create(token, AccessToken.class).parse(); Type guard
static boolean isCompactJws(String s) {
return s != null && s.split("\\.").length == 3
&& s.chars().allMatch(c -> isBase64UrlChar((char) c) || c == '.');
} Try / catch
try {
TokenVerifier.create(token, AccessToken.class).parse();
} catch (VerificationException e) {
if (e.getMessage().equals("Failed to parse JWT")) {
// inspect e.getCause() (JWSInputException); normalize encoding/structure and retry
} else throw e;
} Prevention
- Strip 'Bearer ' prefix and surrounding whitespace before parsing.
- Ensure tokens are base64url-encoded, not URL-encoded, when passed to the verifier.
- Inspect the chained JWSInputException cause to pinpoint the structural failure.
When it happens
Trigger: Passing a token string that is not a valid compact JWS (not three base64url segments), is URL-encoded instead of base64url-encoded, has been truncated, or contains illegal characters. JWSInput's constructor performs structural + base64 + header-JSON parsing and throws on any failure.
Common situations: Double URL-encoding of the token in transit, a proxy stripping/replacing '+' or '_' characters, copy-paste truncation, or passing a raw SAML/opaque token to a JWT verifier.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Failed to build JWS
- Unable to decode token, payload is not a valid Base64URL val
- Unable to decode token, payload is not a valid JSON value.
- Failed to parse access token
- Failed to parse refresh token
AI-assisted analysis of keycloak/keycloak@66c7e15a37 (2026-08-14).
Data as JSON: /api/errors/b895a4f8a49b56ad.
Report an issue: GitHub.