Can't get CORS working with Restify + GraphQL setup - node.js

I've set up a GraphQL server using express-graphql and Restify, which works perfectly on Postman. However, when actually calling it from our frontend we keep getting CORS issues. I've tried just about everything.
The weird thing is that if we remove all headers from the frontend axios request, CORS is no longer an issue - but then we get the "query must be a string" error from graphql.
Full code:
const restify = require('restify');
const { graphqlHTTP } = require('express-graphql');
const corsMiddleware = require('restify-cors-middleware2');
const schema = require('./Schemas');
const { auth } = require('./middleware');
const { bugsnag } = require('./utils/config');
const PORT = process.env.PORT || 3004;
const app = restify.createServer();
app.use(bugsnag.requestHandler);
app.use(function crossOrigin(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
const allowHeaders = ['Accept', 'Accept-Version', 'Content-Type', 'Api-Version', 'Origin', 'X-Requested-With']; // added Origin & X-Requested-With
res.header('Access-Control-Allow-Headers', allowHeaders.join(', '));
// res.header('Access-Control-Allow-Credentials', true); // tried both with and without this
return next();
});
app.use(auth.authenticateUser);
app.post(
'/graph',
graphqlHTTP((req, res, graphQLParams) => {
console.log(req);
return {
schema,
context: {
user: req.user,
},
};
})
);
app.get(
'/graph',
graphqlHTTP({
schema,
graphiql: true,
})
);
app.listen(PORT, () => console.log(`Listening on port ${PORT}!`));
Other things I've tried:
const cors = corsMiddleware({
preflightMaxAge: 5,
origins: ['*'],
allowHeaders: ['X-App-Version'],
exposeHeaders: [],
});
app.pre(cors.preflight);
app.use(cors.actual);
I also tried:
app.use(function crossOrigin(req, res, next) {
console.log('Adding cors headers');
const allowHeaders = ['Accept', 'Accept-Version', 'Content-Type', 'Api-Version', 'Origin', 'X-Requested-With'];
res.header('Access-Control-Allow-Credentials', 'true');
res.header('Access-Control-Allow-Headers', allowHeaders.join(', '));
res.header("Access-Control-Allow-Origin", "http://localhost:3000");
next();
});
I also tried basically every combination of all of the above, and none worked. I even tried removing the auth header from the request and removing the auth middleware, and that didn't work either (although it did get us to the point where at least it was a 404 error due to "query not being a string" rather than the CORS issue.

This isn't very well documented in the restify-cors-middleware2 package, but turns out I need to set the allowCredentialsAllOrigins and credentials properties, as well as add a lot more allowHeaders:
const cors = corsMiddleware({
preflightMaxAge: 5,
origins: ['*'],
allowHeaders: [
'X-App-Version',
'Accept',
'Accept-Version',
'Content-Type',
'Api-Version',
'Origin',
'X-Requested-With',
'Authorization',
],
exposeHeaders: [],
credentials: true,
allowCredentialsAllOrigins: true,
});
app.pre(cors.preflight);
app.use(cors.actual);

Related

CORS on react request to node.js API

This is my node,js API,that works with no problems using postman, but when I try to make a request from a different origin like a react project the request is blocked
const express = require('express');
const mongoose = require('mongoose');
const app = express();
const port = process.env.PORT || 9000;
const routes = require('./routes/routes');
const token = require('./config/config');
const cors = require('cors')
app.use(cors())
app.use(express.json());
app.use('/api', routes);
app.listen(port, () => console.log('server listening on port', port));
const url = "mongodb://localhost/titles_db";
mongoose.connect(url,{})
.then( () => console.log('DB connected'))
.catch( (e) => console.log('Erorr on db connection'));
and this is the function that is called on my request
searchTitles = (req, res) => {
const terms = req.query.terms;
const format = req.query.format;
titleSchema.find({title: {$regex:terms, $options: 'i'}})
.then( data => {
if(format == 'json')
res.json(data);
else{
res.setHeader("Content-Type", "text/plain");
res.send(data);
}
})
.catch( error => res.json( {message: error}))
}
and here is the function that makes the request on the frontend
const getFieldText = e => {
setTerm({term: e.target.value });
const url = `http://localhost:9000/api/titles/?terms=${e.target.value}&format=json`
fetch(url)
.then(response => console.log(response))
.then(data => console.log(data));
}
even including cors library on node
const cors = require('cors')
app.use(cors())
I get this response
Response { type: "cors", url: "http://localhost:9000/api/titles/?terms=aaaaaa&format=json", redirected: false, status: 403, ok: false, statusText: "Forbidden", headers: Headers, body: ReadableStream, bodyUsed: false }
I added an options array but I have the same result
var corsOptions = {
origin: 'http://localhost:3000',
optionsSuccessStatus: 200 // some legacy browsers (IE11, various SmartTVs) choke on 204
}
app.use(cors(corsOptions))
configure the cross headers like this (in your server node config):
app.use(function (req, res, next) {
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', "http://localhost:8080");
// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, authorization, Access-Control-Allow-Origin');
// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
res.setHeader('Access-Control-Allow-Credentials', 'true');
// Pass to next layer of middleware
next();
});

CORS blocking my node server from react app localhost

Tried everything I could find on here in regards to setting up cors for my node server. Tried aliasing my localhost and that doesn't seem to work either. Also tried using the CORS unblock extension.
error: localhost/:1 Access to fetch at
'http://localhost:8080/api/login' from origin 'http://localhost:3000'
has been blocked by CORS policy: Response to preflight request doesn't
pass access control check: It does not have HTTP ok status.
:8080/api/login:1 Failed to load resource: net::ERR_FAILED
im trying to use magic link authentication in my react app. I got this POST request being made to my node server
const res = await fetch(`http://localhost:8080/api/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer ' + didToken,
},
});
my server code is
const express = require("express");
const cors = require("cors");
const { Magic } = require('#magic-sdk/admin');
require('dotenv').config();
const app = express()
const magic = new Magic(process.env.MAGIC_SECRET_KEY);
app.use("*", (req, res) => res.status(404).json({ error: "not found" }));
// Allow requests from client-side
app.use(cors({origin: process.env.CLIENT_URL}));
app.all('*', (req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Credentials', 'true');
res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
res.header(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept, Authorization'
);
res.sendStatus(200);
next();
});
app.post('api/login', async (req, res) => {
console.log("login fired")
try {
const didToken = req.headers.authorization.substr(7);
await magic.token.validate(didToken);
res.status(200).json({ authenticated: true });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
module.exports = app
app.use(cors({origin: process.env.CLIENT_URL}));
I'd be curious what this URL is. If you want an open CORS policy you don't need to set anything any there.
Put a "/" in front of this route
app.post('/api/login', async (req, res) => {
I was able to reproduce your problem locally and this server setup worked for me to fix it.
const express = require("express");
const cors = require("cors");
const port = 8080;
const app = express();
app.use(cors());
app.post("/api/login", async (req, res) => {
console.log("login fired");
try {
res.status(200).json({ authenticated: true });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.listen(port, () => {
console.log(`Example app listening on port ${port}`);
});
module.exports = app;

Why do I have the CORS policy error in my browser? CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource

I have installed cors via npm and used the app.use(cors());middleware, but it is not solving my issue. I am running my frontend React App on Port localhost:3000
Access to XMLHttpRequest at 'http://localhost:3087/authenticate-token' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Here below is the whole code from my app.js file:
const bodyParser = require("body-parser");
const cors = require("cors");
const dotenv = require("dotenv");
const express = require("express");
const mongoose = require("mongoose");
const session = require("express-session");
// const request = require('req')
const app = express();
dotenv.config();
// Parse Application/json
app.use(bodyParser.json());
// Base URL
// app.locals.baseURL = "h";
app.use(cors());
app.use(
session({
secret: process.env.ACCESS_TOKEN_SECRET,
saveUninitialized: true,
resave: false,
cookie: {
secure: true,
},
})
);
// DB Config
const db = require("./config/keys").mongoURI;
// Connect to MongoDB
mongoose
.connect(db, {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(() => console.log("MongoDB Connected"))
.catch((err) => console.log(err));
// Routes
app.use("/", require("./routes/auth"));
app.use("/pages", require("./routes/pages"));
app.use("/signUpModule", require("./routes/signUpModule"));
app.use("/users", require("./routes/users"));
const PORT = process.env.PORT || 3087;
app.listen(PORT, console.log(`Server running on ${PORT}`));
Below I have added the code from my end point:
const express = require("express");
// Authenticate Token
router.get(
"authenticate-token",
authFunctions.authenticateToken,
(req, res) => {
res.send({user: req.user, tokenValid: true});
);
Try to add this to your app.js file:
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "*");
res.header(
// "Access-Control-Allow-Origin",
"Origin, X-Requested-With, Content-Type, Accept, Authorization"
);
if (req.method == "OPTIONS") {
res.header("Access-Control-Allow-Methods", "GET PATCH DELETE POST PUT");
return res.status(200).json({});
}
next();
});
So, it so happens that the issue was coming from the client-side where I was using axio to make a request. At first I had the following:
export const userAuthenticated = async (token) => {
const response = await axios.get(`${API_BASE_URL}/authenticate-token`, {
headers: {
authorization: token,
}
});
if (response.statusText === "OK") return response.data;
};
Then later, I changed to the following, which worked:
export const userAuthenticated = async (token) => {
const response = await axios({
headers: {
authorization: token,
},
method: "get",
url: `${API_BASE_URL}/authenticate-token`,
});
if (response.statusText === "OK") return response.data;
};

Angular + Nodejs Express: ERROR Cross-Origin Request Blocked: Same Origin Policy disallows reading the remote resource at

I'm trying to post data from angular (on port 4200) to the back-end node.js express server on port 3000.
What I've done so far: I have tried to post the json data from angular to the httpbin.org (a 3rd party server for test use), which proves that my function in angular is valid to post the json data.
Also, I used angular to get data from API of other websites, and they all work, only the nodejs server which is hosted on port 3000 has CORS problem when posting data from angular to it.
I have been googling to change the header of cors for the nodejs server and checked the firewall and lots of other approaches, but nothing works, I always get the CORS error.
**Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://127.0.0.1:3000/api/postData. (Reason: CORS request did not succeed).**
**ERROR:**
Object { headers: {…}, status: 0, statusText: "Unknown Error", url: "http://127.0.0.1:3000/api/postData", ok: false, name: "HttpErrorResponse", message: "Http failure response for http://127.0.0.1:3000/api/postData: 0 Unknown Error", error: error }
​
error: error { target: XMLHttpRequest, isTrusted: true, lengthComputable: false, … }
​
headers: Object { normalizedNames: Map(0), lazyUpdate: null, headers: Map(0) }
​
message: "Http failure response for http://127.0.0.1:3000/api/postData: 0 Unknown Error"
​
name: "HttpErrorResponse"
​
ok: false
​
status: 0
​
statusText: "Unknown Error"
​
url: "http://127.0.0.1:3000/api/postData"
​
<prototype>: Object { … }
the Angular file: compoent.ts
getData(loc : any) {
//angular --> nodejs
const headers = new HttpHeaders()
.set('Authorization', 'my-auth-token')
.set('Content-Type', 'application/json');
this.http.post<any>("http://127.0.0.1:3000/api/postData", JSON.stringify(loc)).subscribe(response =>{
console.log(response);
});
I tried all kinds of headers and cors that I can find on the internet in this Nodejs file but nothing works: app.js
const express = require('express')
const app = express()
const port = 3000
const cors = require('cors')
app.options('*', cors()) // include before other routes
//app.use(cors())
const corsOpts = {
origin: '127.0.0.1:3000',
methods: [
'GET',
'POST',
],
allowedHeaders: [
'Content-Type',
],
};
app.use(cors(corsOpts));
app.use(function(req, res, next) {
// res.header("Access-Control-Allow-Origin", "*");
// res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
// next();
// Website you wish to allow to connect
res.header('Access-Control-Allow-Origin', '127.0.0.1:3000');
// Request methods you wish to allow
res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
// Request headers you wish to allow
res.header('Access-Control-Allow-Headers', 'Accept, Content-Type, X-Requested-With', 'X-HTTP-Method-Override');
// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
res.header('Access-Control-Allow-Credentials', true);
if (req.method === 'OPTIONS') {
res.sendStatus(200);
} else {
next();
}
});
app.use(
cors({
allowedHeaders: ["authorization", "Content-Type"], // you can change the headers
exposedHeaders: ["authorization"], // you can change the headers
origin: "*",
methods: "GET,HEAD,PUT,PATCH,POST,DELETE",
preflightContinue: false
})
);
app.get('/', (req, res, next) => {
res.send("wtffffffffffffffffff");//send to the page
})
app.get('/getAPIResponse', (req, res, next) => {
api_helper.make_API_call('https://jsonplaceholder.typicode.com/posts')
.then(response => {
res.json(response)
})
.catch(error => {
res.send(error)
})
})
//angular --> nodejs
app.post('/api/postData',cors(), (req, res, next) => {
console.log("/postData success when running ng serve");
console.log(req.body);
})
app.listen(port, () => console.log(`NodeJS App listening on port ${port}!`))
This is the proxy file : proxy.conf.json
{
"/api/*": {
"target": "http://127.0.0.1:3000",
"pathRewrite": {"^/api" : ""},
"secure" : false,
"changeOrigin" : true
}
}
The problem is simple: I did not run the nodejs server at the backend
From the docs
Simple Usage (Enable All CORS Requests)
const express = require('express')
const cors = require('cors')
const app = express()
app.use(cors())
app.get('/products/:id', function (req, res, next) {
res.json({msg: 'This is CORS-enabled for all origins!'})
})
app.listen(80, function () {
console.log('CORS-enabled web server listening on port 80')
})
Get the basic CORS setup working first and then think about battoning down the hatches with some CORS config.
Also remove your proxy config if you are using CORS. Make HTTP requests direct from FE (browser) to your BE server if using CORS.

How can I support cors when using restify

I have a REST api created with the restify module and I want to allow cross-origin resource sharing. What is the best way to do it?
You have to set the server up to set cross origin headers. Not sure if there is a built in use function or not, so I wrote my own.
server.use(
function crossOrigin(req,res,next){
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
return next();
}
);
I found this from this tutorial. http://backbonetutorials.com/nodejs-restify-mongodb-mongoose/
The latest version of Restify provides a plugin to handle CORS.
So you can now use it like this:
server.use(restify.CORS({
// Defaults to ['*'].
origins: ['https://foo.com', 'http://bar.com', 'http://baz.com:8081'],
// Defaults to false.
credentials: true,
// Sets expose-headers.
headers: ['x-foo']
}));
This works for me:
var restify = require('restify');
var server = restify.createServer();
server.use(restify.CORS());
server.opts(/.*/, function (req,res,next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", req.header("Access-Control-Request-Method"));
res.header("Access-Control-Allow-Headers", req.header("Access-Control-Request-Headers"));
res.send(200);
return next();
});
server.get('/test', function (req,res,next) {
res.send({
status: "ok"
});
return next();
});
server.listen(3000, function () {
console.log('%s listening at %s', server.name, server.url);
});
This is what worked for me:
function unknownMethodHandler(req, res) {
if (req.method.toLowerCase() === 'options') {
console.log('received an options method request');
var allowHeaders = ['Accept', 'Accept-Version', 'Content-Type', 'Api-Version', 'Origin', 'X-Requested-With']; // added Origin & X-Requested-With
if (res.methods.indexOf('OPTIONS') === -1) res.methods.push('OPTIONS');
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Headers', allowHeaders.join(', '));
res.header('Access-Control-Allow-Methods', res.methods.join(', '));
res.header('Access-Control-Allow-Origin', req.headers.origin);
return res.send(204);
}
else
return res.send(new restify.MethodNotAllowedError());
}
server.on('MethodNotAllowed', unknownMethodHandler);
I this code was taken from https://github.com/mcavage/node-restify/issues/284
CORS Plugin is deprecated in favor of https://github.com/Tabcorp/restify-cors-middleware. (Source: https://github.com/restify/node-restify/issues/1091.)
Below is a sample code regarding how to use
const corsMiddleware = require('restify-cors-middleware')
const cors = corsMiddleware({
preflightMaxAge: 5, //Optional
origins: ['http://api.myapp.com', 'http://web.myapp.com'],
allowHeaders: ['API-Token'],
exposeHeaders: ['API-Token-Expiry']
})
server.pre(cors.preflight)
server.use(cors.actual)
If anyone comes across this as of Feb 2018 there seems to be a bug that's been introduced, I couldn't get the restify-cors-middleware to work.
I'm using this work around for now:
server.pre((req, res, next) => {
res.header("Access-Control-Allow-Origin", "*");
next();
});
To enable CORS for basic authentication I did the following. It did not work until the .pre methods were used instead of the .use methods
server.pre(restify.CORS({
origins: ['https://www.allowedip.com'], // defaults to ['*']
credentials: true,
headers: ['X-Requested-With', 'Authorization']
}));
server.pre(restify.fullResponse());
function unknownMethodHandler(req, res) {
if (req.method.toLowerCase() === 'options') {
var allowHeaders = ['Accept', 'Accept-Version', 'Content-Type', 'Api-Version', 'Origin', 'X-Requested-With', 'Authorization']; // added Origin & X-Requested-With & **Authorization**
if (res.methods.indexOf('OPTIONS') === -1) res.methods.push('OPTIONS');
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Headers', allowHeaders.join(', '));
res.header('Access-Control-Allow-Methods', res.methods.join(', '));
res.header('Access-Control-Allow-Origin', req.headers.origin);
return res.send(200);
} else {
return res.send(new restify.MethodNotAllowedError());
}
}
server.on('MethodNotAllowed', unknownMethodHandler);
I do it like this on my restify base app:
//setup cors
restify.CORS.ALLOW_HEADERS.push('accept');
restify.CORS.ALLOW_HEADERS.push('sid');
restify.CORS.ALLOW_HEADERS.push('lang');
restify.CORS.ALLOW_HEADERS.push('origin');
restify.CORS.ALLOW_HEADERS.push('withcredentials');
restify.CORS.ALLOW_HEADERS.push('x-requested-with');
server.use(restify.CORS());
you need to use restify.CORS.ALLOW_HEADERS.push method to push the header u want into restify first, then using the CORS middleware to boot the CORS function.
MOST OF THE PREVIOUS ANSWERS ARE FROM 2013 AND USE DEPRECATED EXAMPLES!
The solution (in 2017 at least) is as follows:
npm install restify-cors-middleware
Then in your server javascript file:
var corsMiddleware = require('restify-cors-middleware');
var cors = corsMiddleware({
preflightMaxAge: 5,
origins: ['*']
});
var server = restify.createServer();
server.pre(cors.preflight);
server.use(cors.actual);
And add whatever additional other options work for you. My use case was creating a localhost proxy to get around browser CORS issues during devolopment. FYI I am using restify as my server, but then my POST from the server (and to the server) is with Axios. My preference there.
npm listing for restify-cors-middleware
This sufficed in my case:
var server = restify.createServer();
server.use(restify.fullResponse());
server.get('/foo', respond(req, res, next) {
res.send('bar');
next();
});
It wasn't necessary to server.use(restify.CORS());
Also, it appears server.use() calls must precede server.get() calls in order to work.
This worked for me with restify 7
server.pre((req, res, next) => {
res.header('Access-Control-Allow-Origin', req.header('origin'));
res.header('Access-Control-Allow-Headers', req.header('Access-Control-Request-Headers'));
res.header('Access-Control-Allow-Credentials', 'true');
// other headers go here..
if(req.method === 'OPTIONS') // if is preflight(OPTIONS) then response status 204(NO CONTENT)
return res.send(204);
next();
});
I am using Restify 7.2.3 version and this code worked for me very well.
You need to install the restify-cors-middleware plugin.
const corsMiddleware = require('restify-cors-middleware')
const cors = corsMiddleware({
preflightMaxAge: 5, //Optional
origins: ['http://ronnie.botsnbytes.com', 'http://web.myapp.com'],
allowHeaders: ['API-Token'],
exposeHeaders: ['API-Token-Expiry']
})
server.pre(cors.preflight)
server.use(cors.actual)
const cors = require('cors');
const server = restify.createServer();
server.use(cors());
This worked for me
const restify = require('restify');
const corsMiddleware = require('restify-cors-middleware');
const cors = corsMiddleware({
origins: ['*']
});
const server = restify.createServer();
server.pre(cors.preflight);
server.use(cors.actual);
server.get('/api/products', (request, response) => {
response.json({ message: 'hello REST API' });
});
server.listen(3000, () => console.info(`port 3000`));
... is one brute-force solution, though you should be very careful doing that.

Resources