Apollo + Next.js, authentication and CSRF protection

Valentijn Nieman
4 min readApr 24, 2018

--

At my previous job, we were working on a project for a client where we wanted to try out writing a backend GraphQL server and connect to it from a Apollo and React frontend. I also read about this cool thing called universal rendering, and wanted to try out Next.js. We ran into some difficulties setting up and understanding how authentication should work with this set up, so I thought I’d write our journey of discovery down here, might it help others in a similar situation!

The specification I got for authentication from the back end developer who build the GraphQL server (in Java) was the following: A login mutation is available, which takes a username and password, that will return a JSESSIONID token, which is used in the back end for sessions. On the /graphql endpoint though — where the mutation is being sent to — a valid CSRF token should be sent along with every request.

We had a small discussion about if the CSRF token was actually needed, and decided it would be, because of the project’s nature (should be secure!) and because Spring Boot’s documentation specified it.

I started writing my front end code, utilising Next.js’ server side rendering, and thinking about how getting the data from the GraphQL server should work on the server side. I found this article very helpful, and the example that comes with it. I also found that Next.js has a great number of well written examples on his Github page. Most if not all of what I ended up using was taken straight from these examples, from the with-apollo-auth example in particular. I just tweaked it a little bit.

In these examples, a HOC called withData is used to create components with data coming from the GraphQL server. The HOC determines if the component passed in is being rendered server side or client side, and sets up an Apollo client via the initApollo method accordingly. It passes cookies along to this function, for the purpose of passing along authentication tokens. Perfect! The cookies are gotten from a parseCookies method, which again checks if we’re on the server or client (if context.req and context.req.headers are set, we have a request object coming from a browser, so we’re on the server. If we would be on the client side, these objects would not exist.)

In the initApollo function, we use create to create an Apollo client. Here, we’re creating an httpLink object, that specifies what Apollo will use for every request to the GraphQL endpoint. The documentation is here. We create a link, pass in our uri — the URL of our /graphQL endpoint — and set credentials to include. This last bit will specify that Apollo will include the headers it gets in the response from the server. In our case, this was the JSESSIONID token. We also create an authLink object that will hold the header data, and here we can specify extra stuff like an X-XSRF-TOKEN header, which Spring Boot will pick up as a CSRF token (in the Next.js example they set a Bearer token here, which is also a good idea). This token is gotten from the getToken() method which was passed in by our withData HOC.

In our case, we had a /csrf endpoint, that when receiving a GET request, would return a Set-Cookie header, which would set the XSRF-TOKEN as a cookie. Whether called from the client or server, these cookies would be set and gotten from the parseCookies method in withData, and be passed on to the initApollo function that could then set these values as headers in a Apollo Link object. My create method in the end looked like this:

function create(initialState, { getToken }) {
const httpLink = createHttpLink({
uri: gql_url + "/graphql",
credentials: "include"
});
const authLink = setContext((_, { headers }) => {
const token = getToken()["XSRF-TOKEN"];
return {
headers: {
...headers,
"X-XSRF-TOKEN": token
}
};
});
return new ApolloClient({
connectToDevTools: process.browser,
ssrMode: !process.browser, // Disables forceFetch on the server (so queries are only run once)
link: authLink.concat(httpLink),
cache: new InMemoryCache().restore(initialState || {})
});
}

At first, these examples can be pretty confusing, at least they were to me. But once you learn more about how it works, you’ll see that Apollo handles a lot of stuff for you, and once you have your Link object set up correctly, it will all work very smoothly!

--

--