CORS blocks mutation in GraphQL Yoga

CORS blocks mutation in GraphQL Yoga


6

I am working here with a graphql prisma backend and a graphql yoga express server on top of that. In the frontend, I am trying to call a signout mutation but its blocked by the CORS policy. Though I have added cors settings in my graphql yoga server, I keep getting this error. GraphQL Queries are working fine but Mutations are being blocked. My frontend URL is ‘https://localhost:7777‘ and yoga server is running at ‘https://localhost:4444/‘. The Error was:

Access to fetch at 'https://localhost:4444/' from origin 'https://localhost:7777' 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.

[Network error]: TypeError: Failed to fetch

GraphQL Yoga Server Cors Config:

server.start(
{
    cors: {
        credentials: true,
        origin: [process.env.FRONTEND_URL],
    },
},
deets => {
    console.log(
        `Server is now running on port https://localhost:${deets.port}`
    );
}
);

Mutation:

// import React, { Component } from 'react';
import { Mutation } from 'react-apollo';
import styled from 'styled-components';
import gql from 'graphql-tag';
import { CURRENT_USER_QUERY } from './User';
import { log } from 'util';

const SIGN_OUT_MUTATION = gql`
mutation SIGN_OUT_MUTATION {
    signout {
        message
    }
}
`;

const SignOutBtn = styled.button`
color: ${props => props.theme.textMedium};
padding: 10px;
margin-right: 20px;
text-align: center;
font-family: garamond-light;
border: 1px solid ${props => props.theme.textMedium};
border-radius: 5px;
transition: background-color 0.5s ease;
transition: color 0.5s ease;
:hover {
    background: ${props => props.theme.textMedium};
    color: ${props => props.theme.white};
}
`;

const Signout = props => (
<Mutation
    mutation={SIGN_OUT_MUTATION}
    refetchQueries={[{ query: CURRENT_USER_QUERY }]}
>
    {signout => (
        <SignOutBtn
            onClick={() => {
                console.log("comes here")
                signout();
            }}
        >
            Sign Out
        </SignOutBtn>
    )}
</Mutation>
);
export default Signout;

Please tell me what I am doing wrong here. Thanks in Advance.

3

  • I don't see what's wrong with the code you shared. Could you provide a minimum reproduciable repository for us to investigate more?

    – Errorname

    Dec 16, 2018 at 18:43

  • @Errorname Thanks for trying to help and you can find the repo here. The repo won't be having environment files. If you are in need of those, please let me know.

    – arvind

    Dec 17, 2018 at 8:07


  • Thank you for the link, but there is too much files to analyse. Could you create a repository with only the files necessary to reproduce the issue?

    – Errorname

    Dec 17, 2018 at 10:00

5 Answers
5


3

The solution to the problem was to write a middleware that sets appropriate response headers so that the fetch doesn’t fail.

server.express.use(function(req, res, next) {
  res.header('Access-Control-Allow-Origin', 'https://localhost:7777');
  res.header(
    'Access-Control-Allow-Headers',
    'Origin, X-Requested-With, Content-Type, Accept'
  );
  next();
});

The above is the yoga express server middleware used to solve the problem.

4

  • Did you keep the cors: {credentials: true,origin: process.env.FRONTEND_URL,}, on the server?

    – Chance Smith

    Jan 31, 2019 at 19:01

  • @ChanceSmith Yes I tried that, but it wasn't working for me. I have posted the same config in the question as well. Let me know if I have done something wrong.

    – arvind

    Jan 31, 2019 at 19:15

  • Sorry, I'm having the same issue, but now wondering if you left that object in or not. 🤷‍♂️

    – Chance Smith

    Feb 1, 2019 at 22:12

  • Can you share more of the code above this block? I've found several implementations of this, but none that really explain how the .express.use part is set up. This CodePen is what I have so far.

    – redliz5808

    Apr 13, 2022 at 15:41


1

What I had to do was pass the origin an array of string values. As well as set the new origin PAST_FRONTEND_URL in heroku

server.start(
  {
    cors: {
      credentials: true,
      origin: [process.env.FRONTEND_URL, process.env.PAST_FRONTEND_URL],
    },
  },
  deets => {
    console.log(`Server is now running on port https://localhost:${deets.port}`);
  }
);


1

I had the same problem and it was solved with this

server.start(
  {
    cors: {
      credentials: true,
      origin: [process.env.FRONTEND_URL],
      methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
      preflightContinue: false,
      optionsSuccessStatus: 204
    }
  },
  server => {
    console.log(`Server is running on https://localhost/${server.port}`);
  }
);


1

Adding this middleware helped in my case:

server.express.use((req, res, next) => {
  res.header('Access-Control-Allow-Credentials', true)
  next()
})


1

Server Application must add Access-Control-Allow-Origin: YOUR_DOMAIN to the response header and the browser will not complain about it.

You can use a middleware to achieve it.

app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "YOUR-DOMAIN"); // update to match the domain you will make the request from
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
});

OR

const cors =  require('cors')
const corsOptions = {
    origin: [
        
        "https://YOUR-DOMAIN"
    ],
    credentials: true
}
app.use(cors(corsOptions))

But wait !! I already done these steps but still the problem exist ;(

if after these steps the issue still exist.

then it’s because of corrupted response.

maybe your server throw an exception while sending the response or maybe it restart and the response not sent to client completely. or maybe some problem with your ISP or VPN which block some requests. 🙂



Leave a Reply

Your email address will not be published. Required fields are marked *