CORS Header Issue between react / express - node.js

I'm having a problem with CORS, despite reading and implementing various solutions on SO.
I have an app that uses Express/NodeJS as an api and React JS as a front end.
In development, the react app http://localhost:3000 is able to talk to the express backend http://localhost:9000with app.use(cors()).
Now I'm trying to use this app in production.
Both apps are kept in separate git repositories.
React is deployed as a static website on aws s3 and works fine.
Node JS is deployed on Elastic Bean Stalk and is in the ready state.
I have a Postgres SQL database attached to the ebs instance(node app) that I'm able to connect to in pgadmin4.
Both apps are using the same base domain in route 53 myproject.com.
Both are configured to listen for https/443. I can hit both URLS https://myproject.com and https://api.myproject.com & they look like how they do in my localhost environment.
When I try to signup a user on my site I run into this error:
Access to XMLHttpRequest at 'https://api.myproject.com/users/signup/' from origin 'https://myproject.com' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Both apps are able to "see" each other but that's about where it ends.
Looking at my code, I can't figure out where the issue is taking place:
server.js
const express = require('express');
const cors = require('cors');
const logger = require('morgan');
const bodyParser = require('body-parser');
require('dotenv').config();
const PORT = process.env.PORT || 9000; // DEV
const app = express();
const corsOptions = {
origin: 'https://myproject.com',
optionsSuccessStatus: 200 // some legacy browsers (IE11, various SmartTVs) choke on 204
}
const allowCrossDomain = function (req, res, next) {
res.header('Access-Control-Allow-Origin', 'https://myproject.com');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
}
app.use(cors());
const { userRouter } = require('./routes/userRouter');
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(allowCrossDomain);
app.use((e, req, res, next) => {
res.header("Access-Control-Allow-Origin", "https://myproject.com");
res.header('Access-Control-Allow-Methods', 'DELETE, PUT, GET, POST');
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
if (e) {
console.log(e);
res.status(500).send(e.message);
}
next();
});
app.use('/users', userRouter);
app.listen(PORT, () => {
console.log(`Express server is listening on PORT ${PORT}.`);
});// - TESTING
What I've tried:
Most of these solutions came from this SO post: Why doesn't adding CORS headers to an OPTIONS route allow browsers to access my API?
Using just app.use(cors());
Using a wildcard * instead of a domain name.
White listing my domain with cors (from this blog post): https://daveceddia.com/access-control-allow-origin-cors-errors-in-react-express/
// Set up a whitelist and check against it:
var whitelist = ['https://myproject.com']
var corsOptions = {
origin: function (origin, callback) {
if (whitelist.indexOf(origin) !== -1) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS'))
}
}
}
// Then pass them to cors:
app.use(cors(corsOptions));
I've also moved app.use(cors()) above my routes as suggested in another StackOverflow post.
At this point, I'm stuck so any help is appreciated so thanks in advance.

Try requiring cors this way:
const cors = require('cors')({
origin: 'https://yourdomain.com',
});
This way you can add origin and then just call app.use(cors()) at the top of the express app
const app = Express();
app.use(BodyParser.json());
app.use(cors);
this is the way I usually get things to work. Another factor you may be dealing with is if the domain hasn't fully propagated yet, this may be causing your regions for aws to not recognize the domain's dns. That's just a theory though.

Related

Unxpect CORS policy error when using auth api from locally

First of all, i have an backend RESTapi running on my ubuntu server on the cloud(works perfectly 100%).
And I also have an frontend webapplication running on the same server(works perferctly aswell), and i can use the login system and all that stuff.
Now my issue: I am deploying the frontend locally at my computer for development purposes, but i still want to have the connection to my backend at the cloud instead of also deploying the backend locally.
Problem is now that when im using the authentication from my local computer i get this error:
Access to fetch at 'http://ip-adress-to-the-backend-at-the-cloud:5000/api/auth' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The 'Access-Control-Allow-Origin' header has a value 'http://*:3000' that is not equal to the supplied origin. Have the server send the header with a valid value, or, if an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
The thing is: it worked perfectly logging in while using the webapp locally at my computer until last week.. Now that i made some changes in my ".env" file, "server.js" and "routes.js" file, it doesnt work.
The strange thing is that i tried removing the changes from those files but still aint working.
Here is my .env file:
APP_PORT=*****
DB_HOST=*****
DB_USER=*****
DB_PASSWORD=******
DB_NAME=******
JWT_SECRET=******
JWT_KEYSECRET=*******
ALLOWED_ORIGIN=http://ipadress_to_both_the_frontend_and_backend:3000
here is my server.js:
const express = require('express');
const app = express();
require('dotenv').config();
if(process.env.JWT_SECRET == undefined || process.env.JWT_KEYSECRET == undefined){
console.log("Fatal error: Secret is not set")
process.exit(1);
}
require('./startup/routes')(app)
require('./startup/database')
app.listen(process.env.APP_PORT, () => {
console.log("Server is running: " + process.env.APP_PORT);
})
and my routes.js:
require('dotenv').config();
const users = require('../api/user/user.router')
const keys = require('../api/keys/keys.router')
const equipmentType = require('../api/equipmenttypes/equipmenttype.router');
const auth = require('../api/authentication/auth.router')
const helmet = require('helmet')
const express = require('express')
module.exports = function (app) {
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static('public'))
app.use(helmet.xssFilter())
app.use(helmet.frameguard())
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', process.env.ALLOWED_ORIGIN);
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With, content-type, x-auth-token, x-api-key');
res.setHeader('Access-Control-Allow-Credentials', true);
next();
})
app.use('/api/user', users)
app.use('/api/auth', auth)
app.use('/api/key', keys)
app.use('/api/equipmenttypes', equipmentType)
}
Firstly, install cors by npm i cors
Add this to your server.js file:
const cors = require("cors");
app.use(cors());
The solution was simple, I changed the line inse my env file this:
ALLOWED_ORIGIN=*
No, this is not a good thing to do, and not secure at all, but now i can accsess the backend api from localhost, and i can optimize my work.

XMLHttpRequest at from origin has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource

I am facing an issue with REST APIs. My front-end is in React and APIs are in Express. I intermittently get below error. I've gone through many other similar posts and tried to add HTTP headers to the response without any luck. These calls works fine from Postman client.
"from origin 'http://localhost:3000' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested
resource."
So, far I've added below lines to populate HTTP response. The MOST annoying part is these errors only happens with certain web services and not others. They all are identically coded so, it makes it difficult to determine why in certain cases it fails.
My server.js (Express REST app) is as per below ...
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const app = express();
const controllers = require('./controllers');
const logger = require('./logger/logger');
const port = 9000;
app.use(bodyParser.urlencoded({ extended: true }))
app.use(bodyParser.json());
app.use(bodyParser.raw());
controllers.init(app);
app.use(cors());
//Listen server on define port
var server = app.listen(port, () => {
logger.info("API Server is running on port " + port);
})
So, far what I've noticed is, when I add the below segment to include HTTP response headers in my controllers (controllers uses services and models to serve requests), the error disappears EVEN if I remove them after first successful call from my React front-end and this is really bizarre. I use Chrome to test my React front-end. Does this mean Chrome browser is caching something esp. when it comes to the origin? I am worried how this will span out in production? has anyone experienced this sort of behaviour?
app.use((req, res, next) => {
res.append('Access-Control-Allow-Origin', "*");
res.append('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.append('Access-Control-Allow-Headers', 'Content-Type');
next();
});
Below are the packages I use for the Express API server ..My React front-end uses "react": "^16.13.1"
"dependencies": {
"body-parser": "^1.19.0",
"cors": "^2.8.5",
"express": "^4.17.1",
ok, just managed to get this work by adding the below segment
controllers.init = function (app) {
app.use((req, res, next) => {
res.append('Access-Control-Allow-Origin', '*');
res.append('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.append('Access-Control-Allow-Headers', 'Content-Type');
next();
});
in my index.js under controllers folder. index.js contains init for all other controllers....see below
(function (controllers) {
var appMenuController = require("./appMenuController");
var applicantTypeController = require("./applicantTypeController");
var permitApplicationController = require("./permitApplicationController");
var campusController = require("./campusController");
var paymentMethodController = require("./paymentMethodController");
var permitTypeController = require("./permitTypeController");
var permitController = require("./permitController");
var permitChangeRequestController = require("./permitChangeRequestController");
var requestTypeController = require("./requestTypeController");
var vehicleController = require("./vehicleController");
controllers.init = function (app) {
app.use((req, res, next) => {
res.append('Access-Control-Allow-Origin', '*');
res.append('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.append('Access-Control-Allow-Headers', 'Content-Type');
next();
});
appMenuController.init(app);
applicantTypeController.init(app);
permitApplicationController.init(app);
campusController.init(app);
paymentMethodController.init(app);
permitTypeController.init(app);
permitController.init(app);
permitChangeRequestController.init(app);
requestTypeController.init(app);
vehicleController.init(app)
}
})(module.exports);
I still don't get it i.e. why Chrome (even Firefox) won't allow HTTP REQ\RESP comms between 2 localhosts on the same host i.e. localhost. Where is a threat in responses originating from the localhost? unless I misunderstood CORS

No 'Access-Control-Allow-Origin' header is present on the requested resource in angular app

I've angular cli project that hosted in azure and I'm making API call to different domain (in Zoho creator) so I have CROS issue I tried some solutions with no luck.
The error is
"Access to XMLHttpRequest at "https://xxxxxxx" from origin "https://yyyyyy" has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource."
I use expressJS as my backend and I tried to add headers but it seems not working I don't know what I'm missing
APP.JS
const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const http = require('http');
const app = express();
// parse application/x-www-form-urlencoded
var cors = require('cors');
// Use this after the variable declaration
app.use(cors({origin: '*'}));
// parse application/json
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
// Angular DIST output folder
app.use(express.static(path.join(__dirname, 'dist')));
// Send all other requests to the Angular app
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'dist/index.html'));
});
// Add headers
app.use(function (req, res, next) {
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:5000');
// 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();
});
//Set Port
const port = process.env.PORT || '5000';
app.set('port', port);
const server = http.createServer(app);
server.listen(port, () => console.log(`Running on localhost:${port}`));
I don't recognize exactly what It's happening but there's something that it makes me noise.
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:5000');
This code indicate that you can only receive requests from http://localhost:5000. Are you trying to consume it from http://localhost:5000? I don't think so because the port 5000 is being used by node.js. if you want to use it, you must set Access-Control-Allow-Origin to the Server or Site where you're trying consume it from.
Example, I have a application in Angular in my machine using the port 4200, so the request header should be:
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:4200');
Or, you can use * to allow everything but It's not secure.
res.setHeader('Access-Control-Allow-Origin', '*');

Angular client enable CORS

CORS is fine on server and works as intended. I tried sending requests to my server's REST API with the angular HTTPClient and I receive a CORS error.
Why is this an error if CORS is enabled on the server? Shouldn't it be fine on the client?
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:3000/api/blah/blah (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
How can I enable CORS on this request please.....
For future refrence it was "Davids" answer that assisted me, the cors was not added before all routing.
"..... Meaning, before the route is defined."
so right after ...
var app = express();
I just use...
app.use(cors());
A little intro:
Cross-Origin Resource Sharing aka CORS is a mechanism that uses additional HTTP headers to tell browsers to give a web application running at one origin (e.g. http://localhost:3000), access to selected resources from a different origin (e.g. http://localhost:8080). In other words, a web app executes a cross-origin HTTP request when it requests a resource that has a different origin (domain, protocol, or port) from its own. For security reasons, browsers restrict cross-origin HTTP requests initiated from scripts.
The Access-Control-Allow-Origin header determines which origins are allowed to access server resources over CORS.
How to Fix CORS Issues?
You can do it yourself by creating an Express middleware. Here's the appropriate code snippet:
// Enable CORS for specific origins:
app.use((req, res, next) => {
// Allow multiple predefined origins
const allowedOrigins = ["https://deployed-app.com", "http://localhost:3000"];
const origin = req.headers.origin; // extract the origin from the header
if (allowedOrigins.indexOf(origin) > -1) { // if the origin is present in our array
res.setHeader("Access-Control-Allow-Origin", origin); // set the CORS header on the response
}
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept"
);
next(); // move on to the next middleware
});
Alternatively, you can accept all requests,
but this option is only appropriate if you're in development or if your API is public :)
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "*");
next();
});
Additionally, there's an Express CORS middleware and this is how you would use it:
npm install cors --save
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!'})
});
const port = process.env.PORT || 8080;
app.listen(port, () => {
console.log(`CORS-enabled server is up on ${port}`);
});
Enable CORS for a Single Route
const express = require('express');
const cors = require('cors');
const app = express();
app.get('/products/:id', cors(), (req, res, next) => {
res.json({msg: 'This is CORS-enabled for a Single Route'})
});
const port = process.env.PORT || 8080;
app.listen(port, () => {
console.log(`CORS-enabled server is up on ${port}`);
});
Important gotcha: When it comes to Express middleware, the order is very important. So make sure CORS is enabled before any other controller/ route/ middleware which may depend on it.
You dont need to enable cors in angular, this is a server side issue. See:
https://stackoverflow.com/a/29548846/4461537

Socket.io - Origin is not allowed access

I'm having this weird problem with socket.io. I have an express app which I run on port 5000. I have configured socket.io like this:
const app = require('../index');
const http = require('http');
const server = http.Server(app);
const io = require('socket.io')(server);
io.on('connection', function (socket) {
console.log('User has connected');
socket.emit('connect', {
message: 'Hello World'
});
});
Then I import this piece of code into my index.js file like this:
const express = require('express');
const app = module.exports = express();
const bodyParser = require('body-parser');
const cors = require('cors');
const request = require('request');
const boxRoutes = require('./routes/v1/boxRoutes');
const bidRoutes = require('./routes/v1/bidRoutes');
// use body parser so we can get info from POST and/or URL parameters
app.use(bodyParser.urlencoded({ limit: '10mb', extended: true }));
app.use(bodyParser.json({ limit: '10mb' }));
require('./services/usersClass');
// cors set up
app.use(cors());
app.use(function (req, res, next) {
console.log('Headers Middleware Called');
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, DELETE');
// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'origin, x-requested-with, content-type, accept, x-xsrf-token', 'token');
// 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);
// Request headers you wish to expose
res.setHeader('Access-Control-Expose-Headers', false);
next();
});
// Middleware to authenticate the requests to this service
app.use(function(req, res, next) {
console.log('Auth Middleware Called');
if(!req || !req.headers['authorization']) return res.sendStatus(401);
const token = req.headers['authorization'].split(' ')[1];
request.post(
'http://localhost:4000/api/v1/users/auth',
{
headers: {
'Authorization': `Bearer ${token}`
}
},
function (error, response, body) {
if (!error && response.statusCode == 200) {
const data = JSON.parse(body);
res.locals.user = data.user;
next();
} else {
console.log('Request has failed. Please make sure you are logged in');
res.sendStatus(401);
}
}
);
});
app.use('/api/v1/boxes/', boxRoutes);
app.use('/api/v1/bids/', bidRoutes);
// disable 'powered by'
app.disable('x-powered-by');
app.listen(5000, () => {
console.log('Trading service is running on port 5000');
});
Now, in my client code, I try to establish socket.io connection when the user logs in. Everytime I try to connect to the server, I get the following error:
Failed to load
http://localhost:5000/socket.io/?EIO=3&transport=polling&t=MA_9wXE:
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'. Origin 'http://localhost:3000' is therefore not allowed
access. The credentials mode of requests initiated by the
XMLHttpRequest is controlled by the withCredentials attribute.
I don't understand why the connection fails. I have configured Access-Control-Allow-Origin to my client domain but it still fails.
You can use cors npm module. It will fix your problem.
var cors = require('cors')
var app = express()
app.use(cors({origin: '*'}))
start '*' means allow every origins. You can type spesific origin too.
I've seen this problem before, but never seen it manifested as a cross origin issue. You are creating two separate http servers. One you are making your express server and the other you are making your socket.io server. The code you show only actually starts the express server and you show no code that actually starts your socket.io server.
Here's where you create these two separate servers:
const server = http.Server(app); // creates the http server you use for socket.io
app.listen(5000, () => {...}); // creates the http server you use with Express
Inside of app.listen(), it creates it's own new server and starts it. Your other server is never started (at least per the code you show here).
When you probably want to do is to make your socket.io server use the same server as your express server and then you should be able to connect just fine without any CORs issues.
If you want to use app.listen(), it will return the server object that it created and you need to use that to initialize socket.io.
If you want to use the other server, then you need to share that with your express initialization code so it can use that one.

Resources