Background
I am working on a web application using Spring Security and am trying to use JSON Web Tokens for authentication for the first time. The app should restrict access to certain URIs based on user roles. It should provide password change option and enable Admin users to change other users' roles.
In a tutorial I've followed, on each HTTP request to the server the database is hit by CustomUserDetailsService to load the current details of the user which seems heavy on performance:
public class JwtAuthenticationFilter extends OncePerRequestFilter {
//...
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
try {
String jwt = getJwtFromRequest(request);
if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) {
Long userId = tokenProvider.getUserIdFromJWT(jwt);
UserDetails userDetails = customUserDetailsService.loadUserById(userId);
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
} catch (Exception ex) {
logger.error("Could not set user authentication in security context", ex);
}
filterChain.doFilter(request, response);
}
//...
}
The author of the tutorial suggests another option:
Note that you could also encode the user's username and role inside JWT claims and create the UserDetails object by parsing those claims from the JWT.
However, this comes at the cost of making it difficult to change user's role as we have no way of discarding issued tokens, without keeping track of them.
Possible solution
I've researched the topic of JWT and came up with the following solution:
Let's store username and role inside JWT claims and set a short token expiration time (using exp claim) - after this period, e.g. 15 minutes, we hit the database to check user's details. If the role has changed, we generate the new token with the new role in payload. If the password has been changed, we require the user to re-authenticate, before generating the new token.
An obvious downside of this solution is that any change in user access rights is effective after the period of expiration time.
Question
Are there any other ways of tackling the issue of handling user details change while using JWTs?