javaspringspring-securityjwt

getSubject() method rerturn null when trying to extract from JWT claims


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.


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