GraphQL, Apollo Studio, and Cookies

Danny Ibrahim
Dev Genius
Published in
6 min readDec 22, 2021

--

What We Will Cover

Apollo GraphQL is a great tool, but sometimes its documentation is lacking. A quick Google search will reveal that one of the things that people struggle with (often unsuccessfully) is enabling cookies between Apollo Studio and a NodeJS GraphQL server.

In this article we will:

  1. Describe the problem (skim/skip this if you are in a rush — see the TL;DR at the bottom of the section)
  2. Identify common pitfalls as we work through an implementation
  3. Provide a working final solution

The Problem

So you have setup your GraphQL server using apollo-server-express, write a few queries, and decide its time to implement your application’s authentication strategy. You opt for a cookie-based sessions approach and grab familiar tools like express-session, redis, and connect-redis. After setting-up session logic in your code, you head over to Apollo Studio to see what you have to do to get things rolling. You find the cog icon in the upper left-hand corner of the screen, open the dialog, toggle Include Cookies to ON and see something similar to Figure 1.

The Apollo Studio connection settings dialog
Figure 1: Apollo Studio connection settings dialog

No problem, you think to yourself. You are an experienced software engineer — CORS, cookies, headers — all stuff you are familiar with, and you feel very confident that you will be passing cookies between Apollo Studio and your server in a matter of seconds. You add the specified URL to your CORS origin header, enable credentials, and save your project. Next, you head over to Apollo Studio to validate your genius. Sadly, you likely encounter one of two things:

1) Apollo Studio connects to your server without issue, however, cookies are still not working, or;

2) Your browser’s console is littered with CORS errors (Figure 2), and you see a popup in the bottom-right corner similar to what is shown in Figure 3 (this little dialog is probably about to become the bane of your existence).

CORS policy console error message
Figure 2: CORS error message
Figure 3: Apollo Studio connection error dialog

If you are like many of the people that have posted about this problem on Reddit, you proceed to attempt to figure out what is going wrong for a number of hours before concluding that Apollo Studio is broken and cookies are just not in the cards. You elect to use the GraphQL Playground (not a bad option!) and renounce Apollo Studio forever.

Fast-forward a few months: you are starting a new project and decide that perhaps you were too hasty in your definitive rejection of Apollo Studio. Not only do you remember that it was very pretty, but you are so much more experienced than you were those many moons ago. Long story short(ish), you run into this same problem. You try. Your blood boils. You quit. The cycle repeats over the next few projects until finally, you stumble on this article, giving you hope that it does not have to be this way.

TL;DR

Scenario #1: Apollo Studio connects to your NodeJS GraphQL server, but cookies are not passed.

Scenario #2: Apollo Studio refuses to connect to your server.

Note: Despite the error dialog (Figure 3) and Apollo Studio displaying “Failed to fetch” as its error-response message, you may still observe that your server is receiving requests.

We will actually start with Scenario #2 as fixing it will lead us to Scenario #1, at which point we can proceed to our final solution.

Identifying Potential Causes

Starting Code

As stated above, we will start with an example that results in Scenario #2 and work our way through to a full solution. It is quite possible that your code looks something like this:

server.ts: GraphQL server with issues to fix
appSession.ts: Session setup leveraging redis.

Hopefully, it is not too difficult to follow the flow of these files. server.ts shows a pretty standard implementation of an apollo-server-express application, whereas appSession.ts shows an express-session implementation using redis as its session store. appSession.ts is already setup the way it needs to be — note the sameSite and secure cookie properties on lines 13 and 14 as these are necessary for the desired functionality.

From here on out, whenever we refer to lines of code, we are specifically referring to the server.ts file.

Getting Rid of the `cors` Package

If you are experiencing Scenario #2 but the application seems to integrate perfectly with Apollo Studio when cookies are toggled to OFF, then there is a good chance that you are trying to set your CORS headers using the cors package (as seen on lines 41– 44).

Although I may be the only one that has ever done this, I felt that it is worth addressing because it took me forever to figure out that this was part of the problem when I was working through this issue for the first time.

To enforce CORS headers and rules, take the object passed as an input to cors and instead pass it to the cors property of the server.applyMiddleware input on line 46. It should look like this:

server.applyMiddleware({
app,
cors: {
origin: ['https://studio.apollographql.com'],
credentials: true,
}
});

Delete app.use(cors(//...)) , save the file, and head over to Apollo Studio — you should now see that, that pesky dialog has disappeared and Apollo Studio successfully connects to your server.

Great! The first major hurdle cleared, and we have now hit Scenario #1.

What is in a Proxy, Anyways?

The next line of code that we have to add to our server is:

app.set('trust proxy', 1);

I know that the title of this section alludes to some kind of explanation, but instead, I will just refer you to the Express documentation and let you dig into it on your own.

You do not actually need to understand what this line of code is doing as we are not going to be using it in any other way (although I do encourage you to read up!). That said, if you do not know what a proxy is and the implications of setting this option, I would advise the following modification:

process.env.__dev__ && app.set('trust proxy', 1);

Basically, unless you are already working with a reverse proxy and know what you are doing, including this option in production leaves your server vulnerable. Including this one-liner sets you on your way to working with cookies on Apollo Studio to your heart’s content while in local development, but prevents you from exposing your server to harm once it is released to the world.

Setting the `X-Forwarded-Proto` Apollo Studio Header

If you look at Figure 1, you will see the Default headers section at the bottom of the dialog. The last thing we need to do is set a header called x-forwarded-proto and assign it a value of https . This is pretty straightforward, but I’ve included Figure 4 just in case:

x-forwarded-proto header set to https in Apollo Studio settings dialog
Figure 4: The X-Forwarded-Proto header

This header is directly related to the topic of proxies which we barely talked about, and so I will not go into detail here, however lookout for references to this header in your reading!

If all has gone well, this is the final step and your application should be able to exchange cookies with Apollo Studio!

Final Solution

As promised, here is a file snippet with all of the changes we have discussed:

server.ts: GraphQL server configured to exchange cookies with Apollo Studio

Conclusion

I hope that this has been helpful! It took me a long time to figure this out (the narrative described in the first section pretty closely fits my experience!), and so I wanted to share the benefit of what I have learned.

If this article saved you some time and frustration, please consider offering support by buying me a coffee! If there are any clarifications or questions about this article, or if there is something I mentioned that you would like further explained, please reach out or comment below!

--

--