When I create JWT token string and try to extract login (subject), getLogin() method returns null. getLogin() method just wraps Claims.getSubject().
JWTService.java
@Service
public class JWTService {
private static final SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
@Value("${jwt.token-validity}")
private Integer tokenValidity;
@Nullable
public String getLogin(@NotNull String token) {
return extractClaim(token, Claims::getSubject);
}
private Claims getClaims(@NotNull String token) {
return Jwts
.parserBuilder()
.setSigningKey(key)
.build()
.parseClaimsJws(token)
.getBody();
}
private <T> T extractClaim(@NotNull String token, @NotNull Function<Claims, T> claimsResolver) {
return claimsResolver.apply(getClaims(token));
}
public String generateToken(@NotNull String login) {
return generateToken(login, new HashMap<>());
}
public String generateToken(@NotNull String login, @NotNull HashMap<String, Object> extraClaims) {
return Jwts.builder()
.setSubject(login)
.setClaims(extraClaims)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + tokenValidity * 1000))
.signWith(key)
.compact();
}
}
JWTServiceTest.java
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@FieldDefaults(level = AccessLevel.PRIVATE)
public class JWTServiceTest {
@Autowired
JWTService jwtService;
@Test
public void whenGivenTestLoginAndJwtGenerated_ThenExtractTestUsername(){
String jwt = jwtService.generateToken("test");
assertEquals("test", jwtService.getLogin(jwt));
}
}
expected: <test> but was: <null>
Expected :test
Actual :null
I tried to search same topics here, but don't found a solution.
The issue is in the jwt token generation
return Jwts.builder()
.setSubject(login)
.setClaims(extraClaims)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + tokenValidity * 1000))
.signWith(key)
.compact();
If you look the the setSubject method you will find out that it's just a convenience method to set the sub claim if the Claims are not present. You are in fact filling a Claims object with the sub claim and then overriding it with your other extraClaims.
What I simply did was switch the order:
return Jwts.builder()
.setClaims(extraClaims)
.setSubject(login)
//etc