next-with-apollo-auth icon indicating copy to clipboard operation
next-with-apollo-auth copied to clipboard

Access to fetch at 'https://prismatest3.brunocrosier.now.sh/' from origin 'https://with-apollo-auth.brunocrosier.now.sh' has been blocked by CORS policy

Open arbaouimehdi opened this issue 5 years ago • 7 comments

You've a problem on your Demo that shows on the Google Chrome console:

Access to fetch at 'https://prismatest3.brunocrosier.now.sh/' from origin 'https://with-apollo-auth.brunocrosier.now.sh' 
has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' 
header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
POST https://prismatest3.brunocrosier.now.sh/ net::ERR_FAILED

I guess that prismatest3.brunocrosier.now.sh is blocked by CORS Policy, is there any solution to solve this problem, because everything works perfectly locally, except where I deploy the repo on zeit.co

arbaouimehdi avatar Jan 23 '20 13:01 arbaouimehdi

Hi @freemh that's because I've deleted https://prismatest3.brunocrosier.now.sh 😅

You should replace that URL with your own backend URL inside /frontend/next.config.js

Let me know if you have any difficulty with it

brunocrosier avatar Jan 23 '20 14:01 brunocrosier

Hi @brunocrosier, thanks for your answer, I'm getting the same error from this domaine name https://mern-crud-admin.now.sh/ pointing at this https://mern-crud-api.now.sh.

Everything works perfectly locally, but once I deploy it on it trigger the CORS policy error.

This is the api code:

// Accessing Environment Variables
require("dotenv").config({
  path: `.env.${process.env.NODE_ENV}`
});

const { prisma } = require("./generated/prisma-client");
const { GraphQLServer } = require("graphql-yoga");
const cors = require("cors");

const cookieParser = require("cookie-parser");
const jwt = require("jsonwebtoken");

// Resolvers
const Mutation = require("./resolvers/Mutation");
const Query = require("./resolvers/Query");
const Post = require("./resolvers/Post");
const User = require("./resolvers/User");

// Secret
const { APP_SECRET } = process.env;

// import schema stuff
if (process.env.NODE_ENV !== "production") {
  const { importSchema } = require("graphql-import");
  const fs = require("fs");

  const text = importSchema(__dirname + "/schema.graphql");
  fs.writeFileSync("./schema_prep.graphql", text);
}

const resolvers = {
  Query,
  Mutation,
  User,
  Post
};

const server = new GraphQLServer({
  typeDefs: __dirname + "/schema.graphql",
  resolvers,
  context: request => {
    return { ...request, prisma };
  }
});

const corsOptions = {
  credentials: true,
  origin:
    process.env.NODE_ENV === "production"
      ? [process.env.PRODUCTION_FRONTEND_URL, process.env.PRODUCTION_ADMIN_URL]
      : ["http://localhost:3000", "http://localhost:6555"]
};

server.express.use(cors(corsOptions));

server.express.use(cookieParser());

// 2. decode the JWT so we can get the user Id on each request
server.express.use((req, res, next) => {
  const { token } = req.cookies;

  if (token) {
    const { userId } = jwt.verify(token, APP_SECRET);
    // put the userId onto the req for future requests to access
    req.userId = userId;
    // console.log("userId", userId);
  }
  next();
});

// 3. Create a middleware that populates the user on each request
server.express.use(async (req, res, next) => {
  // if they aren't logged in, skip this
  if (!req.userId) return next();

  const user = await prisma.user({ id: req.userId });
  req.user = user;
  // console.log("req.user", JSON.stringify(req.user));

  next();
});

server.start(
  {
    port: process.env.PORT,
    cors: {
      ...corsOptions
    }
  },
  () => console.log(`Server is running on http://localhost:${process.env.PORT}`)
);

arbaouimehdi avatar Jan 23 '20 15:01 arbaouimehdi

@brunocrosier this is the link of the repo in question: https://github.com/freemh/mern-crud

arbaouimehdi avatar Jan 23 '20 15:01 arbaouimehdi

Hi @freemh I have cloned your project and found the issue.

in the frontend/init-apollo.js file on line 14 you will see this code, which decides whether we load the backend API from the local development server, or from the published one.

const httpLink = createHttpLink({
    uri:
      process.env.NODE_ENV === "production"
        ? process.env.API_URI
        : "http://localhost:7777",
    credentials: "include",
    fetchOptions
  });

If you change it from === to !== then your code will work (because it will fetch the data from https://mern-crud-api.now.sh instead of http://localhost:7777

If you don't want to run your backend API locally, you can just change the code to:

const httpLink = createHttpLink({
    uri: process.env.API_URI,
    credentials: "include",
    fetchOptions
  });

I hope that this helps you!

brunocrosier avatar Jan 23 '20 16:01 brunocrosier

I already did that by setting the uri to process.env.API_URI as you described, and I even set it manually to uri: "https://mern-crud-api.now.sh/" still have the same problem.

I think that this problem is related to the server more than the client, plus the server.express.use(cors(corsOptions)); is not taking effect at all from the api "index.js" file.

Both solution doesn't work to allow different domain names:

const corsOptions = {
  credentials: true,
  origin:
    process.env.NODE_ENV === "production"
      ? [process.env.PRODUCTION_ADMIN_URL]
      : ["http://localhost:6555"]
};

server.express.use(cors(corsOptions));
const corsOptions = {
  credentials: true,
  origin: "https://mern-crud-admin.now.sh/"
};

server.express.use(cors(corsOptions));

What I don't really understand that everything works perfectly locally.

arbaouimehdi avatar Jan 23 '20 16:01 arbaouimehdi

Ah, I only tested this locally - so I think I misunderstood your issue initially.

I have recently built a more updated version of next + apollo + auth for a different project. I will try and tidy it up and then upload it.

In the meantime, this is the index.js for the backend folder for the new project.

require("dotenv").config()

const { prisma } = require("./generated/prisma-client")
const { GraphQLServer } = require("graphql-yoga")
const jwt = require("jsonwebtoken")
const { APP_SECRET } = require("./utils")
const Query = require("./resolvers/Query")
const Mutation = require("./resolvers/Mutation")

const cookiesMiddleware = require("universal-cookie-express")

console.log("process.env.NODE_ENV is: ", process.env.NODE_ENV)

console.log("process.env.PRISMA_SECRET is: ", process.env.PRISMA_SECRET)

// import schema stuff

if (process.env.NODE_ENV !== "production") {
  const { importSchema } = require("graphql-import")
  const fs = require("fs")

  const text = importSchema(__dirname + "/schema.graphql")
  fs.writeFileSync("./schema_prep.graphql", text)
}

const server = new GraphQLServer({
  typeDefs: __dirname + "/schema_prep.graphql",
  resolvers: {
    Query,
    Mutation
  },
  context: request => {
    return { ...request, prisma }
  }
})

server.use(cookiesMiddleware())


server.use((req, res, next) => {
  const token = req.headers.authorization

  if (token && token.length > 10) {
    const { userId } = jwt.verify(token, APP_SECRET)
    req.token = token
    req.userId = userId
  }

  next()
})

server.start(
  {
    cors: {
      credentials: true,
      origin: new RegExp("/*/")
    }
  },
  () => console.log("Server is running on http://localhost:4000")
)

Hopefully this can help you. If not, I will try and update this repo with the latest versions of everything

brunocrosier avatar Jan 23 '20 16:01 brunocrosier

@brunocrosier I'll try to implement the new index.js and let you know, thanks for your time.

arbaouimehdi avatar Jan 23 '20 17:01 arbaouimehdi