Search code examples
asp.net-coreoauthjwtsingle-page-applicationidentityserver4

SPA with refresh tokens stored in cookie - how to configure with IdentityServer4?


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.


Solution

  • You can use ReferenceToken type instead of Jwt Token to revoke the tokens whenever the user's session is ended (or logout). Reference Token

    You need to change the AccessTokenType in Client configuration

    new Client
        {
            ClientName = "OAuth Test",
            ClientId = "TestClientId",
            AllowedGrantTypes = GrantTypes.Hybrid,
            AccessTokenLifetime = 300,
            AllowOfflineAccess = true,
            AccessTokenType = AccessTokenType.Reference,
            ......
        }
    

    When the user logs out, you can use the following lines to revoke all tokens generated within that session.

    await _interaction.RevokeTokensForCurrentSessionAsync();