How to fix this CORS issue in socket.io? - javascript

I am trying to connect to a remote server with socket.io, but I am having some problems. I am getting this error: 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'
OK, so here is the code:
Server
var server = require('http').createServer();
const io = require("socket.io")(server, {
cors: {
origin: "my URL",
methods: ["GET", "POST"],
credentials: false
}
});
io.sockets.on('connection', function(socket) {
console.log("Client has connected!");
});
console.log ('Server started.');
server.listen(3000);
Here is the client code:
var socket = io.connect("https://persistent-gentle-banon.glitch.me", {
withCredentials: false
});
How can I solve this and get it to connect?
Thanks for any help!

i had the same problem, i was using express and i was able to solve it by
var cors = require("cors");
const corsOptions = {
origin: "*",
optionsSuccessStatus: 200
};
const io = require("socket.io")(server, {
cors: {
origin: "*",
methods: ["PUT", "GET", "POST", "DELETE", "OPTIONS"],
credentials: false
}
// transports: ['websocket']
});
app.use(cors(corsOptions));

According to this link https://socket.io/docs/v4/server-instance/#serverengine , you should use io.engine initial_headers and headers events to set cors headers simply, this should work with socket.io v4+.
import { createServer } from "http";
import {Server} from 'socket.io';
const server = createServer(app);
const io = new Server(server);
io.engine.on("initial_headers", (headers, req) => {
headers["Access-Control-Allow-Origin"] = "http://localhost:4200";
});
io.engine.on("headers", (headers, req) => {
headers["Access-Control-Allow-Origin"] = "http://localhost:4200"; // url to all
});
server.listen(3000);

Related

MERN stack herokuapp does not work in edge and firefox browser. CORS preflight error

I have build a React Redux app. It works fine in localhost in every browser(chrome,edge,firefox). But the Heroku deployed app doesn't works in Edge, Firefox , although it worked in chrome perfectly.
My app doesn't seems to send request and receive response ,because i noticed that the login button spinner keeps on spinning because it waits for response. So i think that no response is received from backend.
Following are the conclusion i made after test in different browser:
it works perfectly in every browser in localhost development mode.
After Deploying , herokuapp works perfectly fine in chrome only.
Herokuapp doesn't work in edge , Firefox.
Same is the issue with other system(Friends PC).
It doesn't work in any browser except chrome in Mobile device
After console logging and banging my head for hours i got the following error in microsoft edge:
Access to XMLHttpRequest at 'https://ecrypt.herokuapp.com/user/login' from origin 'http://ecrypt.herokuapp.com' 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 'https://ecrypt.herokuapp.com' that is not equal to the supplied origin.
2.2c59d01c.chunk.js:2 POST https://ecrypt.herokuapp.com/user/login net::ERR_FAILED
Okay, so i figured out that there is some problem with CORS.
Following is my code
Frontend:
import axios from "axios";
const API = axios.create({
baseURL: "https://ecrypt.herokuapp.com",
// withCredentials: false,
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET,PUT,POST,DELETE,PATCH,OPTIONS",
"Access-Control-Allow-Headers": "Origin, Content-Type, X-Auth-Token",
},
});
// const API = axios.create({ baseURL: "http://localhost:9000" });
const cloudinaryAPI = axios.create({
baseURL: "https://api.cloudinary.com/v1_1/ecryptimgdb",
});
//register new user
export const registerNewUser = (formData) =>
API.post("/user/register", formData);
//Account Activation through Email
export const activation = (activation_token) =>
API.post("/user/activation", {
data: {
activation_token,
},
});
//Login
export const login = (formData) =>
API.post("/user/login", formData, { withCredentials: true });
//get Token
export const getToken = () =>
API.post("/user/refresh_token", null, { withCredentials: true });
//Logout
export const logout = () => API.get("/user/logout", { withCredentials: true });
//get User
export const getUser = (token) =>
API.get("/user/info", {
headers: { Authorization: `${token}` },
});
//PROFILE SETTINGS__________________________________________________________________________________________
export const editProfile = (token, profileData) =>
API.post(
"/user/updateProfile",
{ profileData },
{
headers: { Authorization: `${token}` },
}
);
//forgot password____
export const forgotPass = (email) =>
API.post("/user/forgotPassword", { email });
//reset password_____
export const resetPass = (token, password) =>
API.post(
"/user/resetPassword",
{ password },
{
headers: { Authorization: `${token}` },
}
);
//change password____
export const changePass = (oldPassword, newPassword, token) =>
API.post(
"/user/changePassword",
{ oldPassword, newPassword },
{
headers: { Authorization: `${token}` },
}
);
BACKEND:
//IMPORTS
require("dotenv").config();
const express = require("express");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const cors = require("cors");
const cookiesParser = require("cookie-parser");
const path = require("path");
const app = express();
// app.use(cors({ credentials: true, origin: "http://localhost:3000" }));
app.use(cors({ credentials: true, origin: "https://ecrypt.herokuapp.com" }));
app.use(cookiesParser());
// app.use(bodyParser.json({ limit: "30mb", extended: true }));
// app.use(bodyParser.urlencoded({ limit: "30mb", extended: true }));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
const CONNECTION_URL = process.env.MONGODB_URL;
// const CONNECTION_URL = process.env.MONGODB_LOCAL_URL;
const PORT = process.env.PORT || 9000;
//MONGODB CLOUD DATABASE CONNECTION________________________
mongoose
.connect(CONNECTION_URL, {
useCreateIndex: true,
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: false,
})
.then(() => console.log("Connected to Database :: MongoDB Cloud"))
.catch((err) => console.log(err.message));
// app.use("/", routesIndex);
app.use("/", require("./routes/index"));
if (process.env.NODE_ENV === "production") {
app.use(express.static("client/build"));
app.get("*", (req, res) => {
res.sendFile(path.join(__dirname, "client", "build", "index.html"));
});
}
//SERVER LISTENING
app.listen(PORT, (err) => {
if (err) {
console.log(err.message);
} else {
console.log(`Listening on localhost:${PORT}`);
}
});
NOTE
I am using cookies to store token so i needed withCredentials and Authorization headers.
The following headers should be sent by the server (instead of the front)
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET,PUT,POST,DELETE,PATCH,OPTIONS",
"Access-Control-Allow-Headers": "Origin, Content-Type, X-Auth-Token",
},
Try removing headers from your axios request. I don't think those headers are allowed.
Ok, so i figured it out ,in my case i was setting headers as
{
headers: { Authorization: `${token}` },
}
Instead of setting it like above a slight change just worked for me:
{
headers: { Authorization: `Bearer ${token}` },
}
and at backend side in index.js or server.js whatever your file name is ,use cors middle ware like this:
const cors = require("cors");
app.use(
cors({
origin: ["https://blahblah.herokuapp.com", "http://localhost:****"],
credentials: true,
})
);
Note: credentials true if you want to pass cookies and access them at server side.
In my case i wanted to access the HttpOnly cookies at server side.

How to Fix Coinbase Pro API Request Headers?

I am trying to code to execute orders using Coinbase Pro API according to the Documentation provided. However, I got an error like this.
Access to XMLHttpRequest at 'https://api.pro.coinbase.com/orders' from origin 'http://localhost:8000' has been blocked by CORS policy: Request header field cb-access-key is not allowed by Access-Control-Allow-Headers in preflight response.
And this is the code that I wrote.
var vm = this;
var coinbasePro = {
passphrase: 'xxxxxxxxx',
key: 'xxxxxxxxxxxxxxxxxxxxxxx',
secret: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==',
apiURI: 'https://api.pro.coinbase.com',
};
var dataRequest = {
url: '/orders',
method: 'POST',
timestamp: Date.now() / 1000,
};
var dataBody = JSON.stringify({
price: '1.0',
size: '1.0',
side: 'buy',
product_id: 'BTC-USD'
});
var what = vm.dataRequest.timestamp + vm.dataRequest.method + vm.dataRequest.url + dataBody;
var key = Buffer.from(vm.coinbasePro.secret, 'base64');
var hmac = cryptoJs.createHmac('sha256', key);
var sign = hmac.update(what).digest('base64');
vm.$http({
url: vm.coinbasePro.apiURI+vm.dataRequest.url,
method: vm.dataRequest.method,
headers: {
'Accept': 'application/json',
'CB-ACCESS-KEY': vm.coinbasePro.key,
'CB-ACCESS-SIGN': sign,
'CB-ACCESS-PASSPHRASE': vm.coinbasePro.passphrase,
'CB-ACCESS-TIMESTAMP': vm.dataRequest.timestamp,
},
}).then((res) => {
console.log(res);
}).catch((err) => {
});
I have tried different ways to get things going and applied some of the references I have come across. Thank you for the help.
Their API does support CORS, however it is misconfigured and does not permit the security headers that they require you to use! You can work around this by running an express proxy with middleware to re-write the headers:
import express from 'express'
import { createProxyMiddleware } from 'http-proxy-middleware'
const app = express()
app.use(express.static('client'))
const apiProxy = createProxyMiddleware({
target: 'https://api.pro.coinbase.com',
changeOrigin: true,
onProxyRes: res => {
res.headers = {
...res.headers,
'access-control-allow-headers':
'Content-Type, cb-access-key, cb-access-sign, cb-access-timestamp, cb-access-passphrase',
}
},
})
app.use('/', apiProxy)
app.listen(3001)

node.js fetch post request returning index.html instead of json

I have a node.js app connected to a dialogflow bot I created, in which there's only one file: app.js.
I have index.html, index.js UI for the bot, which when I open unconnected to app.js, runs perfectly. I get json response from app.js
However, when I tried to include the UI (index.html and index.js) in app.js, the post method is returning index.html instead of the json it returned before, resulting in error: "SyntaxError: Unexpected token < in JSON at position 0" (because index.html is returned instead of json)
Here's my app.js
const dialogflow = require('#google-cloud/dialogflow');
const uuid = require('uuid');
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const port = 9000;
const sessionId = uuid.v4();
app.use(bodyParser.urlencoded({
extended: false
}));
// ------------------The following code is the one I use for including the UI----------------------------------
const path = require('path');
app.use(express.static('botui'));
app.use('/', function(req,res){
res.sendFile(path.join(__dirname+'/botui/index.html'));
});
// ------------------------------Code for including the UI ended-----------------------------------------------
// ------------------When I did not use the above code and just opened file://index.html it worked great-------
app.use(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', 'X-Requested-With,content-type');
res.setHeader('Access-Control-Allow-Credentials', true);
// Pass to next layer of middleware
next();
});
app.post('/send-msg',(req,res)=>{
runSample(req.body.MSG).then(data=>{
res.send({
statusCode: 200,
body: {},
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
},
Reply:data})
})
})
/**
* Send a query to the dialogflow agent, and return the query result.
* #param {string} projectId The project to be used
*/
async function runSample(msg, projectId = 'bot_ID') {
// Create a new session
const sessionClient = new dialogflow.SessionsClient({
keyFilename:"BOT-KEY.json"
});
const sessionPath = sessionClient.projectAgentSessionPath(projectId, sessionId);
// The text query request.
const request = {
session: sessionPath,
queryInput: {
text: {
// The query to send to the dialogflow agent
text: msg,
// The language used by the client (en-US)
languageCode: 'en-US',
},
},
};
// Send request and log result
const responses = await sessionClient.detectIntent(request);
console.log('Detected intent');
const result = responses[0].queryResult;
console.log(` Query: ${result.queryText}`);
console.log(` Response: ${result.fulfillmentText}`);
if (result.intent) {
console.log(` Intent: ${result.intent.displayName}`);
} else {
console.log(` No intent matched.`);
}
return result.fulfillmentText;
}
app.listen(port,()=>{
console.log("Running on port: " + port)
})
And here's the code from index.js which sends the POST request:
fetch(url, {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
},
method: 'POST',
body:data
})
.then(res => res.json())
.then(response => {
console.log(response);
serverMessage(response.Reply);
})
.catch(error => console.error('Error h:', error));
It seems you should replace app.use('/', function(req,res){ to app.get('/', function(req,res){
take a look at Difference between app.use and app.get in express.js

Node.js Connect middleware Limit not working

I have a problem
server:
var connect = require('connect');
var http = require('http');
var app = connect()
.use(connect.limit('32kb'))
.use(connect.urlencoded())
.use(connect.json())
.use(function(req, res){
console.log('yo');
res.end('hello\n');
});
http.createServer(app).listen(3000);
client:
var http = require('http');
var req = http.request({
method: 'POST',
port: 3000,
headers: {
'Content-Type': 'application/json'
}
});
req.write('[');
var n = 30000000;
while (n--) {
req.write('"foo",');
}
req.write('"bar"]');
req.end();
Connect's middleware limit not "limiting" size of json. I know that it will deprecated, but instead Express framework what can i use to limit a size of requests?
do this instead:
.use(connect.urlencoded({
limit: '32kb'
}))
.use(connect.json({
limit: '32kb'
}))
or just:
.use(connect.bodyParser({
limit: '32kb'
})
you can still write to req, but that doesn't necessarily mean the server will receive those bytes. if you check the response and it isn't a 4xx error, then it's a bug.
EDIT:
req.once('response', function (res) {
assert.equal(res.statusCode, 413)
})
.write(new Buffer(123123123213223122))
.end()
the limit middleware checks the header Content-Length of request message only while there's no such header out of your HTTP POST request.
You can verify this by using:
var app = connect()
.use(connect.limit('32kb'))
.use(connect.urlencoded())
.use(connect.json())
.use(function(req, res){
console.log(req.headers);
console.log('yo');
res.end('hello\n');
});
You can test the limit middle via this code:
var http = require('http');
var req = http.request({
method: 'POST',
port: 3000,
headers: {
'Content-Type': 'application/json',
'Content-Length': 40 * 1024
}
});
BTW: you can check how the limit middleware is tested: https://github.com/senchalabs/connect/blob/master/test/limit.js

How to resolve NODE.Js HTTP POST "ECONNRESET" Error

I have this function and the below data which is passed into this function returns a ECONNRESET, socket hang up error. However, when the discountCode array is reduced to like only 10 objects, it can POST without any problem.
What could the cause for this problem? I tried to do multiple req.write() by segmenting the data in Buffer, however that doesn't work out well. Any NodeJs ninja could give some insights to this problem?
createObj: function(data, address, port, callback) {
//console.log('Create Reward: '+JSON.stringify(data));
var post_data = JSON.stringify(data);
var pathName = '/me/api/v1/yyy/'+data.idBusinessClient+'/newObj';
//
var options = {
hostname: address,
port: port,
path: pathName,
method: 'POST',
headers: {
'Content-Type': 'application/json; charset=utf-8',
'Accept': 'application/json',
'Accept-Encoding': 'gzip,deflate,sdch',
'Accept-Language': 'en-US,en;q=0.8'
}
};
// http call to REST API server
var req = restHttp.request(options, function(res) {
console.log('HTTP API server PUT Reward response received.');
var resData = '';
res.on('data', function(replyData) {
// Check reply data for error.
console.log(replyData.toString('utf8'));
if(replyData !== 'undefined')
resData += replyData;
});
res.on('end', function() {
//<TODO>Process the data</TODO>
callback(JSON.parse(resData));
});
});
req.write(post_data);
req.end();
console.log('write end');
req.on('close', function() {
console.log('connection closed!');
});
req.on('error', function(err) {
console.log('http request error : '+err);
callback({'error':err});
throw err;
});
req.on('socket', function(socket) {
console.log('socket size:'+socket.bufferSize);
socket.on('data', function(data) {
console.log('socket data:'+data);
});
});
}
]}`
I had the same problem and was able to resolve it by adding a Content-Length header:
headers: {
'Content-Type': 'application/json; charset=utf-8',
'Content-Length': Buffer.byteLength(post_data),
'Accept': 'application/json',
'Accept-Encoding': 'gzip,deflate,sdch',
'Accept-Language': 'en-US,en;q=0.8'
}
However, I still have no clear idea why a missing Content-Length header causes such a trouble. I assume it's some kind of weirdness in the internal Node.js code. Maybe you can even call it a bug, but I'm not sure about that ;)
PS: I'm absolutely interested more information about the cause of this problem. So please leave a comment if you have any idea...
When you change the content of response for sure you need also to update on header the content length:
headers: {
...
'Content-Length': Buffer.byteLength(post_data),
...
}
But i run on this problem also when i try to make multiple request and seems that this is not well managed on different library so a workaround that i have found if this problem persist is to add on headers:
headers: {
...
connection: 'Close'
...
}
So if you are making request on different servers.. this close the connection after finish the process. This worked for me in net, node-http-proxy.
If Express and http-proxy-middleware is used to make the POST call, and some body parser middleware is used like express.json(), the request interceptor fixRequestBody must be used (more info). Otherwise the POST call will hang with the ECONNRESET error.
const express = require('express');
const { createProxyMiddleware, fixRequestBody } = require('http-proxy-middleware');
const app = express();
app.use(express.json());
app.post(
'/path',
createProxyMiddleware('/path', {
target: API_URL,
changeOrigin: true,
pathRewrite: (path, req) => `/something/${req?.body?.someParameter}`,
onProxyReq: fixRequestBody // <- Add this line
});
Had the same problem. The solution for me was to append it to the proxy for it to work. If you're not using a proxy, you can probably just append it to the post request itself.
With proxy:
import express from 'express';
import { createProxyMiddleware } from 'http-proxy-middleware';
import logger from './logger';
// setup routes
server.get('/isAlive', (req, res) => res.send('Alive'));
server.get('/isReady', (req, res) => res.send('Ready'));
server.use(express.static(path.join(__dirname, '../build')));
const restream = (proxyReq, req, res, options) => {
if (req.body) {
let bodyData = JSON.stringify(req.body);
proxyReq.setHeader('Content-Type', 'application/json');
proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData));
proxyReq.write(bodyData);
}
};
server.use(
'/api',
createProxyMiddleware({
target: 'http://your-backendUrl-api',
onProxyReq: restream,
changeOrigin: true,
proxyTimeout: 30000,
secure: true,
logLevel: 'info',
onError: (err, req, res) => {
logger.error('error in proxy', err, req, res);
},
})
);
E.g without proxy:
import axios, { AxiosResponse } from 'axios';
const api = axios.create({
baseURL: '/api/....',
timeout: 35000,
withCredentials: true,
headers: { Pragma: 'no-cache', 'Cache-Control': 'no-cache' },
validateStatus: (status) => status < 400,
});
const response = await api.post(
`/somepath/${exampleInjectedId}/somepathToRestAPI`,
{
...payload
},
{
baseURL: '/api/...',
timeout: 35000,
withCredentials: true,
headers: {
Pragma: 'no-cache',
'Cache-Control': 'no-cache',
'Content-Length': Buffer.byteLength(
JSON.stringify({
...payload
})
),
},
validateStatus: (status) => status < 400,
}
);

Categories

Resources