CptDayDreamer
CptDayDreamer

Reputation: 1794

Spring Boot refresh JWT Token on every request as long it's valid

My idea or my wish was to refresh the JWTToken on every successful request. At the moment the user gets back to the login mask if his token is expired and that should stay that way.

But in my opinion and as I have seen it in some applications it is nice to get a fresh token or at least the full length of time back after a sucessful request. Like you have a expiration time of 10 minutes and you send a request with a remaining token time of 3 minutes which succeeds, then the token should be valid for the next 10 minutes again.

How to it the best way? Currently I'm using the standard Spring Security libraries to validate, create and so on. I literally followed this guide https://bezkoder.com/spring-boot-jwt-authentication/.

I thought I could refresh the token with literally the same method:

public String generateJwtToken(Authentication authentication) {

    UserDetailsImpl userPrincipal = (UserDetailsImpl) authentication.getPrincipal();

    return Jwts.builder().setSubject((userPrincipal.getUsername())).setIssuedAt(new Date())
            .setExpiration(new Date((new Date()).getTime() + jwtExpirationMs))
            .signWith(SignatureAlgorithm.HS512, jwtSecret).compact();
}

But to do so I need the authentication object which I can't create because I don't have a username and password given like here:

    Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(
            loginRequest.getUsername().toLowerCase(), loginRequest.getPassword()));

    SecurityContextHolder.getContext().setAuthentication(authentication);
    String jwt = jwtUtil.generateJwtToken(authentication);+

Is there something instead of new UsernamePasswordAuthenticationToken() that I could use for that?

Upvotes: 2

Views: 2230

Answers (1)

tibortru
tibortru

Reputation: 752

So on initial login you create and use

authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(
            loginRequest.getUsername().toLowerCase(), loginRequest.getPassword()));

but after that you use your jwt in header of each request and check it for validity. So you would have something like

if (!jwtProvider.isTokenExpired(jwt) && SecurityContextHolder.getContext().getAuthentication() == null) {
                UsernamePasswordAuthenticationToken usernameAndPasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(jwtProvider.extractUsername(jwt),
                        null, jwtProvider.extractUserAuthorities(jwt));
                usernameAndPasswordAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(usernameAndPasswordAuthenticationToken);
            }

as you can see you can create UsernamePasswordAuthenticationToken with just username and authorities(if needed), because you already validated user with jwt, no need for his password again.

I guess after this you can use username and whatever you need from previous token, extract it and put it in new token to be generated.

I also suggest that you refactor your generateJwtToken to use UserDetails as parameter or even just username, cause you don't need whole Authentication. You are definitely not using password in token generation and as I can see you are not using authorities either.

P.S. Thx for the question, I was wondering how to do auto refresh of token on each request :*

Upvotes: 3

Related Questions