Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apollo Server 2 - Override CORS Default #1142

Closed
zachrnolan opened this issue Jun 5, 2018 · 21 comments
Closed

Apollo Server 2 - Override CORS Default #1142

zachrnolan opened this issue Jun 5, 2018 · 21 comments

Comments

@zachrnolan
Copy link

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?

@evans
Copy link
Contributor

evans commented Jun 5, 2018

@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 evans closed this as completed Jun 5, 2018
@techyrajeev
Copy link

@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.

@ScreamZ
Copy link

ScreamZ commented Aug 5, 2018

@skindstrom
Copy link

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
});

@ScreamZ
Copy link

ScreamZ commented Aug 13, 2018

@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

@skindstrom
Copy link

@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.

@ScreamZ
Copy link

ScreamZ commented Aug 13, 2018

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

@norbertkeri
Copy link

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

@skindstrom
Copy link

@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

constructor(config: Config & { cors?: CorsOptions | boolean }) {

@norbertkeri
Copy link

You are probably right, sorry.

@MarcosRZ
Copy link

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!

@zsolt-dev
Copy link

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.

@kfrajtak
Copy link

kfrajtak commented Apr 25, 2019

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

@ScreamZ
Copy link

ScreamZ commented Apr 25, 2019

Maybe think about switch to express ?

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

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

@kfrajtak
Copy link

@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.

@agavazov
Copy link

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"))
            }
        }
    }
});

@radkin
Copy link

radkin commented Jul 20, 2020

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'
          })
        };
      },

@elrhaff
Copy link

elrhaff commented Dec 11, 2020

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.

@davincif
Copy link

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?

@glasser
Copy link
Member

glasser commented Apr 16, 2021

@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.

@CoreyKovalik
Copy link

@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.

@glasser 's answer: this is the way! :)

For those having some trouble using app.use(CorsMiddleware); at the top of their express app, like this:

const app = express.default();
app.use(CorsMiddleware);

you'll notice that apollo server will disregard your cors middleware:

// your earlier cors middleware will be disregarded because cors defaults to `true`
apolloServer.applyMiddleware({ app, path: '/graphql' });

// when using cors options, even if they are the same for both your cors middleware, and specified here in .applyMiddleware,
// your first cors middleware will be disregarded.
apolloServer.applyMiddleware({ app, path: '/graphql', cors: corsOptions });
// This will make your initial cors middleware be respected o7
apolloServer.applyMiddleware({ app, path: '/graphql', cors: false });

Also worth mentioning, cors package respects regex in allowed origins, but for applyMiddleware regex does not seem to work as expected.

import * as express from 'express';
import { ApolloServer } from 'apollo-server-express';
import cors, { CorsOptions } from 'cors';


// https://github.com/expressjs/cors#readme
const corsAllowedOrigin: Array<string | RegExp> = ['https://foobar.com'];

if (!config.IS_PROD) {
    corsAllowedOrigin.push(/localhost/);
}

const corsOptions: CorsOptions = {
    origin: corsAllowedOrigin,
    credentials: true,
};

const CorsMiddleware = cors(corsOptions);

const app = express.default();

// regex for `cors.origin` will work
app.use(CorsMiddleware);

// regex for `cors.origin` will NOT work
apolloServer.applyMiddleware({ app, path: '/graphql', cors: false });

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 20, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests