Authentication in a React SPA with JWT

Hello. I’ve been building a single page application and when it came to implementing authentication I ended with a deadlock.

I am not sure about the workflow of implementing a secure authentication with JWT in a React single page app.I want to do the JWT authentication by myself, without any services, and I want to focus specifically on JWT authentication and not session based authentication, because I want to learn something new.

The problems I ran into so far are regarding token storage and security. In a React app it is tempting to store the user id (and other data from the JWT payload) in the app component’s state (the highest component in the hierarchy). But when it comes to silent refreshing it obviously should re-render as the state is being changed, which is bad UX. The other options are:

  • LocalStorage - here many say it is not secure to do so, but I think it’s ok because access token are short lived.Also it requires additional work on the client to store, then get the token on every API request

  • SessionStorage - because it is not persisted

  • Cookie (JS-accessible for access token)

Here is a more systematic explanation of my understanding of the authentication flow:

  • When client is signing up or logging in, the API is responding with an access token(which is short lived and should be stored in memory) and with a refresh token (long lived, although not too long as it is persisted and stored in plain sight; sent via a Set-Cookie with HTTP Only and Secure flags).

  • An API request would require sending the access token which is verified by the API before sending a response, or sending an Unauthorized response status code if the token isn’t valid

  • Logging out involves deleting everything user related and all the authentication tokens from the client’s memory.Regarding the refresh token what I did was to send a Set Cookie response from /logout which sets the refresh token from the HTTP Only cookie to have an expired date and, thus, automatically erasing it’s content .Doing some research I found out that getting rid of the refresh token can be done by blacklisting it, using a key-value database like Redis.

  • Silent refresh may or may not be required, because the access token is verified on the API on every request on a protected route.But here arises the question: then why use silent refresh at all, I mean why is it a thing ?

The tools I use: Create React App with requests proxied to my express.js API (I am free to change it’s code), React-Router, Mongodb (and mongoose).

Is my understanding of the authentication flow correct ? Do I need silent refresh ? Is there a better way ? Also, should I send the access token in Bearer(or Basic) Authorization HTTP header or in the request body ? Or is it a matter of preference ?