Socket.io - Origin is not allowed access - node.js

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.

Related

Node Express Cors issue

I cant figure why the cors express middleware wont work. cors, express, and ejs are all saved in package.json. The app works fine if I add corsanywhere proxy on the front end but id like to work around this on the server side. any help much appreciated I've been stuck on this.
the api is in the get View/index path
the error is:
Access to fetch at 'https://api.darksky.net/forecast/' 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.
const express = require('express');
const app = express();
const ejs = require('ejs');
const cors = require('cors');
const PORT = process.env.PORT || 3000;
// app.use((req, res, next) => {
// res.header('Access-Control-Allow-Origin', '*')
// res.header('Access-Control-Allow-Headers', 'Origin', 'X-Requested-With')
// next();
// });
app.use(cors());
app.use(express.static(__dirname + '/Public'));
app.set('view engine', 'ejs');
app.get('/', cors(), (req, res) => {
res.render(__dirname + '/Views/index')
});
app.listen(PORT, () => {
console.log(`server is listening on ${PORT}`)
});
client side:
it works with the ${proxy} in there but id like to get rid of that
if(navigator.geolocation){
navigator.geolocation.getCurrentPosition(position => {
long = position.coords.longitude;
lat = position.coords.latitude;
var proxy = 'https://cors-anywhere.herokuapp.com/'
var api = `${proxy}https://api.darksky.net/forecast/042750f3abefefdfe2c9d43cf33ce576/${lat},${long}`;
fetch(api)
.then(response => {
return response.json();
})
.then(data => {
let {temperature, summary, icon,} = data.currently;
temperatureDegree.textContent = Math.floor(temperature);
temperatureDescription.textContent = summary;
locationTimezone.textContent = data.timezone;
setIcons(icon, document.querySelector('.icon'
w
``````
So, if you're trying to access some other service https://api.darksky.net/forecast/ (that you don't control) from your web page, then there is nothing you can do to make CORs work for that. It's up to the api.darksky.net server to decide if CORs is allowed or not. You can't change that.
You could make a request from your web page to your server to ask it to get some data from api.darksky.net for you and then return it back to your webpage (working as a simple proxy). Your server is not subject to any CORs limitations when accessing api.darksky.net. Only browsers are limited by CORs.
And, as you've found, you can also use a proxy service that enables CORs and fetches data for you.
Let's suppose you want to proxy the parts of the darksky API, you could do something simple like this:
const express = require('express');
const app = express();
const request = require('request');
const apiRouter = express.Router();
// maps /api/forecast/whatever to http://api.darksky.net/forecast/developerKey/whatever
// and pipes the response back
const apiKey = "yourAPIKeyHere";
apiRouter.get("/*", (req, res, next) => {
// parse out action and params
// from an incoming URL of /api/forecast/42.3601,-71.0589
// the /api will be the root of the router (so not in the URL here)
// "forecast" will be the action
// "42.3601,-71.0589" will be the params
let parts = req.path.slice(1).split("/"); // split into path segments, skipping leading /
let action = parts[0]; // take first path segment as the action
let params = parts.slice(1).join("/"); // take everything else for params
request({
uri: `https://api.darksky.net/${action}/${apiKey}/${params}`,
method: "get"
}).pipe(res);
});
app.use("/api", apiRouter);
app.listen(80);
Now, when you send this server, this request:
/api/forecast/42.3601,-71.0589
it will request:
https://api.darksky.net/forecast/yourAPIKeyHere/42.3601,-71.0589
and pipe the result back to the caller. I ran this test app and it worked for me. While I didn't see anything other than forecast URLs in the darksky.net API, it would work for anything of the format /api/someAction/someParams.
Note, you probably do NOT want to enable CORS on your server because you don't want other people's web pages to be able to use your proxy. And, since you're just sending requests to your own server now, you don't need CORS to be able to do that.

CORS Header Issue between react / express

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.

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', '*');

what is the solution to connect socketio with express with "Access-Control-Allow-Origin", "*"

I want to connect with socket.io to a backend that uses express.
the backend is used as api for other functionalities. So, I use some middleware to add headers to express (you could see that in the code).
the problem is that the socketio on the client side gives the following error:
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'.
but I need to keep the '*' to allow all users from any where to access my api.
var express = require('express'); var server = express();
var app = require('http').Server(server);
var io = require('socket.io')(app);
io.set( "Access-Control-Allow-Origin", "*" );
require('./controllers/watsonIoT.controller').startWatson(io);
server.use(function(request, response, next) { // configuration of headers
response.header("Access-Control-Allow-Origin", "*");
response.header("Access-Control-Allow-Headers", "Content-Type, x-auth");
response.header("Access-Control-Allow-Methods", "GET,POST,DELETE,PUT")
next();
})
.use('/gui', express.static('views'))
.use(bodyParser.json())
.use('/api', mainRouter)
.get('*', (req, res) => res.redirect('/'))
.listen(PORT,function(){
console.log("Starting ... port: "+ PORT);
// startWatson();
});

NodeJS Express App not calling app.use

I have a NodeJS app I am using as a game server.
I am trying to setup CORS with it, but app.use doesn't seem to be getting called.
Anyone know why?
var util = require("util"); // Utility resources (logging, object inspection, etc)
var fs = require('fs');
var express = require("express");
var app = express();
var port = 3000;
app.use(function (req, res, next) {
// these never get printed out:
util.log( "app.use adding Access-Control-Allow-Origin" );
console.log( "app.use adding Access-Control-Allow-Origin" );
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', 'https://example.com');
// 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();
});
var server = app.listen(port, function(){
console.log('CORS-enabled web server listening on port ' + port);
});
var io = require('socket.io').listen(server);
Checkout the npm cors package. https://www.npmjs.com/package/cors
Example usage where all requests will be CORS enabled:
var express = require('express')
, cors = require('cors')
, app = express();
app.use(cors());
app.get('/my_API_URL/: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');
});
On their page they also got other examples where the CORS are only enabled on a single route.
Also, just wondering how are you testing your application? You haven't defined any routes in the example code.
As pointed out in the comment section, #Nitzan Wilnai is not doing REST API, apologise for the confusion. It is suppose to be a simple server that listens on a certain port, so for this case you might not need express at all. Did some research and this solution came out;
io.configure('development', function(){
io.set('origins', '*:*');
}
OR
io.set( 'origins', '*domain.com*:*' );
References:
Socket.io doesn't set CORS header(s)
Just in case you are trying to build a chat program. Here is an example project;
https://github.com/socketio/socket.io

Resources