{"record":{"id":"78c891692d945403","repo":"spring-projects/spring-security","slug":"an-error-occurred-while-attempting-to-decode-the-j-78c891","errorCode":null,"errorMessage":"An error occurred while attempting to decode the Jwt: Malformed token","messagePattern":"An error occurred while attempting to decode the Jwt: Malformed token","errorType":"exception","errorClass":"BadJwtException","httpStatus":null,"severity":"error","filePath":"oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoder.java","lineNumber":156,"sourceCode":"\t@Override\n\tpublic Jwt decode(String token) throws JwtException {\n\t\tJWT jwt = parse(token);\n\t\tif (jwt instanceof PlainJWT) {\n\t\t\tthis.logger.trace(\"Failed to decode unsigned token\");\n\t\t\tthrow new BadJwtException(\"Unsupported algorithm of \" + jwt.getHeader().getAlgorithm());\n\t\t}\n\t\tJwt createdJwt = createJwt(token, jwt);\n\t\treturn validateJwt(createdJwt);\n\t}\n\n\tprivate JWT parse(String token) {\n\t\ttry {\n\t\t\treturn JWTParser.parse(token);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthis.logger.trace(\"Failed to parse token\", ex);\n\t\t\tif (ex instanceof ParseException) {\n\t\t\t\tthrow new BadJwtException(String.format(DECODING_ERROR_MESSAGE_TEMPLATE, \"Malformed token\"), ex);\n\t\t\t}\n\t\t\tthrow new BadJwtException(String.format(DECODING_ERROR_MESSAGE_TEMPLATE, ex.getMessage()), ex);\n\t\t}\n\t}\n\n\tprivate Jwt createJwt(String token, JWT parsedJwt) {\n\t\ttry {\n\t\t\t// Verify the signature\n\t\t\tJWTClaimsSet jwtClaimsSet = this.jwtProcessor.process(parsedJwt, null);\n\t\t\tMap<String, Object> headers = new LinkedHashMap<>(parsedJwt.getHeader().toJSONObject());\n\t\t\tMap<String, Object> claims = this.claimSetConverter.convert(jwtClaimsSet.getClaims());\n\t\t\t// @formatter:off\n\t\t\treturn Jwt.withTokenValue(token)\n\t\t\t\t\t.headers((h) -> h.putAll(headers))\n\t\t\t\t\t.claims((c) -> c.putAll(claims))\n\t\t\t\t\t.build();\n\t\t\t// @formatter:on\n\t\t}","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoder.java#L138-L174","documentation":"NimbusJwtDecoder.parse wraps JWTParser.parse failures: when Nimbus throws ParseException the token is structurally invalid, and the decoder throws BadJwtException 'An error occurred while attempting to decode the Jwt: Malformed token'.","triggerScenarios":"decode() → parse(token) with a string that is not parseable as a JWT: missing segments, invalid Base64URL, oversized/malformed JSON header or payload, wrong compact serialization.","commonSituations":"Sending an opaque token or OAuth2 access token that is not a JWT to a JWT decoder; truncating the Authorization header value; whitespace/newlines inside the token; double-URL-encoding the bearer token in transit; proxy mangling the header.","solutions":["Confirm the token is actually a JWT (three dot-separated Base64URL segments) — log/inspect the raw Authorization header server-side.","Check for transport corruption: strip whitespace, avoid re-encoding, ensure the full token is forwarded (long tokens can be cut by proxies/gateways).","If the token is opaque, use an introspection decoder (NimbusOpaqueTokenIntrospector / OpaqueTokenIntrospector) instead of NimbusJwtDecoder.","Catch BadJwtException and return 401 so the client re-authenticates with a fresh token."],"exampleFix":"// before\nString token = request.getHeader(\"Authorization\").replace(\"Bearer \", \"\").trim();\n// after\nString auth = request.getHeader(\"Authorization\");\nif (auth != null && auth.startsWith(\"Bearer \")) {\n    String token = auth.substring(7).trim(); // validate non-empty, 3 segments\n}","handlingStrategy":"try-catch","validationCode":"String token = authorizationHeader != null && authorizationHeader.startsWith(\"Bearer \")\n    ? authorizationHeader.substring(7).trim() : null;\nboolean plausible = token != null && token.chars().filter(c -> c == '.').count() == 2\n    && !token.contains(\" \") && !token.contains(\"\\n\");","typeGuard":"boolean looksLikeJwt(String token) {\n    return token != null && token.split(\"\\\\.\", -1).length == 3\n        && token.matches(\"[A-Za-z0-9_-]+\\\\.[A-Za-z0-9_-]+\\\\.[A-Za-z0-9_-]*\");\n}","tryCatchPattern":"try { return jwtDecoder.decode(token); }\ncatch (BadJwtException e) {\n    // malformed token: respond 401 WWW-Authenticate: Bearer error=\"invalid_token\"\n}","preventionTips":["Distinguish JWTs from opaque tokens before choosing decoder vs introspector","Strip 'Bearer ' exactly once and trim; never re-encode the token in transit","Check proxies/gateways for header size limits that truncate long tokens"],"tags":["jwt","malformed-token","parsing","base64"],"backgroundTag":"invalid-token-format","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}