Apollo-server: Apollo Server 2 - Override CORS Default

Created on 5 Jun 2018  路  20Comments  路  Source: apollographql/apollo-server

Is there a way to override the CORS default when using apollo-server directly? It looks like apollo-server is defaulting to origin: '*', and I'd like to lock it down so only my client can hit the server.

I don't see anything related to CORS in ApolloServer or listen(). It does look like I can set CORS in registerServer using express middleware. Is that the only way?

Most helpful comment

For anyone else reading this, newer versions of apolloServer accept the cors property in the applyMiddleware call, not in the constructor:

https://github.com/apollographql/apollo-server/blob/version-2/packages/apollo-server-express/src/ApolloServer.ts#L90

All 20 comments

@zachrnolan You'll have to use apollo-server-express and pass in the cors configuration to registerServer. apollo-server is designed to be a good getting started with best practice defaults and be an integration independent interface. cors settings are unfortunately specific to the integration.

Right now we have to create an instance of express to pass in as app. A nice change would be to make it optional here and construct it around here. Some documentation around its new usage in the api reference

@evans generally I would prefer to avoid heavy library such as express just to enable cors.
That's sole purpose of using apollo-server directly without added middlewares.

The method supplied by @ScreamZ requires the use of ApolloServer.applyMiddleware, that throws an error stating that one should use apollo-server-express.

To not require the need of a middleware, instead one can supply the cors field in the constructor of ApolloServer.
e.g.

const server = new ApolloServer({
  cors: false,
  typeDefs,
  resolvers
});

@SimonKinds This is also an option, I was using it before I needed to use cookies in my request context.

keep in mind that cors: false is really a bad idea, you open any hacked website to spam your api using XSS.

Consider settings an array of hosts or a function as described in the original cors library which is used under the hood by apollo.

EDIT: This is for cors:true not false

@ScreamZ Please excuse me if I'm incorrect, but the lack of a access-control-allow-origin header disallows _all_ websites, except for the same origin, to access the API.
Is that not so?

The effect cors: false has upon the response is that the access-control-allow-origin header is removed, and should therefore be safe, given that my previous assumption is correct.

@SimonKinds My bad, I think you're right, it was about cors:true which allows any ;)

For anyone else reading this, newer versions of apolloServer accept the cors property in the applyMiddleware call, not in the constructor:

https://github.com/apollographql/apollo-server/blob/version-2/packages/apollo-server-express/src/ApolloServer.ts#L90

@norbertkeri, correct me if I'm wrong but that's the ApolloServer by the apollo-server-express, and not the apollo-server package. I believe the package discussed in this thread is more directed towards the apollo-server.

The ApolloServer class given by the apollo-server package accepts the cors option in the constructor, as seen in https://github.com/apollographql/apollo-server/blob/fa6c973f3685fceea905acf259824005e0e0ffe2/packages/apollo-server/src/index.ts#L30

You are probably right, sorry.

Anyway, I spent a few hours trying to figure out why apollo-server-express was not working until I got here. You're both right, probably. Thank you guys!

After migrating from apollo server 1 to version 2 I could not figure out why I am getting access-control-allow-origin * even if I have my own express middleware taking care of the cors.

As it turns out, apollo server has its own cors implementation and therefore you need to turn it off if you have cors set up allready.

The official documentation is wrong / or not clear, since you have to turn it off in two places in order to disable it.

// first pass cors: false to the constructor:
const server = new ApolloServer({
  cors: false,
  ...
})

// and you also have to pass it here
server.applyMiddleware({ app, cors: false });

Now it will not override your own implementation.

In apollo-server v2.4.8 my requests from a client application running at http://localhost:3000 sent to server running at http://localhost:4000 are rejected

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://localhost:4000/. (Reason: CORS request did not succeed).

This is how my server is configured ApolloServer

const apolloServer = new ApolloServer({
    schema,
    context,
    introspection: true,
    cors: {
      origin: "*",
      methods: "GET,HEAD,PUT,PATCH,POST,DELETE",
      preflightContinue: false,
      optionsSuccessStatus: 204,
      credentials: true
    }
  });

but neither of those worked.

I can't use server.applyMiddleware() since it is throwing an error in this version

public applyMiddleware() {
    throw new Error(
      "To use Apollo Server with an existing express application, please use apollo-server-express"
    );
  }

In FireFox the OPTIONS request does not have HTTP response code and response size is 0. In Chrome I am getting an error - the request fails with ERR_SSL_PROTOCOL_ERROR.

Can anybody help me?
Thanks,
Karel

Maybe think about switch to express ?

import { ApolloServer } from "apollo-server-express";

apolloServer.applyMiddleware({
    app,
    cors: {
      credentials: true,
      origin: true
    },
    path: "/",
  });

@ScreamZ thanks for help, it did not help first. Then I wondered why the SSL error and the it hit me - my apollo client was making requests to https://localhost:4000, after removing the s and switching to http it worked (your suggestion and my original code).

Note to myself - never blindly copy and paste code from the Internet.

The CORS settings come from ExpressJS, not from ApolloServer. If you want to add a custom or wildcard origin you have to handle it with a callback function.

const server = new ApolloServer({
    ....,
    cors: {
        credentials: true,
        origin: (origin, callback) => {
            const whitelist = [
                "http://site1.com",
                "https://site2.com"
            ];

            if (whitelist.indexOf(origin) !== -1) {
                callback(null, true)
            } else {
                callback(new Error("Not allowed by CORS"))
            }
        }
    }
});

Thank you @agavazov . The above worked for me and the client/server architecture appears to handle the whole thing, IE. There is no need to make specific changes to the client. I imagine the InMemoryCache setting is where that happens, (for Angular pure client) :

// ../src/app/app.module.ts
providers: [
    {
      provide: APOLLO_OPTIONS,
      useFactory: (httpLink: HttpLink) => {
        return {
          cache: new InMemoryCache(),
          link: httpLink.create({
            uri: '/api/graphql'
          })
        };
      },

Apollo was overidding my cors middleware applied to the express app. I moved cors from the express to here:

apolloServer.applyMiddleware({ app, cors: {origin: "http://localhost:3000", credentials: true} });

and now it works.

Apollo was overidding my cors middleware applied to the express app. I moved cors from the express to here:

apolloServer.applyMiddleware({ app, cors: {origin: "http://localhost:3000", credentials: true} });

and now it works.

I'm having exactly the same problem, and your solution just worked perfectly. Thank you =)
However I would like to keep using the cors package as middleware =/
Did anyone find a solution to this?

@davincif If you pass cors: false, Apollo Server won't do any cors stuff, and you can just do your own cors earlier in the pipeline.

Was this page helpful?
0 / 5 - 0 ratings