JwtParser.parseClaimsJws doesn't consider token just created by JwtBuilder.compact to be valid

971 views Asked by At

I'm trying to implement JWT enabled authentication in my Spring Boot application. I'm using the io.jsonwebtoken.jjwt library. But unfortunately I'm facing issues with parsing JWT tokens my application has created. JwtParser.parseClaimsJws doesn't consider my token just created by JwtBuilder.compact to be valid. The exact same javax.crypto.SecretKey is used for signing and checking. The token is definitely not expired. When JwtParser.parseClaimsJws is called the following exception is thrown: io.jsonwebtoken.security.SignatureException: JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.

Here is a truncated version of the class I'm writing to manage JWTs in my Spring Boot project:

import java.security.SecureRandom;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import org.springframework.stereotype.Component;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;

@Component
public class JwtUtils {
  private SecretKey jwtSigningKey;

  public JwtUtils() throws Exception {
    KeyGenerator keyGenerator = KeyGenerator.getInstance("HmacSHA256");
    keyGenerator.init(SecureRandom.getInstanceStrong());
    jwtSigningKey = keyGenerator.generateKey();
  }

  private Claims extractAllClaims(String token) {
    return Jwts
      .parserBuilder()
      .setSigningKey(jwtSigningKey)
      .build()
      .parseClaimsJws(token)
      .getBody();
  }

  public String generateToken(UserDetails userDetails) {
    Map<String, Object> claims = new HashMap<>();
    return createToken(claims, userDetails);
  }

  public String generateToken(
    UserDetails userDetails,
    Map<String, Object> claims
  ) {
    return createToken(claims, userDetails);
  }

  private String createToken(
    Map<String, Object> claims,
    UserDetails userDetails
  ) {
    return Jwts
      .builder()
      .setClaims(claims)
      .setSubject(userDetails.getUsername())
      .claim("authorities", userDetails.getAuthorities())
      .setIssuedAt(new Date(System.currentTimeMillis()))
      .setExpiration(
        new Date(System.currentTimeMillis() + TimeUnit.HOURS.toMillis(24))
      )
      .signWith(jwtSigningKey)
      .compact();
  }
}

When createToken is executed, a token is successfully generated and returned to an Angular frontend application. After that, when the token is successfully passed back to my code and passed into the extractAllClaims method successfully a few seconds later, the SignatureException is thrown on line 24 in the call to parseClaimsJws.

The constructor of this class, creating the secret key, also ran without problems. Because of Spring Boot's @Component annotation, I know this class is a singleton in my running application and the key stays the same. I have confirmed this through logging the hash code of the key over several independent requests to my application.

I'm using the following versions of the libraries:

io.jsonwebtoken.jjwt-api: 0.11.5
io.jsonwebtoken.jjwt-impl: 0.11.5
io.jsonwebtoken.jjwt-jackson: 0.11.5
spring-boot: 3.1.0

Any help or insight is much appreciated!

Thank you in advance and best regards,
Joshua Schroijen

0

There are 0 answers