2
votes

I have a single-page web application that uses OAuth bearer tokens to authenticate users. We do not use cookies, and there is no support for sessions. It simply makes calls to an ASP.NET Web API to access protected resources with an access token. We also support refresh tokens to obtain a new access token.

How would I implement a sliding expiration? I only see three options:

  1. Issue a new access token on every request using the refresh token. This defeats the whole purpose of refresh tokens.

  2. Track when the last request was in the client app. Each request would see when the last one was, and if it was after a set period, log them out and bring up the login screen. If not and their access token has expired, issue a new one and let them continue. This seems kind of messy and insecure to me.

  3. Forget refresh tokens. Store access tokens in a database with the expiration date and update it on every request. I prefer to not do a DB operation on every request.

Is there another option or do one of these actually sound acceptable?

1

1 Answers

2
votes

You said there is no session support. But this is pretty much what sessions are for, and ASP.NET and IIS support them with quite a few options for how they are managed, with or without cookies and with or without a database if I recall right. If sessions are not available in your case...

There is also the option of using an encrypted token, which contains session identity and timeout info. Then the server merely needs to know the key for decrypting the token. The server decrypts the token on each request, updates the time and sends a new encrypted token back with the new response. You can send the token as a header, cookie, part of url, take your pick. But cookies and headers are designed for this use pattern and take less work in my experience.

A token that does not decrypt is treated as an unauthorized request. Timeout is handled as you normally would, e.g. using the refresh token to get a new authentication.

If you have a server farm, only the key for decryption has to be shared between the servers. No need for a session in a database or shared cache.

You can elaborate this to expire keys over time. Then servers only have to infrequently check with a directory service, shared cache, or database, message or queue to get the most recent keys. If you generate them properly and expire them faster than someone can brute force hack them, you win! (joke) Windows has apis to support you on the encryption and key management.

I did this for a project years ago with success. It is, in effect implementing sessions without server side state. And as with all session methods and all authentication methods it has vulnerabilities.

But without some special reason to the contrary, I would just use sessions for their intended purpose. If I want each browser tab to have separate authentication I would use header based session tokens. If I want browser tabs in a browser session to share authentication I would use session cookies.

Or I would use your option three, maybe with a shared cache instead of a database, depending on performance requirements and infrastructure. I suspect that IIS+ASP.Net may even do that for you, but I have been away from them too long to know.