javaspring-bootspring-securityjwt

Validate JWT - Java17 Spring Security JWT:0.12.6


I'm doing a personal project, and I'm trying so setup an API with several JWT protected endpoints. I had no clue about how spring security works so I've decided to watch a tutorial. I've ended by having a login endpoint which works. Nevertheless, I'm trying to access JWT protected endpoints with a JWT and it return a 401 http response and it throws this error :

Cannot verify JWS signature: unable to locate signature verification key for JWS with header: {alg=HS512}

And here is my class :

@Component
public class JWTGenerator {

    @Value("${jwt.secret}")
    private String jwtSecret;

    public String generateToken(Authentication authentication) {
        String email = authentication.getName();
        Date currentDate = new Date();
        Date expireDate = new Date(currentDate.getTime() + SecurityConstants.JWT_EXPIRATION);

        SecretKey key = getSecretKey();

        return Jwts.builder()
                .subject(email)
                .issuedAt(new Date())
                .expiration(expireDate)
                .signWith(key)
                .compact();
    }

    private SecretKey getSecretKey() {
        byte[] keyBytes = Decoders.BASE64.decode(jwtSecret);
        return Keys.hmacShaKeyFor(keyBytes);
    }

    public String getEmailFromJWT(String token) {
        Claims claims = Jwts.parser()
                .verifyWith(getSecretKey())
                .build()
                .parseSignedClaims(token)
                .getPayload();
        return claims.getSubject();
    }

    public boolean validateToken(String token) {
        try {
            SecretKey key = getSecretKey();
            Jwts.parser().decryptWith(key).build().parse(token);
            return true;
        } catch(SecurityException | MalformedJwtException e) {
            throw new AuthenticationCredentialsNotFoundException("JWT was expired or incorrect");
        } catch (ExpiredJwtException e) {
            throw new AuthenticationCredentialsNotFoundException("Expired JWT token.");
        } catch (UnsupportedJwtException e) {
            throw new AuthenticationCredentialsNotFoundException("Unsupported JWT token.");
        } catch (IllegalArgumentException e) {
            throw new AuthenticationCredentialsNotFoundException("JWT token compact of handler are invalid.");
        }
    }
}

The error occurs while trying to parse the token in the validateToken method. The sign / decode / decrypt / parse parts are totally unclear to me, I understand why there is an error but i have no idea how to fix it.

Excuse my English, it's not my first language.

I've tried several topics but they mostly using deprecated version of jsonwebtoken. I would like someone to help me to understand how the validate part work.


Solution

  • the problem is that you using the method decryptWith. This method is only supposed to be used to decrypt JWE, in case you created one with encryptWith.

    Since in your program you only want to use JWTs (not encrypted) you have to stick to signWith and veryfyWith

    Therefore change your validate method to the following:

     public boolean validateToken(String token) {
            try {
                SecretKey key = getSecretKey();
                Jwts.parser().verifyWith(key).build().parseSignedClaims(token);
                return true;
            } catch(SecurityException | MalformedJwtException e) {
                throw new AuthenticationCredentialsNotFoundException("JWT was expired or incorrect");
            } catch (ExpiredJwtException e) {
                throw new AuthenticationCredentialsNotFoundException("Expired JWT token.");
            } catch (UnsupportedJwtException e) {
                throw new AuthenticationCredentialsNotFoundException("Unsupported JWT token.");
            } catch (IllegalArgumentException e) {
                throw new AuthenticationCredentialsNotFoundException("JWT token compact of handler are invalid.");
            }
        }
    

    For more info check out documentation