Handling the Set-Cookie Header in Nuxt

Nuxt | Cookies

Before we get started, it’s worth clarifying that this process will effectively involve two “servers”. Those being the Nuxt server itself, and the server containing the API to which your Nuxt application is making HTTP requests. To distinguish between the two I will refer to the former as the “Nuxt server” and the latter simply as the “API”.

The Problem

If you’re using Nuxt in Universal mode, you might have noticed that, sometimes, cookies created on an API don’t seem to get handled correctly. That is, the browser doesn’t appear to save or acknowledge them in any way.

To understand the issue here we have to realise that, whichever process is being used to create cookies on the API, the end result is an HTTP response containing a Set-Cookie header. Normally, the browser would automatically interpret this header and store the cookie accordingly. However, if the HTTP request is made from the Nuxt server, that Set-Cookie header is not actually forwarded to the browser. Meaning the cookie data is essentially lost at the Nuxt server, and the browser never has any knowledge of it.

You can validate this claim by running your Nuxt application in SPA mode (or just otherwise ensuring the HTTP request is made from the browser). You should see that this time, the cookie gets saved as expected!

The Solution

There are a multitude of ways this can be handled but the one I’m going to outline below is the one I believe is simplest for most purposes. We’re going to intercept any HTTP responses coming in to the Nuxt server. If that response has a Set-Cookie header, we’re going to parse out that cookie data and manually create the equivalent cookie using a library that allows us to set cookies on a Nuxt server.

This approach uses 3 packages that heavily simplify the solution. None are necessarily mandatory, and you could quite easily adapt the approach to use alternatives or perhaps none at all:

Let’s start by creating a Nuxt plugin named forward-set-cookie.js.

// forward-set-cookie.js

import SetCookieParser from 'set-cookie-parser';

export default function ({ $axios, $cookies }) {
  $axios.onResponse((response) => {
    const cookies = SetCookieParser.parse(response);

    cookies.forEach((cookie) => {
      const { name, value, ...options } = cookie;
      $cookies.set(name, value, options);
    });
  });
}

Now let’s break it down and try to explain each major part.

$axios.onResponse((response) => { ...

We start by creating a callback that will be invoked on the response of any request made by the $axios module. The callback will have access to the full response object.

const cookies = SetCookieParser.parse(response);

We can now use the set-cookie-parser library to pull all the cookie data out of any Set-Cookie headers that were found in the response.

cookies.forEach((cookie) => {
  const { name, value, ...options } = cookie;
  $cookies.set(name, value, options);
});

Finally, simply loop through each cookie we found and use the cookie-universal-nuxt library (via $cookies) to actually set a new cookie, using the same options.

Now all we need to do is enable our new plugin. Add the following to the plugins section of nuxt.config.js.

// nuxt.config.js

plugins: [...{ src: '@/plugins/forward-set-cookies.js', mode: 'server' }];

Note how you’ll only want to run this server-side. If the request is made from the client (the browser), this process won’t be necessary.

That’s it! You should now see that if you make a request to your API, any cookies returned are being correctly handled by the browser.

Other Solutions

Whilst the above approach is, in my opinion, the simplest, you may want to consider a different technique that involves merging any Set-Cookie headers into the headers of the Nuxt response object. This allows those cookies to be handled by the browser as normal, without needing cookie-universal-nuxt. This can get slightly complicated since you need to ensure headers are being correctly merged from all sources, but it might be worth considering, particularly if you are having trouble with missing more headers than just Set-Cookie. For more details about this concept, see this comment.