1

The issue I have is after the user is authenticated meaning user has signed in, I understand from the client side to logout a user, I delete the token from the local storage but the issue I have is how do I invalidate the token or logout from the serverside.

My intial approach was to make the logout API permit all in my SecurityFilterChain but when I try to grab the authenticated user from SecurityContextHolder after the user had signed in I was getting anonymousUser.

My second/current approach is I instead authorized LOGOUT API which means to access the API, a token has to passed in the header. Then I can then set SecurityContextHolder.getContext().setAuthentication(authentication == false); and also clearContext(). With this approach I am able to get the logged in user but my questions are:

  1. Is this the right logic to implement a log out?
  2. I understand a token cannot be invalidated because it is STATELESS. But is there a way to get around this? Because even after setting Authentication to false in SecurityContextHolder and clearing security context SecurityContextHolder.clearContext(); when I try accessing Authenticated API i.e CRUD operations, I am still able to use the token.

Here is my login and logout methods in my RestController Class

logout

@PostMapping(path = "/logout", headers = "Authorization")
@ResponseStatus(OK)
public ResponseEntity<?> logout() {
        LOGGER.info("Trying to Logout ");

        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        String username = authentication.getName();
        LOGGER.info("Username {} ", username);
        authentication.setAuthenticated(false);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        SecurityContextHolder.clearContext();

        return ResponseEntity.ok().body("Successfully logged out");
    }

login

@PostMapping(path = "/login", consumes = "application/json", produces = "application/json")
@ResponseStatus(OK)
public ResponseEntity<?> login(@Valid @RequestBody UserDTO userDTO) {

        Authentication authentication;
        LOGGER.info("Authenticating {}", userDTO.getUsername());

        var authenticationToken = confirmUser(userDTO); // returns a UsernamePasswordAuthenticationToken
        try {
            authentication = authenticationManager.authenticate(authenticationToken); // Authenticate user password token
            SecurityContextHolder.getContext().setAuthentication(authentication); // Set the security context to the logged user
        } catch (AuthenticationException e) {
            LOGGER.error("Stack trace {}", e.getMessage());
            SecurityContextHolder.getContext().setAuthentication(null);
            throw new InvalidPasswordException("Wrong username or password");
        }

        LOGGER.info("{} has signed in", userDTO.getUsername());
        return ResponseEntity.ok()
                .header( AUTHORIZATION, tokenService.generateToken(authentication) )
                .build();
    }

1 Answer 1

1

I might recommend a different approach, but let's start with your question.

Expiring Access Tokens

To expire a resource server token, you will need to add some kind of state.

This usually comes in the form of some kind of list of valid tokens. If the token isn't in the list, then the token is not valid.

A common way to achieve this is to rely on the authorization server. Many authorization servers ship with an endpoint that you can hit to see if a token is still valid.

Modeling Things Differently

That said, it might be worth considering if you should be thinking about the access token differently. The access token does not represent a user's authenticated session. It represents the user granting access to the client to operate on the user's behalf.

So after the user logs out, it still makes quite a bit of sense for the client to have a valid access token so that the user doesn't have to reauthorize the client every time they log in.

Sign up to request clarification or add additional context in comments.

1 Comment

Oh I see I see. The thing is I am trying to implement my own authorization server but I got a hint from your approach. I'll instead shorten the time for the token for better security since I am making my application STATELESS

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.