I have an SPA which communicates with an API using a long-lived self-contained JWT for auth.
The SPA is currently storing this JWT in Local Storage.
Apart from this being pretty bad from a security standpoint, the other major problem with is that I have way of revoking access to the API (which btw, needs to remain stateless). One a user has a token, they can use it indefinitely.
I'd like to start using refresh tokens. I know these are typically not recommended for SPAs, however after reading The Ultimate Guide to handling JWTs on frontend clients I believe there is a way to do this securely.
What I would like:
- When user logs in (password grant) the server responds with a short-life access_token ONLY, but sets a HttpOnly cookie with the refresh token.
- The client stores the access_token in memory, and uses it when making API requests.
- When the access_token is near expiry, I'd make a request to the auth server to refresh the token. Because a cookie was set by the auth server, it would be automatically included in the request. The server responds with an updated access_token which we store in memory.
- If the user navigates away from the SPA and returns later, we can simply make a request to the auth server to refresh the token, which gives us a brand new one (no need to store anything in local storage).
This would seem to be about the most secure option, minimising both XRSF and CSRF:
- If somebody manages to inject some code into the SPA and steals an access_token, it expires after 5 minutes anyway. The injected code never gets access to the refresh_token.
- You can't trick a user into making CSRF API requests because you don't have the access_token (the access token effectively serves as a CSRF token).
- If somebody did somehow manage to get access to the refresh_token, it can be revoked on the auth server.
If this method is as full proof as I think it is (prove me wrong, please!), why is it seldom mentioned online?
The IdentityServer4 docs don't seem to cover this. Can anybody suggest how it might be implemented? I hoped that there might be a property I could set on in the Client config along the lines of UseCookiesForRefresh, but no.