Enhance socket authentication with access and refresh token handling
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import { Server, Socket } from "socket.io";
|
import { Server, Socket } from "socket.io";
|
||||||
import jwt from "jsonwebtoken";
|
import jwt from "jsonwebtoken";
|
||||||
import { eventHandlerMap } from "../events/eventHandaler";
|
import { eventHandlerMap } from "../events/eventHandaler";
|
||||||
|
import { existingUserData } from "../../shared/services/AuthService";
|
||||||
|
|
||||||
interface UserPayload {
|
interface UserPayload {
|
||||||
userId: string;
|
userId: string;
|
||||||
@@ -16,7 +17,7 @@ interface UserSocketInfo {
|
|||||||
|
|
||||||
const connectedUsersByOrg: { [organization: string]: UserSocketInfo[] } = {};
|
const connectedUsersByOrg: { [organization: string]: UserSocketInfo[] } = {};
|
||||||
|
|
||||||
export const SocketServer = (io: Server) => {
|
export const SocketServer = async (io: Server) => {
|
||||||
|
|
||||||
// ✅ Declare all namespaces here
|
// ✅ Declare all namespaces here
|
||||||
const namespaceNames = ["/edge", "/project", "/graph"];
|
const namespaceNames = ["/edge", "/project", "/graph"];
|
||||||
@@ -26,55 +27,91 @@ export const SocketServer = (io: Server) => {
|
|||||||
// ✅ Attach common handler to each namespace
|
// ✅ Attach common handler to each namespace
|
||||||
namespaceNames.forEach((nspName) => {
|
namespaceNames.forEach((nspName) => {
|
||||||
const namespace = io.of(nspName);
|
const namespace = io.of(nspName);
|
||||||
|
namespace.use(async (socket: Socket, next) => {
|
||||||
|
try {
|
||||||
|
const accessToken = socket.handshake.auth.accessToken as string;
|
||||||
|
const refreshToken = socket.handshake.auth.refreshToken as string;
|
||||||
|
if (!accessToken) return next(new Error("No access token provided"));
|
||||||
|
const jwt_secret = process.env.JWT_SECRET as string;
|
||||||
|
try {
|
||||||
|
const decoded = jwt.verify(accessToken, jwt_secret) as UserPayload;
|
||||||
|
|
||||||
// namespace.use((socket: Socket, next) => {
|
const mailExistance = await existingUserData(decoded.email, decoded.organization);
|
||||||
// try {
|
if (!mailExistance) {
|
||||||
// socket.handshake.auth
|
return next(new Error("Unauthorized user - not in system"));
|
||||||
// console.log('socket.handshake.auth: ', socket.handshake.auth);
|
}
|
||||||
// const token = socket.handshake.auth.token as string;
|
|
||||||
// if (!token) return next(new Error("No token provided"));
|
|
||||||
|
|
||||||
// const jwt_secret = process.env.JWT_SECRET as string;
|
(socket as any).user = decoded;
|
||||||
// const decoded = jwt.verify(token, jwt_secret) as UserPayload;
|
return next();
|
||||||
|
|
||||||
// (socket as any).user = decoded;
|
} catch (err: any) {
|
||||||
// next();
|
if (err.name === "TokenExpiredError") {
|
||||||
// } catch (err) {
|
if (!refreshToken) {
|
||||||
// next(new Error("Authentication failed"));
|
return next(new Error("Token expired and no refresh token provided"));
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const refreshSecret = process.env.REFRESH_JWT_SECRET as string;
|
||||||
|
const decodedRefresh = jwt.verify(refreshToken, refreshSecret) as UserPayload;
|
||||||
|
const mailExistance = await existingUserData(decodedRefresh.email, decodedRefresh.organization);
|
||||||
|
|
||||||
|
if (!mailExistance) {
|
||||||
|
return next(new Error("Unauthorized user - not in system"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate new access token
|
||||||
|
const newAccessToken = jwt.sign(
|
||||||
|
{ email: decodedRefresh.email, organization: decodedRefresh.organization },
|
||||||
|
jwt_secret,
|
||||||
|
{ expiresIn: "3h" } // adjust expiry
|
||||||
|
);
|
||||||
|
|
||||||
|
socket.emit("newAccessToken", newAccessToken);
|
||||||
|
|
||||||
|
(socket as any).user = decodedRefresh;
|
||||||
|
return next();
|
||||||
|
} catch (refreshErr) {
|
||||||
|
return next(new Error("Refresh token expired or invalid"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return next(new Error("Invalid token"));
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
return next(new Error("Authentication error"));
|
||||||
|
}
|
||||||
|
});
|
||||||
namespace.on("connection", (socket: Socket) => {
|
namespace.on("connection", (socket: Socket) => {
|
||||||
console.log(`✅ Connected to namespace ${nspName}: ${socket.id}`);
|
const user = (socket as any).user as UserPayload;
|
||||||
// const user = (socket as any).user as UserPayload;
|
const { organization, userId } = user;
|
||||||
// const { organization, userId } = user;
|
|
||||||
|
|
||||||
// if (!onlineUsers[organization]) onlineUsers[organization] = new Set();
|
if (!onlineUsers[organization]) onlineUsers[organization] = new Set();
|
||||||
// onlineUsers[organization].add(socket.id);
|
onlineUsers[organization].add(socket.id);
|
||||||
|
|
||||||
// if (!connectedUsersByOrg[organization]) connectedUsersByOrg[organization] = [];
|
if (!connectedUsersByOrg[organization]) connectedUsersByOrg[organization] = [];
|
||||||
// connectedUsersByOrg[organization].push({ socketId: socket.id, userId, organization });
|
connectedUsersByOrg[organization].push({ socketId: socket.id, userId, organization });
|
||||||
|
console.log(`✅ Connected to namespace ${nspName}: ${socket.id}`);
|
||||||
|
|
||||||
// 🎯 Common event handler
|
// Common event handler
|
||||||
socket.onAny((event: string, data: any, callback: any) => {
|
socket.onAny((event: string, data: any, callback: any) => {
|
||||||
const handler = eventHandlerMap[event];
|
const handler = eventHandlerMap[event];
|
||||||
if (handler) {
|
if (handler) {
|
||||||
handler(event, socket, io, data, connectedUsersByOrg, callback);
|
handler(event, socket, io, data, connectedUsersByOrg, callback);
|
||||||
} else {
|
} else {
|
||||||
console.warn(`⚠️ No handler found for event: ${event}`);
|
console.warn(` No handler found for event: ${event}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// socket.on("disconnect", () => {
|
socket.on("disconnect", () => {
|
||||||
// onlineUsers[organization]?.delete(socket.id);
|
onlineUsers[organization]?.delete(socket.id);
|
||||||
// if (onlineUsers[organization]?.size === 0) {
|
if (onlineUsers[organization]?.size === 0) {
|
||||||
// delete onlineUsers[organization];
|
delete onlineUsers[organization];
|
||||||
// }
|
}
|
||||||
// connectedUsersByOrg[organization] = connectedUsersByOrg[organization]?.filter(
|
connectedUsersByOrg[organization] = connectedUsersByOrg[organization]?.filter(
|
||||||
// (u) => u.socketId !== socket.id
|
(u) => u.socketId !== socket.id
|
||||||
// );
|
);
|
||||||
// });
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user