From e957fc5c5060961d231d1773022267e34f82925b Mon Sep 17 00:00:00 2001 From: Mayank Mishra Date: Tue, 9 Dec 2025 12:07:03 +0530 Subject: [PATCH] Add token blacklist check in JWT middlewares to enhance session management and security --- src/common/middlewares/jwt/authForHost.ts | 27 ++++++++++++----- .../middlewares/jwt/authForMinglarAdmin.ts | 29 +++++++++++++------ .../jwt/authForMinglarAdminHost.ts | 11 +++++++ .../jwt/authForOnlyMinglarAdmin.ts | 29 +++++++++++++------ src/common/middlewares/jwt/authForUser.ts | 27 ++++++++++++----- src/modules/host/services/token.service.ts | 8 +++++ 6 files changed, 97 insertions(+), 34 deletions(-) diff --git a/src/common/middlewares/jwt/authForHost.ts b/src/common/middlewares/jwt/authForHost.ts index 5dddc5c..342d441 100644 --- a/src/common/middlewares/jwt/authForHost.ts +++ b/src/common/middlewares/jwt/authForHost.ts @@ -49,6 +49,17 @@ export async function verifyHostToken(token: string): Promise<{ id: number; role include: { role: true }, }); + const latestToken = await prisma.token.findFirst({ + where: { + userXid: userId + }, + orderBy: { id: 'desc' } + }) + + if (latestToken.isBlackListed == true) { + throw new ApiError(401, "This session is expired. Please login.") + } + if (!user) { throw new ApiError(httpStatus.UNAUTHORIZED, 'User not found'); } @@ -89,7 +100,7 @@ const verifyCallback = async ( try { const userInfo = await verifyHostToken(token); - + // Attach user to request req.user = { id: userInfo.id.toString(), role: userInfo.role }; @@ -104,12 +115,12 @@ const verifyCallback = async ( */ const authForHost = () => - async (req: Request, res: Response, next: NextFunction) => { - return new Promise((resolve, reject) => { - verifyCallback(req, resolve, reject); - }) - .then(() => next()) - .catch((err) => next(err)); - }; + async (req: Request, res: Response, next: NextFunction) => { + return new Promise((resolve, reject) => { + verifyCallback(req, resolve, reject); + }) + .then(() => next()) + .catch((err) => next(err)); + }; export default authForHost; diff --git a/src/common/middlewares/jwt/authForMinglarAdmin.ts b/src/common/middlewares/jwt/authForMinglarAdmin.ts index cbf6d65..9f31262 100644 --- a/src/common/middlewares/jwt/authForMinglarAdmin.ts +++ b/src/common/middlewares/jwt/authForMinglarAdmin.ts @@ -49,6 +49,17 @@ export async function verifyMinglarAdminToken(token: string): Promise<{ id: numb include: { role: true }, }); + const latestToken = await prisma.token.findFirst({ + where: { + userXid: userId + }, + orderBy: { id: 'desc' } + }) + + if (latestToken.isBlackListed == true) { + throw new ApiError(401, "This session is expired. Please login.") + } + if (!user) { throw new ApiError(httpStatus.UNAUTHORIZED, 'User not found'); } @@ -62,7 +73,7 @@ export async function verifyMinglarAdminToken(token: string): Promise<{ id: numb if (![ROLE.MINGLAR_ADMIN, ROLE.CO_ADMIN, ROLE.ACCOUNT_MANAGER].includes(user.roleXid)) { throw new ApiError(httpStatus.FORBIDDEN, 'Access denied.'); } - + return { id: user.id, role: user.role?.roleName }; } catch (error) { @@ -90,7 +101,7 @@ const verifyCallback = async ( try { const userInfo = await verifyMinglarAdminToken(token); - + // Attach user to request req.user = { id: userInfo.id.toString(), role: userInfo.role }; @@ -105,12 +116,12 @@ const verifyCallback = async ( */ const authForHost = () => - async (req: Request, res: Response, next: NextFunction) => { - return new Promise((resolve, reject) => { - verifyCallback(req, resolve, reject); - }) - .then(() => next()) - .catch((err) => next(err)); - }; + async (req: Request, res: Response, next: NextFunction) => { + return new Promise((resolve, reject) => { + verifyCallback(req, resolve, reject); + }) + .then(() => next()) + .catch((err) => next(err)); + }; export default authForHost; diff --git a/src/common/middlewares/jwt/authForMinglarAdminHost.ts b/src/common/middlewares/jwt/authForMinglarAdminHost.ts index 03967a4..5234989 100644 --- a/src/common/middlewares/jwt/authForMinglarAdminHost.ts +++ b/src/common/middlewares/jwt/authForMinglarAdminHost.ts @@ -51,6 +51,17 @@ export async function verifyMinglarAdminHostToken(token: string): Promise<{ id: include: { role: true }, }); + const latestToken = await prisma.token.findFirst({ + where: { + userXid: userId + }, + orderBy: { id: 'desc' } + }) + + if (latestToken.isBlackListed == true) { + throw new ApiError(401, "This session is expired. Please login.") + } + if (!user) { throw new ApiError(httpStatus.UNAUTHORIZED, 'User not found'); } diff --git a/src/common/middlewares/jwt/authForOnlyMinglarAdmin.ts b/src/common/middlewares/jwt/authForOnlyMinglarAdmin.ts index 270c511..f188472 100644 --- a/src/common/middlewares/jwt/authForOnlyMinglarAdmin.ts +++ b/src/common/middlewares/jwt/authForOnlyMinglarAdmin.ts @@ -49,6 +49,17 @@ export async function verifyOnlyMinglarAdminToken(token: string): Promise<{ id: include: { role: true }, }); + const latestToken = await prisma.token.findFirst({ + where: { + userXid: userId + }, + orderBy: { id: 'desc' } + }) + + if (latestToken.isBlackListed == true) { + throw new ApiError(401, "This session is expired. Please login.") + } + if (!user) { throw new ApiError(httpStatus.UNAUTHORIZED, 'User not found'); } @@ -62,7 +73,7 @@ export async function verifyOnlyMinglarAdminToken(token: string): Promise<{ id: if (user.roleXid !== ROLE.MINGLAR_ADMIN) { throw new ApiError(httpStatus.FORBIDDEN, 'Access denied.'); } - + return { id: user.id, role: user.role?.roleName }; } catch (error) { @@ -90,7 +101,7 @@ const verifyCallback = async ( try { const userInfo = await verifyOnlyMinglarAdminToken(token); - + // Attach user to request req.user = { id: userInfo.id.toString(), role: userInfo.role }; @@ -105,12 +116,12 @@ const verifyCallback = async ( */ const authForHost = () => - async (req: Request, res: Response, next: NextFunction) => { - return new Promise((resolve, reject) => { - verifyCallback(req, resolve, reject); - }) - .then(() => next()) - .catch((err) => next(err)); - }; + async (req: Request, res: Response, next: NextFunction) => { + return new Promise((resolve, reject) => { + verifyCallback(req, resolve, reject); + }) + .then(() => next()) + .catch((err) => next(err)); + }; export default authForHost; diff --git a/src/common/middlewares/jwt/authForUser.ts b/src/common/middlewares/jwt/authForUser.ts index 09124ce..7717194 100644 --- a/src/common/middlewares/jwt/authForUser.ts +++ b/src/common/middlewares/jwt/authForUser.ts @@ -50,6 +50,17 @@ export async function verifyUserToken(token: string): Promise<{ id: number; role include: { role: true }, }); + const latestToken = await prisma.token.findFirst({ + where: { + userXid: userId + }, + orderBy: { id: 'desc' } + }) + + if (latestToken.isBlackListed == true) { + throw new ApiError(401, "This session is expired. Please login.") + } + if (!user) { throw new ApiError(httpStatus.UNAUTHORIZED, 'User not found'); } @@ -90,7 +101,7 @@ const verifyCallback = async ( try { const userInfo = await verifyUserToken(token); - + // Attach user to request req.user = { id: userInfo.id.toString(), role: userInfo.role }; @@ -105,12 +116,12 @@ const verifyCallback = async ( */ const authForHost = () => - async (req: Request, res: Response, next: NextFunction) => { - return new Promise((resolve, reject) => { - verifyCallback(req, resolve, reject); - }) - .then(() => next()) - .catch((err) => next(err)); - }; + async (req: Request, res: Response, next: NextFunction) => { + return new Promise((resolve, reject) => { + verifyCallback(req, resolve, reject); + }) + .then(() => next()) + .catch((err) => next(err)); + }; export default authForHost; diff --git a/src/modules/host/services/token.service.ts b/src/modules/host/services/token.service.ts index d4f350b..403744b 100644 --- a/src/modules/host/services/token.service.ts +++ b/src/modules/host/services/token.service.ts @@ -53,6 +53,10 @@ export class TokenService { config.jwt.secret ); + await this.prisma.token.deleteMany({ + where: { userXid: user_xid } + }) + await this.prisma.token.create({ data: { token: refreshToken.token, @@ -100,6 +104,10 @@ export class TokenService { config.jwt.secret ); + await this.prisma.token.deleteMany({ + where: { userXid: user_xid } + }) + await this.prisma.token.create({ data: { token: refreshToken.token,