Reputation: 1097
I have a login route that eventually create a jwt cookie named access_token
. After the login the client will receive this cookie and will send it on every request. However I didn’t found a way to pass this cookie on to Socket.io.
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);
}
});
Upvotes: 2
Views: 1402
Reputation: 45835
Assuming that you have only one cookie which 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.
If the given solution is not working for you, make sure you are setting up your app and socket this way to have them as a single server (feel free to change the port):
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 (with the same port as the server) :
import { io } from "socket.io-client";
io("http://localhost:9000/", {
transports: ["websocket"],
});
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
})
Upvotes: 2