How to Use Cookies to Persist State in NextJS
With LocalStorage
There are a number of ways to persist users in a React or Single Page Application. A lot of times, devs generally use localStorage to store user data and load the data from there when required. While this approach works, it’s not the most effective way as it leaves users vulnerable to attacks. Using cookies is a little safer although it’s still not the safest option. Personally, I prefer a mixture of using cookies and JWT’s(JSON Web tokens) with expiry to persist user session and to force a user to re-login when their session expires. Using JWT’s is out of the scope of this article.
Getting started using cookies in React/NextJS
To use cookies in NextJS, we need to install 2 packages. For this tutorial, we’ll be using cookie and react-cookie. React-cookie allows us set the cookie from the client side while the cookie package lets us access the set cookie from the server-side. Install both packages by running
npm install react-cookie cookie
Cookie-cutter is a tiny package that does the same thing as react-cookie.
Setting a cookie
With both packages installed, It’s time to set a cookie. Usually, we set a cookie for a user once they’ve succesfully signed in or signed up to our application. To set a cookie on Sign in, follow the example below.
In the snippet above, we call the setCookie hook from `react-cookies` and set it to a default name. In our case, that’s user. We then
make a request to sign in a user by calling a function to log the user in. We take the response from that API call, stringify the data(cookies are formatted as text) and store that data in a cookie.
We also pass some additional options to the cookie including path — makes sure your cookie is accessible in all routes, maxAge, how long from the time the cookie is set till it expires and sameSite. Samesite indicates that this cookie can only be used on the site it originated from — It is important to set this to true to avoid errors within firefox logs.
Giving your app access to the Cookie
To ensure that every route in our application has access to the cookie, we need to wrap our APP component in a cookie provider.
Inside _app.js, add the following bit of code.
Setting up the function to parse the cookie
Next, we need to setup a function that will check if the cookie exists on the server, parse the cookie and return it. Created a new folder called helpers and within that add an index.js file.
Inside this file, add the following piece of code.
The function above accepts a request object and checks the request headers to find the cookie stored.
Accessing the cookie within your component
Finally, we will use getInitialProps in our component to check if the user already has a valid cookie on the server side before rendering the requested route. An alternative to this approach is using getServerSideProps.
Within getInitialProps, we’re passing in the request object(req) that’s available to us on the server-side in NextJS to the parseCookies function. This function returns the cookie to us which we can then send back to the client as props.
We also do a check on the server to see if the response object is available. The res object is only available on the server. If a user hits the HomePage route using next/link or next/router, the res object will not be available.
Using the res object, we check if there are cookies and if they’re still valid. We do this check using the `res` object. If the `data` object is empty, it means the cookie isn’t valid. If the cookie isn’t valid, we then redirect the user back to the index page rather than showing a flash of the HomePage before redirecting the user.
Note that subsequent requests to pages containing getInitialProps using next/link or next/router will be done from the client side. i.e The cookie will be extracted from the client rather than the server side for other routes that are accessed via using next/link or next/router.
And with that, you can now store cookies for users in your application, expire those cookies and secure your app to a good extent.