I'm facing a CORS policies issues with Firebase functions even though I think I'm doing the right thing in the backend, I'll show you the code.
const cors = require("cors");
const express = require("express");
const cookieParser = require('cookie-parser');
const app = express();
app.use(
cors({
origin: true,
credentials: true
}),
cookieParser(),
);
This is the function I'm trying to call from the frontend:
app.post("/auth/login", (req, res) => login(req, res));
With this body:
const login = async (req, res) => {
try {
const user = {
id: req.body.id,
password: req.body.password,
};
const auth = getAuth();
const { valid, errors } = validateLoginData(user);
if (!valid)
throw { code: "validation-failed", message: errors, status: 400 };
let data = await signInWithEmailAndPassword(auth, user.id, user.password);
let token = await data.user.getIdToken();
console.log("TOKEN: " + token);
res.cookie("_token", token, { httpOnly: true, maxAge: 3600000 });
return res.status(202).json({ message: "OK" });
} catch (err) {
switch (err.code) {
case "validation-failed":
return res.status(err.status).json({ message: err.message });
case "auth/user-not-found":
case "auth/wrong-password":
return res
.status(401)
.json({ message: "Wrong credentials, please try again" });
default:
return res.status(500).json({ message: err.message });
}
}
};
So here's the problem: when I call this from postman it works, when I call this from my browser (Brave) it doesn't work and it tells me this in the console:
Access to XMLHttpRequest at 'https://europe-west1-stormtestfordota.cloudfunctions.net/api/auth/login' 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-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
I've tried with many fixes that I found online but none has worked, can you help me please?
CORS is a node.js package for providing Express middleware that can be used to enable CORS with various options.
Enable all CORS requests
Enable CORS for a single route
Configuring CORS
Configuring CORS with dynamic origin
Enable CORS Preflight
Enable CORS asynchronously
If you want to use Express and CORS middleware like that, you should try onRequest functions as shown below:
const express = require('express');
const cors = require('cors');
const app = express(); // Automatically allow cross-origin requests
app.use(cors({ origin: true })); // build multiple CRUD interfaces:
app.get('/test2', (req, res) => { //Handle your test2 methods here
return res.send('your response')
}); // Expose Express API as a single Cloud Function:
exports.api = functions.https.onRequest(app);
Now in this case the CORS middleware you wrote will be running. Your function's URL may look something like - https://us-central1-myapp.cloudfunctions.net/api Then to use the /test2 route it becomes https://us-central1-myapp.cloudfunctions.net/api/test2. CORS shouldn't be an issue anymore here but do note it's an express app now so the parameters in the function are Request, Response instead of data, context.
Also try to follow the steps outlined on https://cloud.google.com/functions/docs/samples/functions-http-cors#functions_http_cors-nodejs and the function will look something like below as in this
exports.hello = functions.https.onRequest((request, response) => {
response.set('Access-Control-Allow-Origin', '*');
response.set('Access-Control-Allow-Credentials', 'true'); // vital
if (request.method === 'OPTIONS') { // Send response to OPTIONS requests
response.set('Access-Control-Allow-Methods', 'GET');
response.set('Access-Control-Allow-Headers', 'Content-Type');
response.set('Access-Control-Max-Age', '3600');
response.status(204).send('');
}
else {
const params = request.body;
const html = 'some html';
response.send(html)
} )};
Also have this essential reading on CORS for better understanding of the issue.
Related
I am trying to upload some images to cloudinary through my client, it works fine on localhost, and in chrome version 87, but in chrome v89 i get No 'Access-Control-Allow-Origin' header error, any ideas on why this is happening?
this is my server route:
const uploader = require('../config/cloudinary.config')
router.post('/upload', uploader.single("imageUrl"), (req, res) => {
res.setHeader('Access-Control-Allow-Origin', 'client domain');
if (!req.file) {
res.status(500).json({ code: 500, message: 'Error loading the file' })
return;
}
res.json({ secure_url: req.file.path })
})
and this is my cors config:
const cors = require('cors')
const whitelist = [process.env.DOMAIN]
const corsOptions = {
origin: (origin, cb) => {
const originIsWhitelisted = whitelist.includes(origin)
cb(null, originIsWhitelisted)
},
credentials: true
}
You probably need to handle CORS preflight requests, which your browser presents as OPTION requests before the POST requests.
Add this line to your code.
router.options('/upload', cors())
Heroku backend Node.js and Netlify frontend react app has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I've seen a lot of posts on this, but I just can't seem to fix what's creating this error. Of course, I believe it has to do with CORS. But as you can see, I've added multiple versions of CORS middleware to allow this to work. Locally everything is fine. Production/live is where I get the issue:
Access to XMLHttpRequest at 'https://seb-youtube-api.herokuapp.com//videos?page=1&limit=50' from origin 'https://seb-youtube-api.netlify.app' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Here is my backend server with Node.js and Express.js
They make a simple call to a youtube API.
require('dotenv').config();
const express = require('express');
const bodyParser = require('body-parser')
const app = express();
const cors = require('cors')
const chalk = require('chalk');
const { google } = require('googleapis');
const youtube = google.youtube('v3'); // initialize the Youtube API library
// Middleware
app.use(cors());
app.use(bodyParser.json());
/******************** GET REQUEST TO VIDEOS *********************/
app.get('/videos', async (req, res) => {
const results = await fetchYoutubePlaylist();
res.json(results)
})
// /******************** POST REQUEST, USER SEARCH *********************/
app.post('/videos', async (req, res) => {
console.log('POST QUERY',req.body)
const query = req.body
res.body = await fetchYoutubeSearch(query)
console.log("RES POST", res.body)
res.json(res.body)
})
app.use('*', cors(), (req, res) => {
return res.status(404).json({ message: 'Not Found' });
});
// CORS
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Content-Type,multipart/form-data,Authorization');
res.header('Access-Control-Allow-Methods', 'GET,POST,PUT,PATCH,DELETE');
if (req.method === 'OPTIONS') {
return res.send(204);
}
next();
});
/******************** FIRST YOUTUBE API CALL *********************/
const fetchYoutubePlaylist = async () => {
try {
const {data} = await youtube.playlistItems.list({
key: process.env.YOUTUBE_API_TOKEN,
part: ['snippet'],
maxResults: 50,
playlistId: "UUBh8XcZST_JTHt-IZDxT_pQ"
})
console.log(data)
return data.items
} catch(err) {
console.log(chalk.red(err))
}
}
/******************** SECOND YOUTUBE API CALL *********************/
const fetchYoutubeSearch = async ({query}) => {
console.log(query)
try {
const {data} = await youtube.search.list({
key: process.env.YOUTUBE_API_TOKEN,
part: ['snippet'],
q: query,
channelId: 'UCBh8XcZST_JTHt-IZDxT_pQ',
order: 'date',
type: 'video',
maxResults: 50
})
console.log('YOUTUBE SEARCH', data)
return data.items
} catch(err) {
console.log(chalk.red(err))
}
}
/******************** LIST TO PORT *********************/
const port = process.env.PORT || 3001;
app.listen(port, () => console.log(`Listing on port ${port}`));
Is the issue that your browser is blocking CORS? That happens to me with Heroku stuff sometimes. There are browser extensions to block/unblock CORS depending on the browser you're using
Stick only with app.use(cors()); that alone should work fine. Instead double check your Config Vars (env vars) on heroku and/or netlify wherever you set such variables. Sometimes that CORS error can be misleading being actually a connection error more about your environment variables.
I am learning to implement API using Node.js, Express and MongoDB. I am on early learning phase. I have added cors package using npm i cors to the project. And I am using cors as middleware in my project as follows.
const express = require("express");
const app = express();
const cors = require("cors");
const mongojs = require("mongojs");
const { body, param, validationResult } = require("express-validator");
const db = mongojs("travel", ["records"]);
const bodyParser = require("body-parser");
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(
cors({
origin: ["http://a.com", "http://b.com"],
methods: ["GET"],
allowHeaders: ["Authorization", "Content-Type"],
})
);
app.get("/api/records", cors(corsOptions), function (req, res) {
db.records.find(function (err, data) {
if (err) {
return res.sendStatus(500);
} else {
return res.status(200).json({
meta: { total: data.length },
data,
});
}
});
});
app.post(
"/api/records",
[
body("name").not().isEmpty(),
body("from").not().isEmpty(),
body("to").not().isEmpty(),
],
function (req, res) {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
db.records.insert(req.body, function (err, data) {
if (err) {
return res.status(500);
}
const _id = data._id;
res.append("Location", "/api/records/" + _id);
return res.status(201).json({
meta: { _id },
data,
});
});
}
);
app.listen(8000, function () {
console.log("Server running at port 8000...");
});
I only added GET request in the allowed methods. But when I try to POST new records, it is working properly. And moreover, I only added "http://a.com", "http://b.com" in the host list but all requests from localhost are working properly. Please let me know what I am missing here. Thanks much in advance.
Based on your question and your subsequent comment, it sounds like there a couple things going on here:
CORS protections are only enforced by an actual browser engine. If you're making the requests from a non-browser client, then there are no CORS limitations.
To trigger a CORs protection from a browser, you have to be making an actual cross origin call. If everything is on localhost, then that won't be cross origin.
This question already has answers here:
5xx or 4xx error with “No 'Access-Control-Allow-Origin' header is present”
(2 answers)
aws apigateway lambda always return 502
(4 answers)
AWS API Gateway error response generates 502 "Bad Gateway"
(4 answers)
Closed 2 years ago.
I have a react front app which invokes rest api based on lambda and express. The integration is done via AWS API Gateway. Even the with the cors module I do not achieve what I want.
This is the code:
const express = require('express');
const app = express();
require('dotenv').config();
const youTube = require('./lib/youtube');
const ffmpeg = require('fluent-ffmpeg');
const Logger = require('./lib/logger');
const cors = require('cors');
const serverLogger = new Logger(__filename);
// Init Middleware
app.use(express.json({ extended: true }));
app.use(cors({ origin: true }));
app.get('/', (req, res) => {
res.json({ msg: 'Welcome to the YouTube downloader API...' });
});
app.post('/api/youtube/download', async (req, res) => {
const body = req.body;
const { url } = body;
res.header('Content-disposition', 'attachment; filename=video.mp3');
res.header('Access-Control-Allow-Headers', 'Content-Type');
res.header('Access-Control-Allow-Methods', 'OPTIONS,POST,GET');
res.header('Access-Control-Allow-Origin', '*');
const youTubeStream = await youTube.getStream(url);
ffmpeg(youTubeStream)
.format('mp3')
.audioBitrate('192k')
.on('end', function () {
console.log('file has been converted succesfully');
res.status(200);
})
.on('error', function (err) {
console.log('an error happened: ' + err.message);
res.status(500).json({ error: err.message });
})
// save to stream
.pipe(res, { end: true });
});
app.post('/api/youtube/info', async (req, res) => {
const body = req.body;
console.log(body);
const { url } = body;
const title = await youTube.getInfo(url);
console.log(title);
res.status(200).json({ title: title });
});
module.exports = app;
I keep on getting this message:
Access to fetch at '...' from origin '...' has been blocked by CORS policy: 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.
I have a very simple nodejs server, but using the 'cors' package seems to not recognize the origin of the request for some reason.
Here is my nodejs server config:
const cors = require('cors');
const express = require('express');
const CORS_WHITELIST = [ 'http://localhost:5000' ];
const corsOptions = {
origin: (origin, callback) => {
console.log(origin) // ----> this is always 'undefined'
if (CORS_WHITELIST.indexOf(origin) !== -1){
callback(null, true)
} else {
callback(new Error('Not allowed by CORS'))
}
}
};
const configureServer = app => {
app.use(cors(corsOptions));
};
module.exports = configureServer;
Here is my server starter file:
const express = require('express');
const SERVER_CONFIGS = require('./constants/server');
const configureServer = require('./server');
const configureRoutes = require('./routes');
const app = express();
configureServer(app);
configureRoutes(app);
app.listen(SERVER_CONFIGS.PORT, error => {
if (error) throw error;
console.log('Server running on port: ' + SERVER_CONFIGS.PORT);
});
I am running this server on localhost, but the origin in the cors callback is always 'undefined'. For example when I open http://localhost:5000 on the browser or do a curl call.
How can I use cors so that it doesn't block the request on localhost?
I read this issue and req.headers.origin is undefined question and also CORS and Origin header!
source:
The origin may be hidden if the user comes from an ssl encrypted website.
Also: Some browser extensions remove origin and referer from the http-request headers, and therefore the origin property will be empty.
There is a solution to solve this by adding a middleware:
app.use(function (req, res, next) {
req.headers.origin = req.headers.origin || req.headers.host;
next();
});
I hope these helps. The issue is in awaiting more info state!