Nuxt Apollo with dynamic headers for a session based authentication

Viewed 3916

Apollo is not storing the header from the query dynamically.

pages/index.vue

methods: {
  fetchCars() {
    const token = Cookies.get('XSRF-TOKEN')

    console.log(token) //  Token is shown in console

    this.$apollo.query({
      query: gql`
        query {
          cars {
            uuid
            name
          }
        }
      `,
      headers: {
        'X-XSRF-TOKEN': token, // ⭕ Fetch without header
      },
    })
  },
},

Is there a way to set the header value new for every Apollo request?

I have a separate Frontend and Backend. For the Frontend I am using Nuxt.js with Apollo. I want to have a session based communication with my server. For this reason I need to send the CSRF-Token with every Request.

Now the problem: On the first load of the page there is no Cookie set on the browser. I do a GET-Request on every initialization of my Nuxt application.

plugins/csrf.js

fetch('http://127.0.0.1:8000/api/csrf-cookie', {
  credentials: 'include',
})

Now I have a valid Cookie set on my side and want to communicate with the GraphQL Server but my header is not set dynamically in the query. Does anyone know how I can solve this?

My Laravel Backend is throwing now a 419 Token Mismatch Exception because I did not send a CSRF-Token with my request.

Link to the repository: https://github.com/SuddenlyRust/session-based-auth

[SOLVED] Working solution: https://github.com/SuddenlyRust/session-based-auth/commit/de8fb9c18b00e58655f154f8d0c95a677d9b685b Thanks to the help of kofh in the Nuxt Apollo discord channel

1 Answers

In order to accomplish this, we need to access the code that gets run every time a fetch happens. This code lives inside your Apollo client's HttpLink. While the @nuxtjs/apollo module gives us many options, we can't quite configure this at such a high level.

Step 1: Creating a client plugin

As noted in the setup section of the Apollo module's docs, we can supply a path to a plugin that will define a clientConfig:

// nuxt.config.js
{
  apollo: {
    clientConfigs: {
      default: '~/plugins/apollo-client.js'
    }
  }
}

This plugin should export a function which receives the nuxt context. It should return the configuration to be passed to the vue-cli-plugin-apollo's createApolloClient utility. You don't need to worry about that file, but it is how @nuxtjs/apollo creates the client internally.

Step 2: Creating the custom httpLink

In createApolloClient's options, we see we can disable defaultHttpLink and instead supply our own link. link needs to be the output of Apollo's official createHttpLink utility, docs for which can be found here. The option we're most interested in is the fetch option which as the docs state, is

a fetch compatible API for making a request

This boils down to meaning a function that takes uri and options parameters and returns a Promise that represents the network interaction.

Step 3: Creating the custom fetch method

As stated above, we need a function that takes uri and options and returns a promise. This function will be a simple passthrough to the standard fetch method (you may need to add isomorphic-fetch to your dependencies and import it here depending on your setup).

We'll extract your cookie the same as you did in your question, and then set it as a header. The fetch function should look like this:

(uri, options) => {
  const token = Cookies.get('XSRF-TOKEN')

  options.headers['X-XSRF-TOKEN'] = token

  return fetch(uri, options)
}

Putting it all together

Ultimately, your ~/plugins/apollo-client.js file should look something like this:

import { createHttpLink } from 'apollo-link-http'
import fetch from 'isomorphic-fetch'

export default function(context) {
  return {
    defaultHttpLink: false,
    link: createHttpLink({
      uri: '/graphql',
      credentials: 'include',
      fetch: (uri, options) => {
        const token = Cookies.get('XSRF-TOKEN')

        options.headers['X-XSRF-TOKEN'] = token

        return fetch(uri, options)
      }
    })
  }
}
Related