CORS in Apollo Client & Apollo Server
Tags: apollo, tutorial, react, express
Published: 2019-05-01 17:00:03

## This is a follow-up
Ok, a while back I asked a question and spent a few days trying to figure this out.  I'm hoping that this can direct someone trying to solve the problem in the right direction.  As a reference, this is the original post.

{% link https://dev.to/doylecodes/graphql-server-not-setting-jwt-cookie-1gme %}

## My problem
So, my problem was that I had set up an Apollo Server with the backend hosted from a /backend directory and the frontend hosted from a separate directory at /frontend.  My frontend was running on localhost:3000 and the backend I had running at localhost:4000. I was running into various problems with CORS as I tried to pass cookies along with requests, and I couldn't figure out what was going on. I also had a difficult time figuring out how to pass certain things (like user data) with requests.

**My problem was, I was trying to pass along specific cors options, and I didn't know that Apollo Server came with default cors settings.  Those settings were overriding and conflicting with what I needed**

## The Solution
My solution ended up being 2 parts:
1. Using the package `apollo-server-express` and the cors middleware.
2. Disabling the Apollo Server cors to avoid conflicts.

```javascript
const express = require('express');
const { Prisma } = require('prisma-binding');
const { ApolloServer } = require('apollo-server-express');
const { importSchema } = require('graphql-import');
const cookieParser = require('cookie-parser');
const jwt = require('jsonwebtoken');
const cors = require('cors');
require('dotenv').config();

const typeDefs = importSchema('./src/schema.graphql');
const Query = require('./src/resolvers/Query');
const Mutation = require('./src/resolvers/Mutation');

const db = new Prisma({
  typeDefs: './generated/prisma.graphql',
  endpoint: process.env.DB_ENDPOINT,
  secret: process.env.DB_SECRET
});

const server = new ApolloServer({
  typeDefs,
  resolvers: {
    Mutation,
    Query
  },
  context: req => ({ ...req, db }),
});

const app = express();

var corsOptions = {
  origin: process.env.FRONTEND_URL,
  credentials: true // <-- REQUIRED backend setting
};

app.use(cors(corsOptions));
app.use(cookieParser());
app.use((req, res, next) => { // checks for user in cookies and adds userId to the requests
  const { token } = req.cookies;
  if (token) {
    const { userId } = jwt.verify(token, process.env.USER_SECRET);
    req.userId = userId;
  }
  next();
})
app.use(async (req, res, next) => {
  if (!req.userId) return next();
  const user = await db.query.user(
    { where: { id: req.userId } },
    '{id, permissions, email, name}' //the graphql query to pass to the user query
  );
  next();
})

server.applyMiddleware({
  app,
  path: '/',
  cors: false, // disables the apollo-server-express cors to allow the cors middleware use
})

app.listen({ port: 4000 }, () =>
  console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`)
);
```

This is my server/app set up as of now with everything working perfectly! Here are the main points and why I ended up implementing it that way.
- **Using `apollo-server-express` instead of `apollo-server`:** This essentially allows you to create an express app and pass it to the server instead of using the vanilla app that Apollo Server creates on its own.  It also allows you to create middlewares just as you would with a generic express based application and server!
- **app.use(cors(corsOptions)):** For more granular cors options (I wanted the server to only listen to localhost:3000) you use the cors middleware and the options to listen to the origin you want, as well as the option to pass on credentials with requests.
- **server.applyMiddleware:** It is here that you pass to the Apollo Server the express application, as well as the other important part, **turn off the default cors options**.  Even though you turn off the default options, you are using the cors middleware in the express app you pass to the server, so it's all handled there.