Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Can't test generateToken() method for JWT token because of iat and exp date

I want to test my JwtService which is for generating and handling JWT Tokens. I am not even sure, if I have to test it because not all the methods are mine but I still would like to see if the token is generated correct. But if I want to test if the generated token is correct I have to compare it to another token. The only problem is the time difference, so iat (Issued At) and exp (Expiration Time/Date) are different. That’s why the test always fails. How can I test even though the iat and exp are different?

JwtService:

package de.gabriel.vertretungsplan.security.service;

import de.gabriel.vertretungsplan.models.UserDetailsImpl.UserDetailsImpl;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import org.springframework.stereotype.Service;

import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

@Service
public class JwtService {

    /*
    Generated with: https://www.allkeysgenerator.com/; 256-bit key
     */
    private static final String SECRET_KEY = "secret_key";

    public String extractUsername(String token) {
        return extractClaim(token, Claims::getSubject);
    }

    public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
        final Claims claims = extractAllClaims(token);
        return claimsResolver.apply(claims);
    }

    public String generateToken(UserDetailsImpl userDetails) {
        return generateToken(new HashMap<>(), userDetails);
    }

    public String generateToken(
            Map<String, Object> extraClaims,
            UserDetailsImpl userDetails
    ) {
        return Jwts.builder()
                .setClaims(extraClaims)
                .setSubject(userDetails.getUsername())
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + (1000 * 60 * 60 * 24 * 7))) // 7 days
                .signWith(getSigningKey(), SignatureAlgorithm.HS256)
                .compact();
    }

    public boolean isTokenValid(String token, UserDetailsImpl userDetails) {
        final String username = extractUsername(token);
        return username.equals(userDetails.getUsername()) && !isTokenExpired(token);
    }

    private boolean isTokenExpired(String token) {
        return extractExpiration(token).before(new Date());
    }

    private Date extractExpiration(String token) {
        return extractClaim(token, Claims::getExpiration);
    }

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

    private Key getSigningKey() {
        byte[] keyBytes = Decoders.BASE64.decode(SECRET_KEY);
        return Keys.hmacShaKeyFor(keyBytes);
    }

}

This is how I want to test it:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

@Test
public void generateToken_shouldGenerateToken() {
    Verwaltung verwaltung = new Verwaltung(
            "user",
            "user@gmail.com",
            "user",
            Rolle.getPrefixedRolle(Rolle.USER)
    );
    String generatedToken = jwtService.generateToken(new UserDetailsImpl(verwaltung));
    assertEquals(token, generatedToken);
}

The expected token was generated on jwt.io with the same secret key and everything as reference/ expected token. Does anyone have an idea how to test it even though there is a time difference?

>Solution :

You could take a different approach and verify the contents of the JWT instead of comparing it with a pre-generated token (which contains a timestamp (iat and exp fields), so it will always be different from a pre-generated token):

@Test
public void generateToken_shouldGenerateToken() {
    Verwaltung verwaltung = new Verwaltung(
            "user",
            "user@gmail.com",
            "user",
            Rolle.getPrefixedRolle(Rolle.USER)
    );
    String generatedToken = jwtService.generateToken(new UserDetailsImpl(verwaltung));

    // parse generated token
    Claims claims = Jwts.parser()
                        .setSigningKey(DatatypeConverter.parseBase64Binary(SECRET_KEY))
                        .parseClaimsJws(generatedToken)
                        .getBody();

    assertEquals(verwaltung.getUsername(), claims.getSubject());
    // check if the token is not expired
    assertFalse(claims.getExpiration().before(new Date()));
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading