I have the following code:
const { v4: uuidv4 } = require('uuid')
const functions = require('firebase-functions')
const nodemailer = require('nodemailer')
const cors = require('cors')({ origin: true })
const gmailEmail = functions.config().gmail.email
const gmailPassword = functions.config().gmail.password
const mailto = functions.config().gmail.mailto
const mailTransport = nodemailer.createTransport({
service: 'gmail',
auth: {
user: gmailEmail,
pass: gmailPassword
}
})
exports.sendMail = functions.https.onRequest((req, res) => {
cors(req, res, () => {
const items = req.body.items.forEach(item => (
`${item.quantity} x ${item.uuid} (${item.name})\n`
))
if (req.method === 'POST') {
const mailOptions = {
from: gmailEmail,
replyTo: gmailEmail,
to: mailto,
subject: `Order ${uuidv4()} from ${req.body.name} (${req.body.email})`,
text: `Order\n\n${items}`
}
mailTransport.sendMail(mailOptions)
res.status(200).send(JSON.stringify({ status: 'OK' }))
} else {
res.status(400).send(JSON.stringify({ status: 'method not allowed' }))
}
})
})
For some reason it worked once and then keeps giving me
Access to fetch at 'https://xxxxx.cloudfunctions.net/sendMail' from origin 'https://xxxx.com' 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.
What am I missing? If possible I'd like to avoid using Express.
For you to configure CORS on your Cloud Functions with Firebase, you will need to configure and set some additional parameters - as mentioned in the official documentation here - for CORS to be authorized and execute via HTTP in your application.
The parameters in an example of settings that you will need to configure on your application is the following:
const express = require('express');
const cors = require('cors')({origin: true});
const app = express();
app.use(cors({ origin: true }));
I would recommend you to give it a try using the above setting for you to give the authorization in your backend.
Besides that, the below questions from the Community, there are some other solutions and use cases of similar issues to yours, that I believe should help you achieve the configuration and that I think you should check as well.
Enabling CORS in Cloud Functions for Firebase
Enable CORS while an XMLHttpRequest error occurs in flutter web
Let me know if the information helped you!
Related
Chrome authorization Headers
I believe I have cors configured correctly in my backend. The API is hosted on Heroku if that helps. Here is the server.js file:
const express = require("express");
const helmet = require("helmet");
const cors = require("cors");
const bodyParser = require("body-parser");
const productsRouter = require("./products/products-router");
const ordersRouter = require("./orders/orders-router");
const emailsRouter = require("./emails/emails-router");
const corsOptions = {
origin: "*",
credentials: true,
optionSuccessStatus: 200,
};
const server = express();
server.use(express.json());
server.use(helmet());
server.use(cors(corsOptions));
server.use("/api/products", productsRouter);
server.use("/api/orders", ordersRouter);
server.use("/api/emails", emailsRouter);
server.use((err, req, res, next) => {
res.status(err.status || 500).json({
message: err.message,
});I
});
module.exports = server;
I get a cors error when my front-end tries to make HTTP requests to the backend. It reads as follows:
Access to XMLHttpRequest at
'https://nanasoapsbackend.herokuapp.com/api/products/categories' from
origin 'http://localhost:3000' has been blocked by CORS policy: No
'Access-Control-Allow-Origin' header is present on the requested
resource.
Yes, my back and and front end are on different domains. This just happened all of a sudden, it was working fine with no cors errors for the past few months, and suddenly it stopped working. Any help would be greatly appreciated.
The problem is: You can't have origin * (allow everything) with allow credentials. See: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors/CORSNotSupportingCredentials
You have to set up a white list (list of domains that are allowed)
const whitelist = ['http://www.example.com', 'http://www.otherexample.com']
const corsOptions = {
origin: function (origin, callback) {
if (whitelist.includes(origin)) {
callback(null, true)
} else {
callback(new Error('Not allowed'))
}
}
}
Then on your client side (frontend) make sure you use withCredientals flag on your http agent (axios, superagent, fetc, etc)
front end: localhost:3000 (react app) App.js (client) on load call api '/'
function fetch_redirect() {
fetch("http://localhost:8082")
}
function App() {
return <div className="App">{fetch_redirect()}</div>;
}
export default App;
backend: localhost:8082 (nodejs express app) send redirect to /test endpoint on client
const express = require('express')
const app = express()
const cors = require('cors');
const whitelist = ['http://localhost:3000']
const corsOptions = {
origin: function (origin, callback) {
console.log(origin, whitelist.indexOf(origin) !== -1);
if (whitelist.indexOf(origin) !== -1) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS'))
}
}
}
app.use(cors(corsOptions))
app.get('/', function (req, res) {
res.redirect('http://localhost:3000/test')
})
app.listen(8082)
The main issue is on the client (react) once the API call is made, the redirect is blocked... how can I make the client react app follow this redirect to 'http://localhost:3000/test' I already have cors on my backend with an enabled whitelist of localhost:3000 to allow me to make the API call not blocked... however the redirect is now blocked from the fetch frontend!
error details:
Access to fetch at 'http://localhost:3000/test' (redirected from 'http://localhost:8082/') from origin 'http://localhost:3000' 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.
In order to facilitate the development and have a development environment closer to what the production environment should be (no need to decrease the security level with Access-Control-Allow-Origin), you should have a unique entry point to your frontend and backend, with a unique origin (http://localhost:3000 in your case).
To achieve that, remove all of the Access-Control-* headers, create a src/setupProxy.js file and fill it like this:
const { createProxyMiddleware } = require("http-proxy-middleware");
module.exports = app => {
app.use(
"/api",
createProxyMiddleware ({
target: "http://localhost:8082",
changeOrigin: true
})
);
};
Then install the needed express middleware as a development dependency with npm install --save-dev http-proxy-middleware
Note: this feature is available with react-scripts#2.0.0 and higher.
Finally, replace all of the fetch from the frontend with relative URLs starting with /api
fetch("http://localhost:8082") becomes fetch('/api'))
Something like fetch('http://localhost:8082/some-endpoint') would become fetch('/api/some-endpoint')
For more information about this, please refer to the docs.
Try to refactor your code like this:
const express = require('express')
const app = express()
const cors = require('cors');
const whitelist = ['http://localhost:3000', 'http://localhost:8082'];
const corsOptionsDelegate = (req, callback) => {
var corsOptions;
if (whitelist.indexOf(req.header('Origin')) !== -1) {
corsOptions = { origin: true };
} else {
corsOptions = { origin: false };
}
callback(null, corsOptions);
};
const corsWithOptions = cors(corsOptionsDelegate);
app.route('/')
.options(corsWithOptions, (req, res) => { res.sendStatus(200); })
.get(cors(), (req, res)=>{
res.redirect('http://localhost:3000/test')
});
app.listen(8082)
Try using next function inside app.get:
app.get('/', function (req, res, next) {
res.redirect('http://localhost:3000/test');
next();
})
Also for your ReactJS application (I'm not sure about your implementation, CSR or SSR) you should add two things:
Webpack: proxy for passing CORS
CSR:
devServer: {
...
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
"Access-Control-Allow-Headers": "X-Requested-With, content-type, Authorization"
}
}
SSR: add the above header to webpackDevMiddleware options.
Route:
CSR: for running the project in the dev side use:
devServer: {
historyApiFallback:{
index:'build/index.html'
},
},
for the prod side use spa flag for running, for example for serve use serve -s ./dist or for pm2 run pm2 start ./dist --spa.
SSR: no need to add extra configuration.
try something like this instead:
whitelistedOrigins = ['http://localhost:3000'];
app.use(cors({
origin: whitelistedOrigins,
methods: ['GET', 'PATCH', 'PUT', 'POST', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With'],
}));
you can modify the methods/allowedHeaders keys as you want...
Edit: your backend is :3000, isn't it the problem? the client can't be at 3000 at the same time.
I'm getting "Possible cross-origin (CORS) issue?" error for Spec2 when run this swagger-ui-express app:
const express = require('express');
var cors = require('cors');
const app = express();
const swaggerUi = require('swagger-ui-express');
var options = {
explorer: true,
swaggerOptions: {
urls: [
{
url: 'http://petstore.swagger.io/v2/swagger.json',
name: 'Spec1'
},
{
url: 'http://xxx.xxx.xxx.xxx:xxxxx/swagger.json',
name: 'Spec2'
}
]
}
}
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(null, options));
app.listen(8080, () => console.log(`Listening on port 8080!`))
Neither app.use(cors()) nor app.use(swaggerUi.cors()) helps. How can it be fixed?
I am not sure if this is exact problem you are facing, but the following solution has fixed my issue.
I was using a fetch on an endpoint and the error suggested that the received request has an origin (header) of value null.
I have set up a request interceptor to add an origin header on the request. Example
app.get("/docs", swaggerUi.setup(null, {
swaggerOptions: {
requestInterceptor: function(request){
request.headers.Origin = `http://localhost:3000`;
return request;
},
url: `http://localhost:3000/docs/api-doc`
}
}))
check the link which gives the way to overcome the issue. Also, you can install CORS plugin in chrome if you want and try it.
Having an issue with a firebase function that I need to work with cors. Based off the documentation and all the posts I've read it should be working but seem's like no matter what I try I keep getting the same error:
Failed to load <URL>: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 500.
If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
And here is the corresponding code in my firebase functions index.js file:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const cors = require('cors')({origin: true});
const stripe = require('stripe')('<TEST_KEY>');
const gcs = require('#google-cloud/storage')({keyFilename: '<PATH_TO_KEY>'});
const Easypost = require('#easypost/api');
const api = new Easypost('<TEST_KEY>');
admin.initializeApp(functions.config().firebase);
exports.processOrder = functions.https.onRequest((req, res) => {
cors(req, res, () => {
var body = JSON.parse(req.body);
if (
!body.shipment_id ||
!body.items ||
!body.card
) return res.set('Access-Control-Allow-Origin', '*').send({error: true, message: 'Missing information'});
getPrices(body.items, (err, prices, totalPrice) => {
if (err) return res.set('Access-Control-Allow-Origin', '*').send({error: err, message: "Error"})
// Create a new customer and then a new charge for that customer:
stripe.customers.create({
email: 'test#example.com'
}).then((customer) => {
return stripe.customers.createSource(customer.id, {
source: body.card.token.id
});
}).then((source) => {
return stripe.charges.create({
amount: (totalPrice * 100),
currency: 'usd',
customer: source.customer
});
}).then((charge) => {
return res.set('Access-Control-Allow-Origin', '*').send({error: false, message: "Success"});
}).catch((err) => {
console.log(err);
return res.set('Access-Control-Allow-Origin', '*').send({error: err, message: "Error"});
});
});
});
});
Any help would be greatly appreciated :)
Edit: Just wanted to note: I've tried only setting res.set('Access-Control-Allow-Origin', '*') and not using the cors middleware, and I've tried not setting the header and only using cors. Neither of which worked :(
Solution: As #sideshowbarker said in a comment, my function had an error elsewhere before returning. The Access-Control-Allow-Origin was never even getting set. Once I fixed the error it was all good! Ty!
In node you can use a package to solve this problem. To enable all CORS install the following package:
npm install cors
Then assuming you are using express you can then enable CORS by the following lines of code:
var cors = require('cors');
app.use(cors());
I'm building a React application and I'm trying to make a call to https://itunes.apple.com/search?term=jack+johnson
I have a helper called requestHelper.js which looks like :
import 'whatwg-fetch';
function parseJSON(response) {
return response.json();
}
function checkStatus(response) {
if (response.status >= 200 && response.status < 300) {
return response;
}
const error = new Error(response.statusText);
error.response = response;
throw error;
}
export default function request(url, options) {
return fetch(url, options)
.then(checkStatus)
.then(parseJSON);
}
So I get:
XMLHttpRequest cannot load
https://itunes.apple.com/search?term=jack%20johnson. No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:3000' is therefore not allowed
access.
My express server looks like this:
const ip = require('ip');
const cors = require('cors');
const path = require('path');
const express = require('express');
const port = process.env.PORT || 3000;
const resolve = require('path').resolve;
const app = express();
app.use(cors());
app.use('/', express.static(resolve(process.cwd(), 'dist')));
app.get('*', function(req, res) {
res.sendFile(path.resolve(resolve(process.cwd(), 'dist'), 'index.html'))
});
// Start app
app.listen(port, (err) => {
if (err) {
console.error(err.message);
return false;
}
const divider = '\n-----------------------------------';
console.log('Server started ✓');
console.log(`Access URLs:${divider}\n
Localhost: http://localhost:${port}
LAN: http://${ip.address()}:${port}
${divider}
`);
});
I have tried using mode: 'no-cors' but is not actually what I need since the response is empty.
Am I doing something wrong with this configuration?
The same origin policy kicks in when code hosted on A makes a request to B.
In this case A is your Express app and B is iTunes.
CORS is used to allow B to grant permission to the code on A to read the response.
You are setting up CORS on A. This does nothing useful since your site cannot grant your client side code permission to read data from a different site.
You need to set it up on B. Since you (presumably) do not work for Apple, you can't do this. Only Apple can grant your client side code permission to read data from its servers.
Read the data with server side code instead.