I implemented JWT authentication for my Spring boot app. Overally, it works like this:
The question is, how should we implement logout ?
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
class TokenAuthenticationService {
static final long EXPIRATIONTIME = 864_000_000; // 10 days
static final String SECRET = "ThisIsASecret";
static final String TOKEN_PREFIX = "Bearer";
static final String HEADER_STRING = "Authorization";
static void addAuthentication(HttpServletResponse res, String username) {
String JWT = Jwts
.builder()
.setSubject(username)
.setExpiration(
new Date(System.currentTimeMillis() + EXPIRATIONTIME))
.signWith(SignatureAlgorithm.HS512, SECRET).compact();
res.addHeader(HEADER_STRING, TOKEN_PREFIX + " " + JWT);
}
static Authentication getAuthentication(HttpServletRequest request, UserDetailsService customUserDetailsService) {
String token = request.getHeader(HEADER_STRING);
if (token != null) {
// parse the token.
Claims claims = Jwts.parser().setSigningKey(SECRET)
.parseClaimsJws(token.replace(TOKEN_PREFIX, "")).getBody();
String userName = claims.getSubject();
Date expirationTime = claims.getExpiration();
if (expirationTime.compareTo(new Date()) < 0) {
return null;
}
UserDetails user = customUserDetailsService.loadUserByUsername(userName);
return user != null ? new UsernamePasswordAuthenticationToken(user.getUsername(),
user.getPassword(), user.getAuthorities()) : null;
}
return null;
}
}
addAuthentication
is used by the JWTLoginFilter
class to send the authentication code when logging in, 'getAuthenticationis used by the
JWTAuthenticationFilter` that filter all requests to the end points.
What is the best practice here ?
Logout user when token is expired and Route changes. We need to do 2 steps: – Create a component with react-router subscribed to check JWT Token expiry. – Render it in the App component.
They are defined by the open standard (RFC 7519) and they're composed of three segments: a header, a payload, and a crypto segment in general. JWT's are signed when generated, and the same signed JWT is validated upon receipt to make sure that it hasn't been modified in transit.
I don't think there is a best practice here. I guess it depends on the application you're building and it's requirements.
The benefit of JWT is that they're stateless. You don't need to query the database to validate the token. This is good when you wish to reduce the load on your database but bad when you want to invalidate an existing non-expired token.
Possible solutions:
I don't know what's best practice, but in a system whose internals I have seen, there is a central authentication manager which knows all the currently valid authentication tokens, so logging out would simply consist of removing the token from the collection of valid tokens.
So, next time the authentication manager is asked whether the token is valid, it would respond with a "no".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With