JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted
Solution 1
I think EXPIRATION_IN_SECONDS
should be in milliseconds, because you're adding it to getTime(), which is in milliseconds. So it should be 120000 actually.
Solution 2
Got the same issue, in my case the token passing from angular has quotes in start/end. Resolved by removing them.
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
let token = localStorage.getItem('token');
if (token) {
token = token.replace(/^"(.*)"$/, '$1');
}
if (token) {
request = request.clone({ headers: request.headers.set('Authorization', 'Bearer ' + token) });
}
if (!request.headers.has('Content-Type')) {
request = request.clone({ headers: request.headers.set('Content-Type', 'application/json') });
}
request = request.clone({ headers: request.headers.set('Accept', 'application/json') });
console.log("............");
return next.handle(request);
}
Comments
-
Bilal Ennouali about 2 years
I am building a server side REST service application. I have a problem with the JWT authentication token. I can get the token easily after sign in (Here I use Postman).
But when I am trying to authenticate a request to access a protected REST controller using the same token, I get the following error:
io.jsonwebtoken.SignatureException: JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted. at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:354) at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:481) at io.jsonwebtoken.impl.DefaultJwtParser.parseClaimsJws(DefaultJwtParser.java:541) at com.configuration.jwt.JwtTokenUtil.extractClaims(JwtTokenUtil.java:104) at com.configuration.jwt.JwtTokenUtil.getUsernameFromToken(JwtTokenUtil.java:39) at com.configuration.jwt.JwtAuthenticationFilter.doFilterInternal(JwtAuthenticationFilter.java:44) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ...
it's like the application doesn't remember the token it generated. Here is the get request from Postman that generated this error:
I guess the source of the exception is from the method
extractClaims
of my classJwtTokenUtil
:@Component public final class JwtTokenUtil { public static final int EXPIRATION_IN_SECONDS = 120; private static final String JWT_SECRET = "Some$ecretKey"; private Clock clock = DefaultClock.INSTANCE; @Value("${jwt.secret}") private String secret; @Value("${jwt.expiration}") private Long expiration; private JwtTokenUtil() { // Hide default constructor } public String getUsernameFromToken(String token) { return extractClaims(token).getSubject(); } public Boolean validateToken(String token, UserDetails userDetails) { UserDetailsImp user = (UserDetailsImp) userDetails; final String username = getUsernameFromToken(token); return (username.equals(user.getUsername()) && !isTokenExpired(token)); } public Date getIssuedAtDateFromToken(String token) { return extractClaims(token).getIssuedAt(); } public String generateToken(UserDetails userDetails) { Map<String, Object> claims = new HashMap<String, Object>(); return doGenerateToken(claims, userDetails.getUsername()); } private String doGenerateToken(Map<String, Object> claims, String subject) { final Date createdDate = clock.now(); final Date expirationDate = calculateExpirationDate(createdDate); return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(createdDate) .setExpiration(expirationDate).signWith(SignatureAlgorithm.HS512, secret).compact(); } private Date calculateExpirationDate(Date createdDate) { return new Date(createdDate.getTime() + expiration * 1000); } public static String createToken(String username, Date issueDate) { String jwtToken = Jwts.builder().setSubject(username).setIssuedAt(issueDate) .setExpiration(new Date(issueDate.getTime() + EXPIRATION_IN_SECONDS)) .signWith(SignatureAlgorithm.HS512, JWT_SECRET).compact(); return jwtToken; } public static String getSubject(String token) { Claims claims = extractClaims(token); return claims.getSubject(); } public static String refreshToken(String token, long expirationInSeconds) { final Claims claims = extractClaims(token); Date now = new Date(); claims.setIssuedAt(now); claims.setExpiration(new Date(now.getTime() + EXPIRATION_IN_SECONDS)); return createTokenFromClaims(claims); } public static boolean isTokenExpired(String token) { final Claims claims = extractClaims(token); Date now = new Date(); return now.after(claims.getExpiration()); } private static String createTokenFromClaims(Claims claims) { return Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.HS512, JWT_SECRET).compact(); } private static Claims extractClaims(String token) { return Jwts.parser().setSigningKey(JWT_SECRET).parseClaimsJws(token).getBody(); } }
This is my
JwtAuthenticationFilter
class:public class JwtAuthenticationFilter extends OncePerRequestFilter { @Autowired private UserDetailsService userDetailsService; @Autowired private JwtTokenUtil jwtTokenUtil; @Override protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException { String header = req.getHeader("Authorization"); String username = null; String authToken = null; if (header != null && header.startsWith("Bearer ")) { authToken = header.replace("Bearer ", ""); try { username = jwtTokenUtil.getUsernameFromToken(authToken); } catch (IllegalArgumentException e) { logger.error("an error occured during getting username from token", e); } catch (ExpiredJwtException e) { logger.warn("the token is expired and not valid anymore", e); } } else { logger.warn("couldn't find bearer string, will ignore the header"); } if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) { UserDetails userDetails = userDetailsService.loadUserByUsername(username); if (jwtTokenUtil.validateToken(authToken, userDetails)) { String role = ""; role = userDetails.getAuthorities().size() > 1 ? "ROLE_ADMIN" : "ROLE_TOURIST"; UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( userDetails, null, Arrays.asList(new SimpleGrantedAuthority(role))); authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(req)); logger.info("authenticated user " + username + ", setting security context"); SecurityContextHolder.getContext().setAuthentication(authentication); } } chain.doFilter(req, res); } }
and I don't know if the sign in controller have anything to do with the issue, but here is the code for it anyway:
@PostMapping(value = "/signin") public ResponseEntity<?> signin(@Valid @RequestBody LoginForm loginForm) throws AuthenticationException { final Authentication authentication = authenticationManager.authenticate( new UsernamePasswordAuthenticationToken(loginForm.getUsername(), loginForm.getPassword())); SecurityContextHolder.getContext().setAuthentication(authentication); final UserDetails user = userService.loadUserByUsername(loginForm.getUsername()); final String token = jwtTokenUtil.generateToken(user); return ResponseEntity.ok(new JwtResponse(token, user.getUsername(), user.getAuthorities())); }
I hope somebody can help.
-
Paul Gobin over 3 yearsI was running into the same problem and this
-
-
Paul Gobin over 3 yearsI was facing the same issue. stackoverflow.com/questions/57297249/… Solved it for me.