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.
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