I was having trouble sending post requests with content-type application/json to my backend due to cors restrictions.
I've started using 'cors' module and also enabled pre-flight requests for these routes.
My requests will now be answered and processed properly but I'll still get the following error on my console, which I'm not sure if it has side effects I'm not aware of.
Method OPTIONS is not allowed by Access-Control-Allow-Methods in
preflight response.
OPTIONS https://example.com/api/postRequest
net::ERR_FAILED
const cors = require('cors');
const corsOptions = {
origin: 'https://example.com',
optionsSuccessStatus: 200,
};
app.options('/api/postRequest', cors(corsOptions), function (req, res, next) {
res.header("Access-Control-Allow-Methods", "*");
res.setHeader('Content-Type', 'application/json');
next()
})
app.post('/api/postRequest', cors(corsOptions), async (req, res) => {
res.header("Access-Control-Allow-Methods", "*");
res.setHeader('Content-Type', 'application/json');
//do other stuff and send response
}
To enable all http methods, use:
const corsOptions = {
origin: 'https://example.com',
optionsSuccessStatus: 200,
methods: '*'
};
Related
I am trying to implement CSRF protection to my API endpoints,
I am using express and csurf, when making a post request using Axios from my react app I am receiving 403 invalid csrf token.
I have been searching all over for a solution but could not find one that fits.
For example, I am trying to send an Axios request to log out from the app (delete the session cookie) and receive the error.
A code that shows the error looks like that:
server.ts:
const router = express();
dotenv.config();
router.use(helmet...)
router.use(cookies());
router.use(express.static(path.resolve(__dirname, '../client/build')));
var production = process.env.NODE_ENV === 'production' ? true : false;
var csrfProtection = csurf({ cookie:{
httpOnly:production,
secure:production
} });
router.use(csrfProtection);
router.use(cors({ credentials: true, origin: true
,exposedHeaders:['itemsCount','notificationCount','courseCount'] }));
router.use((req, res, next) => {
res.cookie('XSRF-TOKEN', req.csrfToken(),{httpOnly:production,secure:production});
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization, itemsCount');
if (req.method == 'OPTIONS') {
res.header('Access-Control-Allow-Methods', 'PUT, POST, PATCH, DELETE, GET');
return res.status(200).json({});
}
next();
});
router.use('/api', userRoute);
const httpServer = http.createServer(router);
httpServer.listen(config.server.port, () =>
logging.info(NAMESPACE, `Server is running ${config.server.hostname}:${config.server.port}`));
user.ts:
router.post(`/${NAMESPACE}/logout`,verifyToken, logout);
userController.ts:
const logout = (req: Request, res: Response, next: NextFunction) => {
res.clearCookie('session');
return sendResponse(res, 200);
}
the axios request looks like that:
logout: () => axios.post(`/users/logout`, {},{withCredentials: true})
Both XSRF-TOKEN and _csrf cookies are secure and httpOnly.
I would much appreciate it if someone can point me to what I am doing wrong here.
Thanks.
This is my first question posed, so I apologize if it is not formatted well.
I have been trying to figure out how to deal with the following CORS error, as well as, the CORS preflight error:
...has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'https://example.com/' that is not equal to the supplied origin.
I have spent the last few days reading every question on this topic, and all other documentation I could find on CORS/Cloud Functions/Axios/etc. I am using React, Node, Express, Axios, Google Firebase to host, and Google Cloud Functions.
I am trying to access the PayPal API to gain a bearer token to make further API requests. I understand some of the code pertaining to the request headers might be redundant. I have just been trying to throw anything at this.
Does anyone have any ideas?
The node file - index.js
const axios = require("axios");
const express = require("express");
const cors = require("cors")({ origin: true });
const app = express();
app.use(cors());
app.use(express.json());
app.post("/v1/oauth2/token/", cors(), (req, res) => {
res.set("Access-Control-Allow-Origin", "https://example.com/");
var data = qs.stringify({
grant_type: "client_credentials",
});
var config = {
method: "post",
url: "https://api-m.sandbox.paypal.com/v1/oauth2/token/",
headers: {
"Access-Control-Allow-Origin": "https://example.com/",
Authorization:"xyz",
"Content-Type": "application/x-www-form-urlencoded",
},
data: data,
};
axios(config)
.then(function (response) {
let bearerToken = response.data.access_token;
res.status(201).send(bearerToken);
})
.catch(function (error) {
console.log(error);
});
});
exports.api = functions.https.onRequest(app);
The react file - payment.js
import axios from "../axios/axios";
const oneTimePaypalPayment = async () => {
const response = await axios.post("/v2/checkout/orders");
console.log(response);
};
The axios file - axios.js
import axios from "axios";
const instance = axios.create({
headers: {
"Access-Control-Allow-Origin": "https://example.com/",
"Access-Control-Allow-Headers": "https://example.com/",
},
baseURL: "https://us-central1-example.cloudfunctions.net/api/"
});
export default instance;
What I have tried
I have tried using the wildcard " * " just to try to get it to work but no luck. I read on another answer that Google Cloud Functions do not recognize the '*' anyways. I have also tried all of the code below, and a lot of other ways to manipulate the Access-Control-Allow-Origin on the request header
const allowCrossDomain = function (req, res, next) {
res.header("Access-Control-Allow-Headers", "*");
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE");
next();
};
app.use(allowCrossDomain);
app.all("*", (req, res, next) => {
res.header("Access-Control-Allow-Headers", "*");
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE");
next();
});
const corsOptions = {
origin: "https://example.com/",
};
app.use(cors(corsOptions))
app.options("/v1/oauth2/token", cors(corsOptions));
app.use(cors({origin:true}));
Any thoughts would be greatly appreciated
In a cloud function that you are exporting or working with use below for Origin :
exports.your function = async (req, res) => {
res.set('Access-Control-Allow-Origin', '*');
I am calling a local API from ionic project testing on android but it shows Http response status code 0 unknown error I did look up for many solutions but non helped.
app.use(function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, OPTIONS');
res.header("Access-Control-Allow-Credentials", "true",);
res.header('Access-Control-Allow-Headers', 'Origin, X-Auth-Token, Accept, Content-Type, Authorization, Content-Length, X-Requested-With, x-access-token, Access-Control-Request-Method, Access-Control-Request-Headers');
next();
});
method requesting API.
async loginWithFacebook(data) {
console.log("api USER data from facebook ");
console.log(data);
let headers = new HttpHeaders({
'Content-Type': 'application/json'
});
let options = {
headers: headers
};
return await (this.http.post(environment.endpoint + "/users/facebook-login", data, options)).toPromise();
}
it's unable to call the API for some reason.
You are just assigning header to the HTTP response, which will not help you with the CORS of the request. Doing the following might help.
Install cors package in the server root using terminal.
npm i cors
Import cors to your app.js (the root file of your server).
const cors = require('cors')
Use cors for your App.
app.use(cors())
Your final code should look something like this.
var express = require('express')
var cors = require('cors')
var 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')
})
Source
This question already has answers here:
CORS: Cannot use wildcard in Access-Control-Allow-Origin when credentials flag is true
(11 answers)
Closed 3 years ago.
I have express.js server:
import express from 'express';
import cors from 'cors';
import bodyParser from 'body-parser';
import mongoose from 'mongoose';
import helmet from 'helmet';
import config from './config/config.js';
import authRoutes from './routes/auth.js';
import userRoutes from './routes/user.js';
mongoose.connect(config.mongoUri, { useNewUrlParser: true });
mongoose.connection.on('error', () => {
throw new Error(`unable to connect to database: ${config.mongoUri}`);
});
const port = 9000;
const app = express();
app.use(helmet());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cors());
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'POST,GET,LINK');
});
app.use('/', authRoutes);
app.use('/', userRoutes);
app.listen(port, () => console.log(`Example app listening on port ${port}!`));
Cors package install corectly in package.json.
Here is my routes
import express from 'express';
import authCtrl from '../controllers/auth.controller.js';
const router = express.Router();
router.route('/auth/signin').post(authCtrl.signin);
router.route('/auth/signout').get(authCtrl.signout);
export default router;
When i trying to make request from Postman - all is working,
but when try to do in from another server :
const signin = user => {
console.log('user', user);
return fetch('http://localhost:9000/auth/signin/', {
method: 'POST',
headers: {
'Access-Control-Allow-Origin': '*',
Accept: 'application/json',
},
credentials: 'include',
body: JSON.stringify(user),
})
.then(response => {
return response.json();
})
.catch(err => console.log(err));
};
It's error occur in the console
Access to fetch at 'http://localhost:9000/auth/signin/' from origin
'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
In network i can see OPTIONAL request :
Access-Control-Allow-Headers: access-control-allow-origin
Access-Control-Allow-Methods: GET,HEAD,PUT,PATCH,POST,DELETE
Access-Control-Allow-Origin: *
So how can I fix this problem?
as you are using cors npm :
in your app js just add below and remove unnecessary code
import cors from 'cors';
app.use(cors());
and in your react project folder in package.json file :
"proxy": "http://localhost:9000",
so your api call will be :
const signin = user => {
console.log('user', user);
return fetch('/auth/signin', {
method: 'POST',
credentials: 'include',
body: JSON.stringify(user),
})
.then(response => {
return response.json();
})
.catch(err => console.log(err));
};
use cors configuration like this.
app.use(function (req, res, next) {
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:9000');
// 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', 'X-Requested-With,content-type');
// 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();
});
Use only one
app.use(cors());
Or
app.use(function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:9000');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
res.setHeader('Access-Control-Allow-Credentials', true);
next();
})
using Postman, so the CORS mechanism wasn’t involved.
in second way and use browser for fetch data from url the request itself was successful, but the browser blocked it.
i think the other ways to bypass the CORS policy
One way to override the CORS policy is to install an extension such as Allow-Control-Allow-Origin: *. It Adds the Allow-Control-Allow-Origin: * header to the all the responses that your browser receives. As mentioned above, it disrupts the way that cookies are sent and received, so keep that in mind.
Another thing you can do is to specify in your request, that you want to bypass the CORS secure mechanism. You can do it if you use Fetch API by setting the mode parameter to no-cors:
fetch('http://localhost:9000', { mode: 'no-cors' });
This will work regardless of the Access-Control-Allow-Origin header. There is no equivalent of that in the XMLHttpRequest, unfortunately.
I need to enable CORS on every endpoint for POST requests that matches /api/v1/support/* path.
I'm making a POST request to /api/v1/support/graphql with credentials true, but the preflight request (the OPTIONS one) returns a 401. I'm not sure what I'm doing wrong.
This is my configuration (note that I have changed the actual domain for a dummy in this sample below):
const corsOptions = {
origin: /mydomain\.com$/,
credentials: true,
maxAge: 3600
};
app.options('/api/v1/support/*', cors(corsOptions));
app.post('/api/v1/support/*', cors(corsOptions));
// graphQLRouter is an instance of express.Router()
app.use('/api/v1/support/graphql', [ fowardIP, validateTokenInCookie ], graphQLRouter);
Can you please try this. Setting access control also
const app = express();
const corsOptions = {
origin(origin, callback) {
callback(null, true);
},
credentials: true
};
app.use(cors(corsOptions));
var allowCrossDomain = function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type,token');
next();
}
app.use(allowCrossDomain);
This may help you