3

I have implemented access tokens and refresh tokens, without an auth server (my API server also does authentication).

  • Access tokens: stored in the client (localstorage). Expire in 20 minutes.
  • Refresh tokens: stored in the client (localstorage), and in the server (database). Expire in 3 months.
  • The refresh "window" is a week, so tokens can be refreshed without re-login within that week.
  • After 3 months the refresh token expires, so the user must re-login.

When the user logs out, I delete the access and refresh tokens from localstorage. But I should also delete the refresh token on the server, so I must make a /logout request to the server.

Should that logout request be authenticated?

Let's say yes. The problem is that if the user is not logged in (i.e. the access token has expired), and the refresh window has passed (let's say, a week), then an automatic refresh can't be performed, so he would be forced to log in, so that he can log out. Weird!

The alternative is for that endpoint to expect an access and refresh token pair, BUT 1) to allow the access token to be expired, and 2) to ensure the access token is nonthelesss valid, and that the refresh token is both valid and current. And in that case, to delete the refresh token from the database.

What is the typical way to handle this? Are there pros/cons I've not considered?

3

There is no need to protect logout resource.

If a session is present with the logout request; it gets invalidated. Otherwise it gets directly redirected to logout page.

  • 1
    A pitfall to this approach, is someone who possesses a stolen expired access token can DoS a user (log him out all the time). – lonix Jul 11 at 15:29
  • I can't think of any approach which can bypass this potential threat unless you customize logout endpoint. I will suggest: Keep logout authenticated. If expired access token is used, send 302 Forbidden instead of 401. otherwise invalidate the tokens. – Shobhit Jul 12 at 10:52
  • 403 forbidden and stop the refresh token endpoint to invoke. – Shobhit Jul 12 at 12:32
3

I think there is a difference between a user requested logout vs. token expiry.

The short answer is you definitely must authenticate the /logout endpoint, to prevent an attacker from forcefully logging out all your users. If you do not validate this endpoint, anyone can logout any user. Hence this endpoint must be protected.

For the situation where both the access and refresh token are expired -- the user tries to go to a page, e.g. /account and your backend detects that the access token is expired, it will then re-direct to refresh endpoint, e.g. /refresh.

/refresh detects that the refresh token is also expired, and now redirects the user to the /login page. Once the user logs in, they'll get new refresh and access tokens, and all is well with the world again.

If you're keeping a list of all active refresh tokens, then you should update the list during the 2nd user log in, and not require a separate /logout to be called. However, these token list are typically only validated post token validation, which it won't be if the token is expired.

  • Thanks! But the problem with this approach is this workflow: logout --> refresh (FAIL) --> login --> logout. – lonix Jul 12 at 9:45
  • Also, the way it works in my answer I think is slightly more comprehensive as the endpoint expects the access token to be valid, but it may be expired (i.e. the endpoint is not protected, but does expect the credentials). Then the refresh token is deleted from the db. Drawback to no protection is an attacker could submit a forged/stolen access token and DoS the user (log him out), but in that case, I believe it would be best to revoke the grant anyway. What do you think? – lonix Jul 12 at 9:46
  • 1
    I think if the user wants to logout, but both their tokens are expired. The user will go through the same flow (redirected to /refresh and then to /login -- and the user will stop at that point -- thinking that they've logged out. On your backend, since both tokens are expired, you can also determine that they're logged out. You might also have a scheduled script to delete all expired refresh tokens from your system as well. – keithRozario Jul 13 at 2:04
0

What I wanted to know is why protect or not protect the logout endpoint?

I decided not to protect the endpoint, but to check: if the access token is valid (even if expired) then revoke the refresh token.

WHY:

  • access=current & refresh=current: this is a normal authenticated request, so revoke
  • access=expired & refresh=current: it's possible to perform a token refresh, so just revoke
  • access=expired & refresh=expired: user would need to login anyway, so revoke

  • access=invalid and/or refresh=invalid: tokens were hacked/stolen, so must revoke

So all paths I can see lead to revocation. As long as the access token is valid, even if it's expired, just revoke the corresponding refresh token.


The alternative to all this is to protect the endpoint the usual way. But that leads to the logout --> refresh (fail) --> login --> logout loop. My approach avoids that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.