can't get express session data from socket io connection - node.js

Hello i'm having a problem to access express session data like I did on http connection.
Even when I copy the documentation edited by socket io on this link
https://socket.io/how-to/use-with-express-session#1st-use-case-socketio-only-retrieves-the-session-context i still can't access express session data.
there is my server
const express = require('express');
const app = express();
const cors = require('cors');
const helmet = require('helmet');
const sessionStrategy = require('#middlewares/session_strategy/sessionStrategy');
const httpServer = require("http").Server(app);
const Server = require("socket.io").Server;
app.use(express.urlencoded({
parameterLimit: 20,
extended: true,
limit: '10mb'
}));
app.use(express.json({limit: '100mb'}));
// CORS
app.use(cors({
origin: true,
credentials: true
}));
app.use(sessionStrategy);
if (process.env.NODE_ENV === 'production') {
app.set('trust proxy', 1);
}
const corsConfig = {
origin: true,
credentials: true,
methods: ["GET", "POST"]
};
const io = new Server(httpServer, {cors: corsConfig});
const wrap = middleware => (socket, next) => middleware(socket.request, {}, next);
io.use(wrap(sessionStrategy));
io.on("connection", (socket) => {
// socket.request.session give undefined value
console.log("Connexion", socket.request.session);
socket.on("event_test", (data) => {
console.log(data);
console.log(socket);
});
socket.on("connect_error", (err) => {
console.log(`connect_error due to ${err.message}`);
});
});
app.all('*', require("#middlewares/catchAllRoute"));
httpServer.listen(process.env.NODE_API_PORT, function () {
console.log('App listening on port ' + process.env.NODE_API_PORT + ' ...');
});
and there is my client
import { io } from "socket.io-client";
const socket = io("http://localhost:9000", {
withCredentials: true
});
export default socket;
import socket_connection from "#/sockets_connections";
// the command is launched after a click
socket_connection.emit("event_test", {"test":"test"});

Related

req.cookies and req.signedcookies are empty

I'm storing cookies on my server, but when I tried to access them. Object Returns Null.
code I'm using to store my cookies. This is done when I'm logging in!
res.cookie("accessToken", accessToken, {
httpOnly: true,
secure: true,
expires: new Date(Date.now() + oneDay),
});
res.cookie("refreshToken", refreshToken, {
httpOnly: true,
secure: true,
expires: new Date(Date.now() + oneDay),
});
index.ts
const dotenv = require("dotenv");
dotenv.config();
const PORT = process.env.PORT || 3001;
const cookies = require("cookie-parser");
const express = require("express");
const app = express();
const cors = require("cors");
app.use(cors());
app.use(express.json());
app.use(cookies());
import dbConnect from "./db/connect";
import adminAuthRoter from "./routes/admin/adminAuthRouter";
app.get("/", (req: any, res: any) => {
res.send("Hello World");
});
app.use("/api/v1/adminauth", adminAuthRoter);
const start = async () => {
try {
await dbConnect(process.env.MONGODB_URI);
app.listen(PORT, () =>
console.log(`Server is listening on port ${PORT}...`)
);
} catch (error) {
console.log(error);
}
};
start();
When I tried to console.log(req.cookies) or console.log(req.signedCookies) my response is empty. But when I see my Postmon cookies there are cookies stored
Postmon Cookie Reponse Image
What may be the issue here?

400 error socket.io when trying to connect from client side

I am setting up a little chat feature with socket.io
for some reason when I try to connect from client I am getting this error
I am initiating my connection in a chatProvider component in a react app.
Here is the client side connection function
import React, { useState, useEffect} from 'react';
import io from "socket.io-client";
const ChatProvider = ({ children }) => {
useEffect(() => {
const socket = io('http://localhost:5000');
socket.on('messageFromServer', (dataFromServer) => {
console.log(dataFromServer);
socket.emit('messageToServer', {data: "this is from client"})
})
}, [])
return <ChatContext.Provider value={value}>{children}</ChatContext.Provider>;
};
ChatProvider.propTypes = { children: PropTypes.node.isRequired };
export default ChatProvider;
Here is my backend
const express = require('express');
const mongoose = require('mongoose');
const cookieSession = require('cookie-session');
const passport = require('passport');
const bodyParser = require('body-parser') // when a post request comes in to express, it doesnt automatically parse, you need to call body-parser
const keys = require('./config/keys');
const cors = require('cors');
const { setIO } = require('./helpers/socket-setup');
require("dotenv").config();
require('./models/GoogleUserModel'); // the user model must be placed before this services passport// this must be ran after requiring model bcuz this needs the model. ORDER
require('./models/UserModel');
require('./services/passport');
const app = express()
const server = require('http').createServer(app)
const corsOptions = {
origin:"http://localhost:3000",
credentials: true, //access-control-allow-credentials:true
optionSuccessStatus:200
}
app.use(cors(corsOptions))
mongoose.Promise = global.Promise;
mongoose.connect(keys.mongoURI, {
useNewUrlParser: true,
useCreateIndex: true,
useUnifiedTopology: true
})
mongoose.connection.on('error', () => {
throw new Error (`unable to connect to database: ${keys.mongoURI}`)
});
app.use(bodyParser.json({limit: '10mb'}))
app.use(express.urlencoded( { extended: true }))
app.use(
cookieSession({
maxAge: 30 * 24 * 60 * 60 * 1000,
keys: [keys.cookieKey]
})
)
app.use(passport.initialize());
app.use(passport.session());
require('./routes/webhookRoutes')(app)
require('./routes/userRoutes')(app);
let io = setIO(server)
io.on("connection", socket => {
socket.emit('messageFromServer', { data: 'this is from server' });
socket.on('messageToServer', ( dataFromClient )=> {
console.log(dataFromClient);
})
})
const PORT = process.env.PORT || 5000;
server.listen(PORT);
Here is a helper file socket-setup.js I made so I can use socket.io functions within other files, could this be the issue?
const socket = require("socket.io")
let _io;
const setIO = (server) => {
_io = socket(server, {
cors : {
origin:"http://localhost:3000",
credentials: true, //access-control-allow-credentials:true
optionSuccessStatus:200
}
})
return _io
}
const getIO = () => {
return _io
}
module.exports = {
getIO,
setIO
}

CORS error in Typescript Express.js API, when request from client (different server)

I'm converting an Express.js API to Typescript, that has a client server react-scripts counterpart. The Express.js API is reachable under port 5000 and the client via port 3000. To handle requests between the two servers, the project uses the cors package (https://www.npmjs.com/package/cors) as a middleware.
When I run my to JavaScript compiled files, the requests from the client are blocked by the CORS policy of my browser.
Access to fetch at 'http://localhost:5000/prs?username=mygithubuser' 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.
When I run the old code (pre-Typescript conversion, aka original JavaScript files), it works without problems. There are not many changes to the code (in api/index.ts), so I am clueless why it blocks the request.
This is the old api/index.js (working)
'use strict';
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const dotenv = require('dotenv');
const setupGithubApi = require('./setupHelpers/setupGithubApi');
const setupGitlabApi = require('./setupHelpers/setupGitlabApi');
const setupErrorHandling = require('./setupHelpers/setupErrorHandling');
const PrController = require('./controllers/pr');
const path = require('path');
const compression = require('compression');
const start = () => {
// Load environment variables from .env file
dotenv.config();
const app = express();
const shouldCompress = (req, res) => {
if (req.headers['x-no-compression']) {
return false;
}
return compression.filter(req, res);
};
const githubApi = setupGithubApi();
const gitlabApi = setupGitlabApi();
const port = process.env.PORT || 5000;
app.set('port', port);
app.set('github', githubApi);
app.set('gitlab', gitlabApi);
setupErrorHandling(app);
app.use(express.static(path.join(__dirname, '../build')));
app.use(bodyParser.json());
const corsOptions = {
origin: process.env.REACT_APP_HOSTNAME,
};
app.use(cors(corsOptions));
app.use(
compression({
filter: shouldCompress,
})
);
app.get('/prs', PrController.index);
app.get('/*', (req, res) => {
res.sendFile(path.join(__dirname, '../build', 'index.html'));
});
app.listen(port, () => {
console.log(`Express server listening on port ${port}`);
});
};
module.exports = start;
This is the Typescript version, api/index.ts (returning cors error)
import express from 'express';
import bodyParser from 'body-parser';
import cors from 'cors';
import dotenv from 'dotenv';
import path from 'path';
import compression from 'compression';
import setupGithubApi from './setupHelpers/setupGithubApi';
import setupGitlabApi from './setupHelpers/setupGitlabApi';
import setupErrorHandling from './setupHelpers/setupErrorHandling';
import PrController from './controllers/pr';
const start = () => {
// Load environment variables from .env file
dotenv.config();
const app = express();
const shouldCompress: compression.CompressionFilter = (req, res) => {
if (req.headers['x-no-compression']) {
return false;
}
return compression.filter(req, res);
};
const githubApi = setupGithubApi();
const gitlabApi = setupGitlabApi();
const port = process.env.PORT || 5000;
app.set('port', port);
app.set('github', githubApi);
app.set('gitlab', gitlabApi);
setupErrorHandling(app);
app.use(express.static(path.join(__dirname, '../../build')));
app.use(bodyParser.json());
const corsOptions = {
origin: [process.env.REACT_APP_HOSTNAME],
};
app.use(cors(corsOptions));
app.options('*', cors(corsOptions));
app.use(
compression({
filter: shouldCompress,
})
);
app.get('/prs', PrController.index);
app.get('/*', (req, res) => {
res.sendFile(path.join(__dirname, '../../build', 'index.html'));
});
app.listen(port, () => {
console.log(`Express server listening on port ${port}`);
});
};
module.exports = start;
When compiled into api/build/index.js (returning cors error)
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = __importDefault(require("express"));
const body_parser_1 = __importDefault(require("body-parser"));
const cors_1 = __importDefault(require("cors"));
const dotenv_1 = __importDefault(require("dotenv"));
const path_1 = __importDefault(require("path"));
const compression_1 = __importDefault(require("compression"));
const setupGithubApi_1 = __importDefault(require("./setupHelpers/setupGithubApi"));
const setupGitlabApi_1 = __importDefault(require("./setupHelpers/setupGitlabApi"));
const setupErrorHandling_1 = __importDefault(require("./setupHelpers/setupErrorHandling"));
const pr_1 = __importDefault(require("./controllers/pr"));
const start = () => {
// Load environment variables from .env file
dotenv_1.default.config();
const app = (0, express_1.default)();
const shouldCompress = (req, res) => {
if (req.headers['x-no-compression']) {
return false;
}
return compression_1.default.filter(req, res);
};
const githubApi = (0, setupGithubApi_1.default)();
const gitlabApi = (0, setupGitlabApi_1.default)();
const port = process.env.PORT || 5000;
app.set('port', port);
app.set('github', githubApi);
app.set('gitlab', gitlabApi);
(0, setupErrorHandling_1.default)(app);
app.use(express_1.default.static(path_1.default.join(__dirname, '../../build')));
app.use(body_parser_1.default.json());
const corsOptions = {
origin: [process.env.REACT_APP_HOSTNAME],
};
app.use((0, cors_1.default)(corsOptions));
app.options('*', (0, cors_1.default)(corsOptions));
app.use((0, compression_1.default)({
filter: shouldCompress,
}));
app.get('/prs', pr_1.default.index);
app.get('/*', (req, res) => {
res.sendFile(path_1.default.join(__dirname, '../../build', 'index.html'));
});
app.listen(port, () => {
console.log(`Express server listening on port ${port}`);
});
};
module.exports = start;
This is the tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"esModuleInterop": true,
"target": "es6",
"moduleResolution": "node",
"noUnusedLocals": false,
"outDir": "./build"
},
"include": [
"./**/*.ts"
]
}
I don't know what exactly causes this error, since cors seems to be imported correctly, when I log it out. Also the value of process.env.REACT_APP_HOSTNAME is set correctly, to 'http://localhost:3000', in the logs.
The full code is available here:
Typescript Version (https://github.com/vincentrohde/hacktoberfest-checker)
Original (https://github.com/jenkoian/hacktoberfest-checker)

Am I doing anything wrong here node+express + vue SPA getCSRFTOKEN()

My index.js Server
// USE STRICT;
const express = require('express');
const app = express();
const session = require('express-session');
const http = require('http').Server(app);
const socket = require('socket.io');
const schedule = require('node-schedule');
const cors = require('cors');
const io = socket(http, {
cors: {
origin: 'http://localhost:8080',
methods: ['GET', 'POST'],
allowedHeaders: ['my-custom-header'],
credentials: true
}
});
const port = 8080;
app.use(express.static(__dirname + '/public'));
app.use(express.static(__dirname + '/uploads'));
const cookieParser = require('cookie-parser');
const csrf = require('csurf');
const mustacheExpress = require('mustache-express');
app.engine('html', mustacheExpress());
app.set('view engine', 'html');
app.set('views', __dirname + '/views');
const secret = 'somesecretkeyhere';
const passport = require('passport');
const helmet = require('helmet');
const { sendMail } = require('./controllers/sellerAdsController');
// Gives us access to variables set in the .env file via `process.env.VARIABLE_NAME` syntax
// require('dotenv').config();
// Must first load the models before passport
require('./models/user');
// Pass the global passport object into the configuration function
require('./config/passport')(passport);
// This will initialize the passport object on every request
app.use(passport.initialize());
// Allows our remote applications to make HTTP requests to Express application
app.use(cors());
app.use(helmet());
app.use(express.urlencoded({ extended: false }));
// app.use(express.json()); //WARNING: Do not turn on. stops formidable for api calls
app.use(cookieParser(secret));
app.use(session({
secret: secret,
resave: false,
saveUninitialized: true,
cookie: {
httpOnly: true,
secure: true
}
}));
app.use(csrf());
// Stop page caching
app.use(function (req, res, next) {
res.set('Cache-Control', 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0');
next();
});
// Imports all of the routes from ./routes/index.js
app.use(require('./routes/api/v1'));
// Socket Operations
// io.on('connection', io => {
// let sessionId = io.id;
// io.on('clientHandshake', (data) => {
// console.log(data);
// io.emit('serverHandshake', { sessionId: sessionId });
// });
// });
// io.use((socket, next) => {
// const username = socket.handshake.auth.username;
// if (!username) {
// return next(new Error('invalid username'));
// }
// console.log(username);
// socket.username = username;
// next();
// });
io.on('connection', (socket) => {
console.log('👾 New socket connected! >>', socket.id);
// notify existing users
socket.broadcast.emit('user connected', {
userID: socket.id,
username: socket.username,
});
socket.on('private message', ({ content, to }) => {
socket.to(to).emit('private message', {
content,
from: socket.id,
});
console.log(content, to);
});
});
// EROOR HANDLING ROUTES MUST BE BENEATH ALL APP.USE AND ROUTES
// Check if request is from web or app (HTML/JSON)
// Handle 404
app.use(function (req, res) {
res.status(404);
res.render('404.html', { title: '404: File Not Found' });
});
// Handle 500
app.use(function (error, req, res) {
return res.send(error);
// res.status(500);
// res.render('500.html', { title: '500: Internal Server Error', error: error });
});
// SCHEDULED JOBS
const now = new Date();
let date = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 0, 0);
schedule.scheduleJob(date, sendMail);
http.listen(port, () => {
console.log(`listening on *:${port}`);
});
And this is how I am getting from VUE
window.axios.get('/databank/getCSRF').then((response) => {
window.axios.defaults.headers.common['XSRF-TOKEN'] = response.data;
}, (err) => {
console.log(err)
})
And this is my login request header
XSRF-TOKEN from my login request header sent by axios
So Ive set my server up like that, and my vue SPA, but getCSRF() seems to be getting the request but I can't do a POST request back to the server throws an error
ForbiddenError: invalid csrf token
at csrf
Maybe because you wrote XSRF-TOKEN instead of CSRF-Token as it suggests in the Express Documentation.

Socket IO CORS issue when using a domain for server

I am having errors from socket io when I call my server from a domain instead of server IP. This domain works for fetching data by Axios but fails and shows the error below for socket:
Access to XMLHttpRequest at
'https://api.alo.social/socket.io/EIO=3&transport=polling&t=NA9Kd2D' from
origin 'https://apps.alo.social' has been blocked by CORS policy: 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'. The credentials mode of requests initiated by the
XMLHttpRequest is controlled by the withCredentials attribute.
GET https://api.alo.social/socket.io/?EIO=3&transport=polling&t=NA9Kd2D net::ERR_FAILED
My server code looks like this:
const express = require('express')
const app = express()
const bodyParser = require('body-parser')
const cors = require('cors')
const server = require('https').createServer(app)
const getRoute = require('./routes/getRoutes')
const postRoute = require('./routes/postRoutes')
const socketIO = require('socket.io')
const io = socketIO(server)
require('dotenv').config()
let port = process.env.PORT
let whitelist = [
'https://apps.alo.social',
'https://api.alo.social'
]
let corsOptions = {
origin(origin, callback) {
if (whitelist.indexOf(origin) !== -1 || !origin) {
console.log('Okay', origin)
callback(null, true)
} else {
console.log('Not okay', origin)
callback(new Error('Not allowed by CORS'))
}
}
}
app.options('*', cors())
app.use(cors(corsOptions));
app.use(express.static('public'))
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: true }))
io.on('connection', function (socket) {
app.use(function (req, res, next) {
res.io = io
next()
})
socket.on('pushMessage', function (data) {
// console.log('pushMessage socket', data)
io.emit('pushMessage', data)
})
})
app.get('/', (req, res) => {
res.send(`Server is up into port ${port}`)
})
app.use('/api/get', getRoute)
app.use('/api/post', postRoute)
app.listen(port, () => console.log(`Server is up into port ${port}`))
module.exports = { app: app, server: server }
The client end where I am defining the socket is like:
import socketIOClient from 'socket.io-client'
let serverSocket = 'https://api.alo.social/'
let socket = socketIOClient(serverSocket)
and calling the socket like:
socket.emit('pushMessage', messageData)
socket.on('pushMessage', messageData => { console.log(messageData) })
Can anyone help with this?
It solved after modifying io configuration in server.js as:
const io = module.exports.io = require('socket.io').listen(server, {
handlePreflightRequest: (req, res) => {
const headers = {
"Access-Control-Allow-Headers": "Content-Type, Authorization",
"Access-Control-Allow-Origin": '*',
};
res.writeHead(200, headers);
res.end();
}
})
server.listen(port)

Resources