Authentication in SPA (ReactJs, VueJs) “Where should the token be stored, are there security related issues?

Tram Ho


Cookie, session, token, JWT where should Cookie, session, token, JWT be stored, what security issues should you care about? In this article, I will share what I know about it.

I will focus on the important concepts that need to be remembered when handling user authentication in the most basic model, Client – Server :


Prerequisites to improve Security

HttpS encrypted protocol

  • authentication uses HTTP headers and exchanges sensitive data ( passwords, access toke, … ), so they should be encrypted communication protocols, otherwise information will be stolen, or changed before it arrives. be with server / client .

Do not use URL query params to exchange sensitive data

  • URL query params can create server, browser, browser history logs, hackers can take that data to find system vulnerabilities.
  • URL containing authentication tokens will be copied and used by everyone, causing unintended hijacking .
  • This can also cause the URL be too long, exceeding the limits of the browser and servers .

Avoid brute force attacks

  • Hackers will try to find a password, token, username by trying all possible passwords, tokens, usernames .
  • Adding the function to limit the number of attempts on the backend server will help minimize this attack.
  • Ban users who often create too many server errors.
  • Do not disclose information about the technology used in the application, for example, you should delete X-Powered-By =))

Update dependencies regularly.

  • If you do not use 1 PaaS in your application, or keep your server always using the latest version of dependencies possible.


There are 2 main mechanisms for enforcing 1 client authentication in the REST API :

  • Bearer Token
  • Authentication cookie

Bearer Token

What is a Bearer token ?

Bearer token is the value passed into the Authentication header of an HTTP Request . It is not automatically saved, does not expire and is not attached to the domain . It is only 1 value =))


Authorization: Bearer bearer_token_value

For a stateless application, we often use JWT for token creation. In simple terms, JWT consists of 3 parts:

  • Header
  • Payload and expiration time (optional)
  • Signature

JWT is a secure password, in the process of exchanging information, making authentication becomes stateless . Signature will authenticate the payload without being modified using symmetric or asymmetric (RSA) algorithms. Header contains the public key information to verify the Signature . The client application , the first time it requests on the server, will retrieve a JWT token through the username and password login. Then, through Javascript to attach the JWT token inside each HTTP header . The server will authenticate the signature corresponding to the payload , if they overlap, we can trust the contents of the Payload .

Cases should use Bearer Token

  • You want to protect traffic between a browser and backend .
  • Protects traffic between a mobile application , desktop application and backend .
  • Protects traffic between 2 backend servers ( M2M ), controls different components of the server.

Where should the JWT token be stored?

We can store JWT on the clients side ( memory, local / session cookie ,, local storage, … ). But JWT not recommended to store in the browser local storage by:

  • JWT token is still saved after the user shuts down the browser so the session can still be restored until the JWT token expires.
  • The site's local storage can be accessed from Javascript , so the data is no longer protected.
  • It cannot be used for web workers .

In my opinion, saving JWT in session cookie is probably the best solution.

Get more information about saving tokens.

Types of attacks should be avoided

Cross-site Scripting (XSS) attack is the most common form of attack when using Javascript to solve security issues. Hackers will take advantage of user input to insert malicious javascript code to steal victim's JWT token , then use it to impersonate the user.

We can minimize the possibility of XSS by controlling user input.

Cookie are a name-value pair, stored on a web browser and they have an expiration time, which is immediately associated with a domain . Cookie are generated by the client browser using Javascript .

or from the Server clearance HTTP Response header :

The web browser automatically sends cookie with each request to the cookie domain .

Typically, Cookie are used to store a Session ID . Session ID is managed by the server. Here, I am referring to a stateful app where the server needs to manage the state on the server while the JWT token is stateless . There are 2 types of Cookie :

  • Session cookies : This cookie is deleted when the user shuts down the application so it does not need to define an expiration time. However, the web browser can use the session to recover, which creates permanent cookies if the browser never closes. Session timeout must be managed by the server side.
  • Permanent cookies : Instead of expiring when the client closes the browser, permanent cookies expire at a predefined time ( Expires ) or after a period of time ( Max-Age ).

Server Cookies can be configured with the following options:

  • HttpOnly cookies: This makes the javascript browser unable to read this Cookie
  • Secure cookie: The browser will send a cookie in every HTTP request only if the request is sent via secure protocol like httpS
  • SameSite cookie: The server will require that the cookie not be sent through cross-site request forgery to avoid CSRF attack. SameSite cookies are still in beta and have unsupported browsers.

The case should use

  • You want to protect traffic between a browser and backend .
  • Cookies are not available and are difficult to deploy on non- browser platforms such as mobile applications .

Where should cookies be stored?

Cookies are automatically saved on the web browser with the expiration time and a specified domain name.

Types of attacks should be avoided

  • Cross-Site Scripting (XSS) if Cookies are not created with the HttpOnly option: a hacker may inject Javascript code to steal the victim's authentication cookie . To minimize XSS , the HttpOnly option should be set on cookies.
  • Cross-Site Request Frogery (CSRF) is a common attack when using Authentication cookies . To minimize CSRF , the SameSite option should be set on cookies. However, there are browsers that still do not support this option, so there are a few other ways to restrict:
    • Reduce each session's timeout time to less than 10 minutes or less.
    • Request a user credentials for each user behavior (for example, Require the user to enter the password into the form when the user wants to change email).
    • Send the cookie twice: The first time the user visits the site, it will generate a temporary value and set it to be a cookie (there is no HttpOnly option so that value can be used by Javascript) on the client's side to perform the cookie. an HttpOnly authentication cookie . The application will ask for that temporary cookie value on each form submission as the value of the form and also the cookie value. When a POST request is sent to the site, that request is only accepted if the values ​​in the form and in the cookie are the same.

Combining both mechanisms

After a while of rambling around, grabbing our Server API is in need of an authentication mechanism that:

  • Support browser and 3rd party components can be called ( M2M call ).
  • Resistant to XSS and CSRF
  • Stateless if possible.

What if JWT token is put into Cookie to combine the advantages of both?

The Server API should use the JWT bearer token in the request header , as well as the JWT inside the session cookie . If you want to authenticate to javascript to read JWT payload , you should use two cookie authentication solution by including two types of cookies to avoid XSS attack. Scenario of two cookie authentication

JWT can be updated on every successive request by the server, as well as JWT inside the cookie response and they are automatically saved by the browser. To restrict CSRF, changes will not be implemented via the GET protocol, instead you use PUT or POST . But dynamic changes to issues that require high security should require user credentials . A temporary cookie (random number) that javascript can read and they are submitted in a hidden value of the form along with the form data. The server will have to check, if the value in the cookie does not match the value in the form, the user behavior will not be executed. A random value that acts as a Cookie helps limit CSRF


In summary, we have learned that an authentication flow for SPA should follow these steps:

  • Step 1: Does SPA application check Cookie with JWT payload exist? If so, the user is already logged in, otherwise, it will return to the / login page. If you only use HttpOnlyy cookies, SPA should send a request to / backend / api / me to know who the current user is or if the user is not logged in and displays an error if missing or authentication cookies are not available.
  • Step 2:
    • Option 1: The page / login below the frontend requires user credentials (username / password) then sends them to the backend API via an AJAX Request. AJAX Response will set authentication cookie with JWT token inside.
    • Option 2: The / login page will provide 1 OpenID authentication using OAuth flow. Like logging in via a third party, the / login page will redirect the browser to the / backend / auth / <provider page. > . After the OAuth flow is completed, the backend will set authentication cookie with JWT in it in response. It will redirect the browser under the frontend and the SPA will start from step 1 again
Share the news now

Source : Viblo