installing Socket.IO on NodeJs server - javascript

I would use Socket.IO . I have read the official documentation and tried to do the same thing so I create my server :
// server.js
// BASE SETUP
// =============================================================================
// call the packages we need
var express = require("express"); // call express
var app = express();
var bodyParser = require("body-parser");
// define our app using express
var routerProj = require("./routes/ajoutProj");
var mongoose = require("mongoose");
mongoose.Promise = global.Promise;
mongoose.connect("mongodb://localhost:27017", {
useMongoClient: true
/* other options */
}); // connect to our database
mongoose.connection.on("error", function(error) {
console.log("error", error);
});
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "GET, POST, PUT ,DELETE");
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept"
);
next();
});
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use("/api/proj", routerProj);
app.get("/", function(req, res) {
res.sendFile(__dirname + "../src/index.html");
});
// Chargement de socket.io
// Quand un client se connecte, on le note dans la console
io.sockets.on("connection", function(socket) {
console.log("User is coonected!");
});
var port = process.env.PORT || 8081; // set our port
// START THE SERVER
// =============================================================================
var server = app.listen(port);
var io = require("socket.io").listen(server);
My angular index.htlm file is in this path relatively to server.js : ../src/app/index.html
When I restart server and angular app, then open new window I don't have a message on the servers's console telling me that a user is connected knowing that angular is making calls to the server api
I don't know where is the problem
Update
I have added socket.IO on client side
import { Injectable } from "#angular/core";
import { NouveauProjet } from "./models/nouveau-projet";
import { HttpClient, HttpResponse } from "#angular/common/http";
import { Observable } from "rxjs/Observable";
import "rxjs/add/operator/map";
import "rxjs/add/operator/catch";
import * as io from "socket.io-client";
#Injectable()
export class AjoutprojService {
apiURL = "http://127.0.0.1:8080/api/proj/projets";
private socket = io("http://localhost:8081");
constructor(private http: HttpClient) {}
getAllProj(): Observable<NouveauProjet[]> {
return this.http.get<NouveauProjet[]>(
"http://127.0.0.1:8081/api/proj/projets"
);
}
getProj(id): Observable<NouveauProjet[]> {
return this.http.get<NouveauProjet[]>(
"http://127.0.0.1:8081/api/proj/nouvProjs/${id}"
);
}
addProj(nouveauProjet: NouveauProjet): Observable<any> {
return this.http.post<NouveauProjet[]>(
"http://127.0.0.1:8081/api/proj/projets",
nouveauProjet
);
}
}
/* private handleError ( response: HttpResponse): Observable<any> {
let errorMessage= `${response.status} - ${response.statusText}`;
return Observable.throw(errorMessage);
}*/
Restarted server , client , no result
Update 2
after adding socket.on('event', function(evt){ console.log(evt); });I get those errors :
Failed to load http://localhost:8081/socket.io/?EIO=3&transport=polling&t=M2tXQXh: 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:4200' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
GET http://localhost:8081/socket.io/?EIO=3&transport=polling&t=M2tXQXh 404 (Not Found)
If I set res.header("Access-Control-Allow-Origin", "*"); To res.header("Access-Control-Allow-Origin", "http://localhost:4200");
I get this error
Failed to load http://localhost:8081/socket.io/?EIO=3&transport=polling&t=M2uichH: 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'. Origin 'http://localhost:4200' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
I notice a difference in the error . Here The value of the 'Access-Control-Allow-Credentials' header in the response is ''
When I put localhost:8081 : The value of the 'Access-Control-Allow-Credentials' header in the response is 'localhost:8081'

Based on the error, I suspect the problem is that you are using a wildcard in your server's CORS response header:
res.header("Access-Control-Allow-Origin", "*");
Why is this a problem? From the docs:
When responding to a credentialed request, the server must specify an origin in the value of the Access-Control-Allow-Origin header, instead of specifying the "*" wildcard.
Here is a relevant StackOverflow answer:
This is a part of security, you cannot do that. If you want to allow credentials then your Access-Control-Allow-Origin must not use *. You will have to specify the exact protocol + domain + port.

Related

Problem facing in socket.io in sending 'Hello World' to console [duplicate]

I'm using node and socket.io to write a chat application. It works fine on Chrome but mozilla gives an error to enable the Cross-Origin Requests.
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://waleedahmad.kd.io:3000/socket.io/?EIO=2&transport=polling&t=1401964309289-2&sid=1OyDavRDf4WErI-VAAAI. This can be fixed by moving the resource to the same domain or enabling CORS.
Here's my code to start node server.
var express = require('express'),
app = express(),
server = require('http').createServer(app),
io = require('socket.io').listen(server),
path = require('path');
server.listen(3000);
app.get('/', function(req, res) {
res.sendfile(__dirname + '/public/index.html');
});
On the client side.
var socket = io.connect('//waleedahmad.kd.io:3000/');
Script tag on HTML page.
<script type="text/javascript" src="//waleedahmad.kd.io:3000/socket.io/socket.io.js"></script>
I'm also using .htaccess file in the app root directory. (waleedahmad.kd.io/node).
Header add Access-Control-Allow-Origin "*"
Header add Access-Control-Allow-Headers "origin, x-requested-with, content-type"
Header add Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"
Simple Server-Side Fix
❗ DO NOT USE "socketio" package... use "socket.io" instead. "socketio" is out of date. Some users seem to be using the wrong package.
❗ SECURITY WARNING: Setting origin * opens up the ability for phishing sites to imitate the look and feel of your site and then have it work just the same while grifting user info. If you set the origin, you can make their job harder, not easier. Also looking into using a CSRF token as well would be a great idea.
socket.io v3
docs: https://socket.io/docs/v3/handling-cors/
cors options: https://www.npmjs.com/package/cors
const io = require('socket.io')(server, {
cors: {
origin: '*',
}
});
socket.io < v3
const io = require('socket.io')(server, { origins: '*:*'});
or
io.set('origins', '*:*');
or
io.origins('*:*') // for latest version
* alone doesn't work which took me down rabbit holes.
I am using v2.1.0 and none of the above answers worked for me.
This did though:
import express from "express";
import http from "http";
const app = express();
const server = http.createServer(app);
const sio = require("socket.io")(server, {
handlePreflightRequest: (req, res) => {
const headers = {
"Access-Control-Allow-Headers": "Content-Type, Authorization",
"Access-Control-Allow-Origin": req.headers.origin, //or the specific origin you want to give access to,
"Access-Control-Allow-Credentials": true
};
res.writeHead(200, headers);
res.end();
}
});
sio.on("connection", () => {
console.log("Connected!");
});
server.listen(3000);
You can try to set origins option on the server side to allow cross-origin requests:
io.set('origins', 'http://yourdomain.com:80');
Here http://yourdomain.com:80 is the origin you want to allow requests from.
You can read more about origins format here
For anyone looking here for new Socket.io (3.x) the migration documents are fairly helpful.
In particular this snippet:
const io = require("socket.io")(httpServer, {
cors: {
origin: "https://example.com",
methods: ["GET", "POST"],
allowedHeaders: ["my-custom-header"],
credentials: true
}
});
If you are getting io.set not a function or io.origins not a function, you can try such notation:
import express from 'express';
import { Server } from 'socket.io';
const app = express();
const server = app.listen(3000);
const io = new Server(server, { cors: { origin: '*' } });
I tried above and nothing worked for me. Following code is from socket.io documentation and it worked.
io.origins((origin, callback) => {
if (origin !== 'https://foo.example.com') {
return callback('origin not allowed', false);
}
callback(null, true);
});
I just wanted to say that after trying a bunch of things, what fixed my CORS problem was simply using an older version of socket.io (version 2.2.0). My package.json file now looks like this:
{
"name": "current-project",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"devStart": "nodemon server.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"socket.io": "^2.2.0"
},
"devDependencies": {
"nodemon": "^1.19.0"
}
}
If you execute npm install with this, you may find that the CORS problem goes away when trying to use socket.io. At least it worked for me.
In my case, I'm using an HTTP server and socket.io
Error:
var http = require('http').Server(app);
var io = require('socket.io')(http);
Solution:
var http = require('http').Server(app);
var io = require('socket.io')(http, { cors: { origin: '*' } });
client:
const socket = io('https://sms-server.cedrick1227.repl.co/', { });
server:
const io = new socket.Server(server, { cors: { origin: '*' } });
it works like a charm for me.
After read a lot of subjetcs on StakOverflow and other forums, I found the working solution for me. This solution is for working without Express.
here are the prerequisites.
call your js script (src=) form the same server the socket will be connected to (not CDN or local call)
ensure to have the same version of socket.io on server and client side
node modules required : fs, path, socket.io and winston for logging
Install Let's encrypt certbot and generate certificate for your domain or buy a SSL certificate
jQuery declared before socket.io.js on client side
UTF-8 encoding
SERVER SIDE
// DEPENDENCIES
var fs = require('fs'),
winston = require('winston'),
path = require('path');
// LOGS
const logger = winston.createLogger({
level : 'info',
format : winston.format.json(),
transports: [
new winston.transports.Console({ level: 'debug' }),
new winston.transports.File({ filename: 'err.log', level: 'err' }),
new winston.transports.File({ filename: 'combined.log' })
]
});
// CONSTANTS
const Port = 9000,
certsPath = '/etc/letsencrypt/live/my.domain.com/';
// STARTING HTTPS SERVER
var server = require('https').createServer({
key: fs.readFileSync(certsPath + 'privkey.pem'),
cert: fs.readFileSync(certsPath + 'cert.pem'),
ca: fs.readFileSync(certsPath + 'chain.pem'),
requestCert: false,
rejectUnauthorized: false
},
(req, res) => {
var filePath = '.' + req.url;
logger.info('FILE ASKED : ' + filePath);
// Default page for visitor calling directly URL
if (filePath == './')
filePath = './index.html';
var extname = path.extname(filePath);
var contentType = 'text/html';
switch (extname) {
case '.js':
contentType = 'text/javascript';
break;
case '.css':
contentType = 'text/css';
break;
case '.json':
contentType = 'application/json';
break;
case '.png':
contentType = 'image/png';
break;
case '.jpg':
contentType = 'image/jpg';
break;
case '.wav':
contentType = 'audio/wav';
break;
}
var headers = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'OPTIONS, POST, GET',
'Access-Control-Max-Age': 2592000, // 30 days
'Content-Type': contentType
};
fs.readFile(filePath, function(err, content) {
if (err) {
if(err.code == 'ENOENT'){
fs.readFile('./errpages/404.html', function(err, content) {
res.writeHead(404, headers);
res.end(content, 'utf-8');
});
}
else {
fs.readFile('./errpages/500.html', function(err, content) {
res.writeHead(500, headers);
res.end(content, 'utf-8');
});
}
}
else {
res.writeHead(200, headers);
res.end(content, 'utf-8');
}
});
if (req.method === 'OPTIONS') {
res.writeHead(204, headers);
res.end();
}
}).listen(port);
//OPENING SOCKET
var io = require('socket.io')(server).on('connection', function(s) {
logger.info("SERVER > Socket opened from client");
//... your code here
});
CLIENT SIDE
<script src="https://my.domain.com:port/js/socket.io.js"></script>
<script>
$(document).ready(function() {
$.socket = io.connect('https://my.domain.com:port', {
secure: true // for SSL
});
//... your code here
});
</script>
This could be a certification issue with Firefox, not necessarily anything wrong with your CORS. Firefox CORS request giving 'Cross-Origin Request Blocked' despite headers
I was running into the same exact issue with Socketio and Nodejs throwing CORS error in Firefox. I had Certs for *.myNodeSite.com, but I was referencing the LAN IP address 192.168.1.10 for Nodejs. (WAN IP address might throw the same error as well.) Since the Cert didn't match the IP address reference, Firefox threw that error.
Alright I had some issues getting this to work using a self signed cert for testing so I am going to copy my setup that worked for me. If your not using a self signed cert you probably wont have these issues, hopefully!
To start off depending on your browser Firefox or Chrome you may have different issues and I'll explain in a minute.
First the Setup:
Client
// May need to load the client script from a Absolute Path
<script src="https://www.YOURDOMAIN.com/node/node_modules/socket.io-client/dist/socket.io.js"></script>
<script>
var options = {
rememberUpgrade:true,
transports: ['websocket'],
secure:true,
rejectUnauthorized: false
}
var socket = io.connect('https://www.YOURDOMAIN.com:PORT', options);
// Rest of your code here
</script>
Server
var fs = require('fs');
var options = {
key: fs.readFileSync('/path/to/your/file.pem'),
cert: fs.readFileSync('/path/to/your/file.crt'),
};
var origins = 'https://www.YOURDOMAIN.com:*';
var app = require('https').createServer(options,function(req,res){
// Set CORS headers
res.setHeader('Access-Control-Allow-Origin', 'https://www.YOURDOMAIN.com:*');
res.setHeader('Access-Control-Request-Method', '*');
res.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET');
res.setHeader('Access-Control-Allow-Headers', '*');
if ( req.method === 'OPTIONS' || req.method === 'GET' ) {
res.writeHead(200);
res.end();
return;
}
});
var io = require('socket.io')(app);
app.listen(PORT);
For development the options used on the client side are ok in production you would want the option:
rejectUnauthorized: false
You would more than likely want set to "true"
Next thing is if its a self signed cert you will need to vist your server in a separate page/tab and accept the cert or import it into your browser.
For Firefox I kept getting the error
MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT
The solution for me was to add the following options and accepting the cert in a different page/tab.
{
rejectUnauthorized: false
}
In Chrome I had to open another page and accept the cert but after that everything worked fine with out having to add any options.
Hope this helps.
References:
https://github.com/theturtle32/WebSocket-Node/issues/259
https://github.com/socketio/engine.io-client#methods
I am facing problem while making an chat app using socket.io and node.js & React. Also this issue is not spacefic to Firefox browser, i face same issue in Edge & Chrome also.
"Cross-Origin request is blocked and it is used by some other resources..."
Then i download cors in project directory and put it in the server file index.js as below: To download simply type command using node.js :
npm install cors
const cors = require('cors');
app.use(cors());
This will allow CORS to used by different resources in the files and allow cross origin request in the browser.
For those using socket.io >= v4.4.0
Because I wanted needed the CORS option only for local development, nothing worked here for me.
The solution that I implemented, backend-side :
const io = require("socket.io")(server, {
path: '/api/socket.io',
});
if (process.env.NODE_ENV === 'development') {
io.engine.on('initial_headers', (headers, req) => {
headers['Access-Control-Allow-Origin'] = 'http://localhost:3000';
headers['Access-Control-Allow-Credentials'] = true;
});
io.engine.on('headers', (headers, req) => {
headers['Access-Control-Allow-Origin'] = 'http://localhost:3000';
headers['Access-Control-Allow-Credentials'] = true;
});
}
I was also struggling with this issue until i saw Documentation says: "You can't set 'withCredentials' to true with origin: *, you need to use a specific origin:". So my code looks like this, hope is useful:
WEB CLIENT
const { io } = require("socket.io-client");
const socket = io("localhost:3000", {
extraHeaders: {
"my-custom-header": "abcd"
}
});
SERVER
var express = require('express');
const app = express();
const http = require('http');
const httpServer = http.createServer(app);
const io = require("socket.io")(httpServer, {
cors: {
origin: '*',
methods: ["GET", "POST"],
}
});
Take a look at this:
Complete Example
Server:
let exp = require('express');
let app = exp();
//UPDATE: this is seems to be deprecated
//let io = require('socket.io').listen(app.listen(9009));
//New Syntax:
const io = require('socket.io')(app.listen(9009));
app.all('/', function (request, response, next) {
response.header("Access-Control-Allow-Origin", "*");
response.header("Access-Control-Allow-Headers", "X-Requested-With");
next();
});
Client:
<!--LOAD THIS SCRIPT FROM SOMEWHERE-->
<script src="http://127.0.0.1:9009/socket.io/socket.io.js"></script>
<script>
var socket = io("127.0.0.1:9009/", {
"force new connection": true,
"reconnectionAttempts": "Infinity",
"timeout": 10001,
"transports": ["websocket"]
}
);
</script>
I remember this from the combination of stackoverflow answers many days ago; but I could not find the main links to mention them
Here is the solution from the official documentation:
Since Socket.IO v3, you need to explicitly enable Cross-Origin Resource Sharing (CORS).
const io = require("socket.io")(httpServer, {cors: {
origin: "https://example.com", // or "*"
methods: ["GET", "POST"]}});
The combination that works for me is:
socketio = require('socket.io')(http, {
origins: process.env.WEB_URL, // http(s)://...
cors: {
origin: process.env.WEB_URL,
credentials: true
}
}).listen(process.env.SOCKET_PORT) // 8899
app.set('socketio', socketio)
Use following on the server side:
const express = require("express");
const cors = require("cors");
const http = require("http");
const app = express();
app.use(express.json());
app.use(cors());
const server = http.createServer(app);
const socket = require("socket.io")(server, {
cors: {
origin: "*",
methods: ["GET", "POST"],
},
});
socket.on("connection", (socket) => {
console.log("socket connection : ", socket.id);
});
server.listen(3001, () => {
console.log("server has started!");
});
i simply updated the version of socket.io from 2.x.x to 4.1.2 for backend and did the same ie. updated the version of socket.io-client at frontend from 2.x.x to 4.1.2 ....And it worked
So, basically in v2, the Socket.IO server automatically added the necessary headers to allow Cross-Origin Resource Sharing (CORS) therefor there was no problem for connection between client and server. But this behavior, while convenient, was not great in terms of security, because it meant that all domains were allowed to reach your Socket.IO server.
In v3 and above versions the CORS is disabled by default. Therefor you need to explicitly enable them on your server side script.
Example of my code:
In v2 of socket.io the server script looked like :
const io = require('socket.io')(8000);
But in v3 and above versions this code becomes to :
const io = require('socket.io')(8000, {
cors: {
origin: ['http://localhost:5500'],
},
});
// Remember by setting cors you allow you client to communicate with the socket server
// In this case 8000 is my port on which my socket connection is running and 5500 is my port where my client files are hosted.
// Socket connection runs on a different port and your client files on different
// Also you need to install socket.io-client where you have installed your socket.io modules
For more clarification I'm adding my files
This is my HTML File :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="http://localhost:8000/socket.io/socket.io.js"" content="text/javascript"></script>
<script src="javascript/client.js"></script>
<link rel="stylesheet" href="css/style.css">
<title>Chat App</title>
</head>
<body>
</body>
</html>
Here is my javascript/client.js
const socket = io('http://localhost:8000/');
And this is server/server.js
const io = require('socket.io')(8000, {
cors: {
origin: ['http://localhost:5500'],
},
});
io.on('connection', socket =>{
console.log(socket.id);
});
// If you still can't get it more detailed information can be seen on https://socket.io/docs/v4/migrating-from-2-x-to-3-0/#CORS-handling
// Also a video from which i got this solution https://youtu.be/ZKEqqIO7n-k
I had the same problem and any solution worked for me.
The cause was I am using allowRequest to accept or reject the connection using a token I pass in a query parameter.
I have a typo in the query parameter name in the client side, so the connection was always rejected, but the browser complained about cors...
As soon as I fixed the typo, it started working as expected, and I don't need to use anything extra, the global express cors settings is enough.
So, if anything is working for you, and you are using allowRequest, check that this function is working properly, because the errors it throws shows up as cors errors in the browser. Unless you add there the cors headers manually when you want to reject the connection, I guess.
Using same version for both socket.io and socket.io-client fixed my issue.
Sometimes this issue is faced when the node server stoped.
So, check if your node server working ok.
Then you can use
io.set('origins', 'http://yourdomain.com:PORT_NUMBER');
I used version 2.4.0 of socket.io in easyRTC and used the following code in server_ssl.js which worked for me
io = require("socket.io")(webServer, {
handlePreflightRequest: (req, res) => {
res.writeHead(200, {
"Access-Control-Allow-Origin": req.headers.origin,
"Access-Control-Allow-Methods": "GET,POST,OPTIONS",
"Access-Control-Allow-Headers": "Origin, X-Requested-With, Content-Type, Accept, Referer, User-Agent, Host, Authorization",
"Access-Control-Allow-Credentials": true,
"Access-Control-Max-Age":86400
});
res.end();
}
});
If you get socket.io app working on Chrome, Safari and other browsers but you still encounter CORS issues in Firefox, and you are using a self-signed certificate, then the problem is that Firefox does not accept self-signed certificates by default, and you have to add an exception by going to Firefox's Preferences > Certificates > View Certificates > Add Exception.
If you don't do this, then Firefox shows the error you posted which is misleading, but deep within its Developer Tools, you will find this error: MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT. This indicates that Firefox is not accepting the certificate at all because it is self-signed.
const options = {
cors: {
origin:
String(process.env.ORIGINS_STRING) === "ALL"
? true
: String(process.env.ORIGINS_STRING).split(","),
methods: ["GET", "PUT", "POST", "DELETE"],
allowedHeaders: [
"Access-Control-Allow-Headers",
"X-Requested-With",
"X-Access-Token",
"Content-Type",
"Host",
"Accept",
"Connection",
"Cache-Control",
],
credentials: true,
optionsSuccessStatus: 200,
},
};
in .env file :
ORIGINS_STRING=ALL
or
ORIGINS_STRING=http://localhost:8080,http://localhost:8081
I was working with socket.io: 4.2.x, node: 14.17.x & #hapi/hapi: 20.1.x.
After trying multiple ways as mentioned in other answers, I found that the only working solutions for these version is:
const io = require('socket.io')(server.listener, { cors: { origin: '*' } });
Please make sure you have { cors: { origin: '*' } } in the options object.
I am using SocketIO with implicit http server and I am using v4.4 of socket io, I had to do it like this in the server:
const { Server } = require("socket.io");
const io = new Server(PORT, {})
io.engine.on("headers", (headers, req) => {
headers["Access-Control-Allow-Origin"] = "http://yourdomain.com"
headers["Access-Control-Allow-Headers"] = "origin, x-requested-with, content-type"
headers["Access-Control-Allow-Methodsn"] = "PUT, GET, POST, DELETE, OPTIONS"
})
const io = require('socket.io')(server, {
cors: {
origin: ['https://example.com','http://example.com','ip-address'],
}
});
Dont use origin: '*' it is a big security mistake!
origin can be used like an array with diffrent entry types:
URI with protocols like http/https
IP Address
Environment variables like process.env.WEB_URL

Reaction request with axes for Node.js, problem in CORS

I am creating a project where your back-end localhost:3333 is developed in node.js and the front-end in react localhost:3000.
When I go to access the API without any type of token or validation, it works perfectly, however when using token to validate accesses, there are some errors in CORS.
When I click on a button in the "Login" application to access the login, there is still no token, so I can make this request successfully, but in the next ones, where the token is requested, the following error occurs:
>Access to XMLHttpRequest at 'http://localhost:3333/processo' from origin 'http://localhost:3000' has been blocked by CORS policy: Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight response.
>GET http://localhost:3333/cliente net::ERR_FAILED
>Uncaught (in promise) Error: Network Error
at createError (createError.js:16)
at XMLHttpRequest.handleError (xhr.js:83)
My chrome network looks like this
>Request URL: http://localhost:3333/processo
Referrer Policy: no-referrer-when-downgrade
Provisional headers are shown
Accept: application/json, text/plain, */*
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiaWF0IjoxNTk3MTc5MDQ0LCJleHAiOjE1OTc3ODM4NDR9.hsj3D1nMSuuHx-r2SofNH0zMiUKIPKeAun1sjccYi7I
Referer: http://localhost:3000/inicio
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36
I've tried two things, the first was to add an extension to the chrome "Moesif Cors" it didn't work, it only works when I don't send Bearer.
And the other was trying to change from https to http. but it also didn't work.
how can i solve this? does this problem happen in my service? how do I configure cors to allow the token?
I will show below how my backend end node.js is configured.
server.js
import app from './app';
app.listen('3333');
app.js
import 'dotenv/config';
import express from 'express';
import path from 'path';
import Youch from 'youch';
import * as Sentry from '#sentry/node';
import 'express-async-errors';
import routes from './routes';
import sentryConfig from './config/sentry';
import './database';
class App {
constructor() {
this.server = express();
Sentry.init(sentryConfig);
this.middlewares();
this.routes();
this.exceptionHandler();
}
middlewares() {
this.server.use(Sentry.Handlers.requestHandler());
this.server.use(express.json());
this.server.use(
'/files',
express.static(path.resolve(__dirname, '..', 'tmp', 'uploads'))
);
}
routes() {
this.server.use(routes);
this.server.use(Sentry.Handlers.errorHandler());
}
exceptionHandler() {
this.server.use(async (err, req, res, next) => {
if (process.env.NODE_ENV === 'development') {
const errors = await new Youch(err, req).toJSON();
return res.status(500).json(errors);
}
return res.status(500).json({ error: 'Internal server error' });
});
}
}
export default new App().server;
now i will show how the call is on the front end where i have an api.js file
api.js
import axios from 'axios';
import { getToken } from "./auth";
const api = axios.create({
baseURL: 'http://localhost:3333',
});
api.interceptors.request.use(async config => {
const token = getToken();
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
export default api;
when I remove the header config, the requests work perfectly.
api.interceptors.request.use(async config => {
const token = getToken();
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
[EDIT]
I'm starting to think that the problem is the way I'm sending it from the front end and not from the back end
example of a call to the api
async listAll() {
const result = await api.get(apiService);
const list = result.data || [];
this.setState({ list, listaFiltrada: list });
}
Have you tried adding the cors middleware to Express?
If you try this request from a server or PostMan it would work. But since you are trying to make a request from the browser you need enable cors in your express server.
There are two simple way to achieve it;
Use cors library
var cors = require('cors')
var app = express()
app.use(cors());
or Write custom middleware. Manual solution for your case would be;
import 'dotenv/config';
import express from 'express';
import path from 'path';
import Youch from 'youch';
import * as Sentry from '#sentry/node';
import 'express-async-errors';
import routes from './routes';
import sentryConfig from './config/sentry';
import './database';
class App {
constructor() {
this.server = express();
this.enableCORS();
Sentry.init(sentryConfig);
this.middlewares();
this.routes();
this.exceptionHandler();
}
enableCORS(){
this.server.all('*', function(req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers');
res.setHeader('Access-Control-Allow-Credentials', 'true');
if ('OPTIONS' == req.method) {
res.sendStatus(200);
} else {
next();
}
});
}
middlewares() {
this.server.use(Sentry.Handlers.requestHandler());
this.server.use(express.json());
this.server.use(
'/files',
express.static(path.resolve(__dirname, '..', 'tmp', 'uploads'))
);
}
routes() {
this.server.use(routes);
this.server.use(Sentry.Handlers.errorHandler());
}
exceptionHandler() {
this.server.use(async (err, req, res, next) => {
if (process.env.NODE_ENV === 'development') {
const errors = await new Youch(err, req).toJSON();
return res.status(500).json(errors);
}
return res.status(500).json({ error: 'Internal server error' });
});
}
}
export default new App().server;
If you are using a create-react-app project, try using the the proxy option in package.json
"proxy": "http://localhost:3333"
Then you would replace URLs in the client like so
axios.get('/') // maps to http://localhost:3333
axios.get('/api/anything') // maps to http://localhost:3333/api/anyting
Install this on the nodejs side
https://www.npmjs.com/package/cors
config 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')
})

Node.js - csurf invalid csrf token

I'm using the npm module csurf for generating a token. First I get the token from the server, which I then use for the /register request. When I'm reproducing the same steps with postman, it seems to work, but unfortunately not in the application. There it always throws the error message that the token is invalid
--- Server side ---
csrfProtection.js
import csrf from 'csurf';
export default csrf({
cookie: true
});
router.js
import csrfProtection from './../../config/csrfProtection'
router.get('/csrfToken', csrfProtection, async (req, res, next) => {
return res.send(req.csrfToken());
});
router.post(
'/register',
validationHelper({ validation: registerUserValidation }),
csrfProtection,
async (req, res, next) => {
return res.send('user registered');
}
);
app.js
const app = express();
app.use(cookieParser());
app.use(
cors()
);
app.use(compression());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
--- Client side ---
const token = await this.$axios.$get('/csrfToken')
// token has the value 1KFmMJVz-dspX9TJo8oRInPzgDA1VY28uqQw
await this.$axios.$post(
'/register',
{
name: 'test456',
email: 'test#gmail.com',
password: '123456789'
},
{
headers: {
'csrf-token': token
}
}
)
Someone experienced the same problem? Frontend and backend are hosted on different domains.
Recently fixed a similar issue regarding 403 for csrf token. A new CSRF token is generated for every post request that happens after the get csrf call.
I found that this is a CORS issue. I fixed by adding below code:
import cors from 'cors';
const allowedOrigins = ['http://localhost:3000', 'http://localhost'];
const corsoptions: cors.CorsOptions = {
allowedHeaders: ["Origin", "X-Requested-With", "Cookie", "Content-Type", "Accept", "X-Access-Token", "Authorization"],
credentials: true,
methods: "GET,PATCH,POST,DELETE",
origin: function (origin, callback) {
// allow requests with no origin
// (like mobile apps or curl requests)
if (!origin) return callback(null, true);
if (allowedOrigins.indexOf(origin) === -1) {
var msg = 'The CORS policy for this site does not ' +
'allow access from the specified Origin.';
return callback(new Error(msg), false);
}
return callback(null, true);
},
preflightContinue: false,
};
export const handleCors = (router: Router) =>
router.use(cors(corsoptions));
Please refer to cors package https://www.npmjs.com/package/cors"
You need to add it in your app.js below the cookieParser like so:
app.use(cookieParser())
app.use(csrfProtection)
You are successfully sending a CSRF token to the frontend in your /csrfToken but then your app is generating a new token in your /post.
Here is the link to the respective documentation.

CORS request issue (XMLHttpRequest)

I'm developing a server at Node js and my front-end at Angularjs, but I'm getting an error when I try to make a request from my front-end:
XMLHttpRequest cannot load http://localhost:8085/server/authenticate/.
Response to preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:9000' is therefore not allowed
access.
My code at my server.js
app.use(function(req,res,next){
res.setHeader('Access-Control-Allow-Oringin','*');
res.setHeader('Access-Control-Allow-Methods','GET,POST,OPTIONS');
res.setHeader('Access-Control-Allow-Headers','X-Requested-With,content-type,Authorization,accept');
if (req.method === 'OPTIONS'){
res.statusCode = 200;
return res.end();
}
else{
return next();
}
});
Any suggestions?
NOTE: back-end and front-end are not at the same port, I'm trying to make it work as a CROSS-Origin resourse.
var express = require('express')
, cors = require('cors')
, app = express();
app.use(cors());
/* Make your app with CORS support: for more information: https://www.npmjs.com/package/cors*/
There is a little error in your header name Access-Control-Allow-Oringin
Try this
app.use(function(req,res,next){
res.setHeader('Access-Control-Allow-Origin','*');
res.setHeader('Access-Control-Allow-Methods','GET,POST,OPTIONS');
res.setHeader('Access-Control-Allow-Headers','X-Requested-With,content-type,Authorization,accept');
if (req.method === 'OPTIONS'){
res.statusCode = 200;
return res.end();
}
else{
return next();
}
});

Making CORS Request in Node.js/Express and AngularJS

I have seen many answers in stack overflow which says setting response headers will make you "CORS" request.But no solution worked for me.I have written the following code:
//Server.js Code
var express = require('express'),
app = express();
app.all('*',function(req, res, next) {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.setHeader('Access-Control-Allow-Credentials', true);
res.setHeader('Access-Control-Allow-Methods', 'POST, GET, PUT, DELETE, OPTIONS');
next();
I am trying to access the content from the URL using $http in client side:
//Controller.js
$http.get('http://domainA.com/a/ipadapi.php?id=135&client=ipad').success(function(response){
alert("I got response");
});
It's showing the following error in console.
XMLHttpRequest cannot load http://domainA.com/a/ipadapi.php?id=135&client=ipad The 'Access-Control-Allow-Origin' header has a value 'http://example.xxxxx.com' that is not equal to the supplied origin. Origin 'http://localhost:3000' is therefore not allowed access.
Note:I am new to nodeJS,Express and AngularJs
When you are passing credentials with CORS, you need to lock down the accepted origins. Try changing your origins from * to "localhost:3000"
See cross origin resource sharing with credentials
Change the header info from
res.setHeader("Access-Control-Allow-Origin", "*");
TO
res.header('Access-Control-Allow-Origin', 'http://localhost:3000');
If you're not the owner of domainA then you cannot send CORS headers from that domain. You can use your Node server as middleware, and proxy the request from your server to domainA. Your server can send CORS headers back to your angular app. pseudo code with hapi and needle:
import Hapi from 'hapi'
import needle from 'needle'
const server = new Hapi.Server()
server.connection({
port: 9090
, routes: {
cors: true
}
})
const handler = (req, reply) => {
const url = 'https://domainA.com'
, data = {
body: 'code'
}
needle.post(url, 'body=${data.body}', function(err, res) {
let json = JSON.parse(res.body)
reply(json.data)
})
}
server.route({
method: 'GET',
path: '/route/{id}',
handler: handler
}
)
server.start( err => {
if( err ) {
console.error( 'Error was handled!' )
console.error( err )
}
console.log( 'Server started at ${ server.info.uri }' )
})

Categories