I have a route login That eventually will create cookie named access_token : someJWT
After the login the client will receive this cookie and will send it on every request to the server so no need to save the JWT on localStorage
How ever i didn’t found a way to pass this cookie on to Socket.iO
I tried to use express session but this will pass the session cookie to the socket and not the one i need
Server Side login route :
const login = async (req, res) => {
const {email, password} = req.body
const user = await UserModel.findOne({email})
const isMatch = await user.checkPassword(password)
if (isMatch) {
const userToken = JwtService.createToken(user.id)
return res.cookie("access_token", userToken, {
httpOnly: true,
secure: process.env.NODE_ENV === "production"
}).status(200).json({user:user.toJSON(),message: 'login success'})
}
}
Socket :
this.io = new socketio.Server(expressServer, {cors: {origin: 'http://localhost:3000'}})
this.io.use((socket,next)=>{
console.log(socket.handshake.headers.cookie); // undefiend
next()
})
Client :
this.socket = socketIOClient(process.env.SOCKET_BASE_URL, {auth: {userId}});
Server :
import express, {RequestHandler} from 'express';
import http from 'http'
import cookieParser from "cookie-parser"
import cors from 'cors';
import {router} from '@router';
import dotenv from 'dotenv'
import mongoose from 'mongoose';
import {SocketService} from "@services";
const expressApp = express();
const port = process.env.PORT || 3001;
dotenv.config()
expressApp.use(cors({
origin: true,
credentials: true
}));
expressApp.use(express.json() as RequestHandler);
expressApp.use(cookieParser());
expressApp.use('/', router)
const httpServer = http.createServer(expressApp);
new SocketService(httpServer)
httpServer.listen(port, async () => {
console.log(`server is listening on ${port}`);
try {
await mongoose.connect('mongodb://guess-it-mongo-dev:27017/guess-it', {connectTimeoutMS: 1000});
console.log('connected to mongo server')
} catch (e) {
console.log(e);
}
});
CodePudding user response:
1. Solution
Assuming that you have only one cookie witch is your jwt
, you could get it with the socket
param like so :
const token = socket.handshake.headers.cookie.split("=")[1];
If you have many cookies, you need to use some cookie parser and give it the socket.handshake.headers.cookie
to parse it, for example:
function getCookie(cName) {
const name = cName "=";
const cDecoded = decodeURIComponent(socket.handshake.headers.cookie);
const cArr = cDecoded.split(';');
let res;
cArr.forEach(val => {
if (val.indexOf(name) === 0) res = val.substring(name.length);
})
return res;
}
const token = getCookie("jwt"); // if your token is called jwt.
2. Troubleshot
Make you are setting up your app and socket this way to have them as a single server:
const app = express();
const http = require("http");
const server = http.createServer(app);
const { Server } = require("socket.io");
const io = new Server(server);
server.listen(9000, () => {
console.log("server runnig on port " 9000);
});
And the client should be connecting like this :
import { io } from "socket.io-client";
io(process.env.SOCKET_BASE_URL, {
transports: ["websocket"],
});
3. An use case
For example, in the code below, I am authenticating every connection with a middleware :
io.use((socket, next) => {
const token = socket.handshake.headers.cookie.split("=")[1];
if (token) {
jwt.verify(token, process.env.SECRET, (err, decodedToken) => {
if (err) {
next(new Error("invalid"));
} else {
User.findById(decodedToken.id, function (err, user) {
if (err) {
next(new Error("invalid"));
} else {
next();
}
});
}
});
} else {
next(new Error("invalid"));
}
});
//if authentication is ok, the code below will get executed
io.on("connection", (socket) => {
// do things
})