{"record":{"id":"b895a4f8a49b56ad","repo":"keycloak/keycloak","slug":"failed-to-parse-jwt","errorCode":null,"errorMessage":"Failed to parse JWT","messagePattern":"Failed to parse JWT","errorType":"exception","errorClass":"VerificationException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/keycloak/TokenVerifier.java","lineNumber":408,"sourceCode":"     * Add check for verifying that token issuedFor (azp claim) is the expected value\n     *\n     * @param expectedIssuedFor issuedFor, which needs to be in the target token. Can't be null\n     * @return This token verifier\n     */\n    public TokenVerifier<T> issuedFor(String expectedIssuedFor) {\n        return this.replaceCheck(IssuedForCheck.class, true, new IssuedForCheck(expectedIssuedFor));\n    }\n\n    public TokenVerifier<T> parse() throws VerificationException {\n        if (jws == null) {\n            if (tokenString == null) {\n                throw new VerificationException(\"Token not set\");\n            }\n\n            try {\n                jws = new JWSInput(tokenString);\n            } catch (JWSInputException e) {\n                throw new VerificationException(\"Failed to parse JWT\", e);\n            }\n\n\n            try {\n                token = jws.readJsonContent(clazz);\n            } catch (JWSInputException e) {\n                throw new VerificationException(\"Failed to read access token from JWT\", e);\n            }\n        }\n        return this;\n    }\n\n    public T getToken() throws VerificationException {\n        if (token == null) {\n            parse();\n        }\n        return token;\n    }","sourceCodeStart":390,"sourceCodeEnd":426,"githubUrl":"https://github.com/keycloak/keycloak/blob/66c7e15a3788de7764f07dd2558275a02770e16d/core/src/main/java/org/keycloak/TokenVerifier.java#L390-L426","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: header includes 'Bearer ' prefix or is URL-encoded\nTokenVerifier.create(rawHeader, AccessToken.class).verify();\n\n// after: normalize the token string first\nString token = rawHeader;\nif (token.startsWith(\"Bearer \")) token = token.substring(7);\ntoken = URLDecoder.decode(token, StandardCharsets.UTF_8);\nTokenVerifier.create(token, AccessToken.class).verify();","handlingStrategy":"validation","validationCode":"// Normalize the token string before parsing\nstatic String normalize(String raw) {\n  if (raw == null) return null;\n  if (raw.startsWith(\"Bearer \")) raw = raw.substring(7);\n  return raw.trim();\n}\nString token = normalize(header);\nif (token == null || token.split(\"\\\\.\").length != 3) {\n  // not a compact JWS — reject before parsing\n}\nTokenVerifier.create(token, AccessToken.class).parse();","typeGuard":"static boolean isCompactJws(String s) {\n  return s != null && s.split(\"\\\\.\").length == 3\n      && s.chars().allMatch(c -> isBase64UrlChar((char) c) || c == '.');\n}","tryCatchPattern":"try {\n  TokenVerifier.create(token, AccessToken.class).parse();\n} catch (VerificationException e) {\n  if (e.getMessage().equals(\"Failed to parse JWT\")) {\n    // inspect e.getCause() (JWSInputException); normalize encoding/structure and retry\n  } else throw e;\n}","preventionTips":["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."],"tags":["jwt","jws","parsing","verification"],"backgroundTag":null,"analyzedSha":"66c7e15a3788de7764f07dd2558275a02770e16d","analyzedAt":"2026-08-14T01:36:42.651Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}