Files
MinglarBackendNestJS/src/common/middlewares/jwt/authForHost.ts

127 lines
3.2 KiB
TypeScript

import jwt from 'jsonwebtoken';
import httpStatus from 'http-status';
import { Request, Response, NextFunction } from 'express';
import ApiError from '../../utils/helper/ApiError';
import config from '../../../config/config';
import { ROLE } from '@/common/utils/constants/common.constant';
import { prisma } from '../../database/prisma.client';
interface DecodedToken {
id?: number;
sub?: string | number;
role?: string;
iat: number;
exp: number;
}
interface UserPayload {
id: string;
role?: string;
}
declare module 'express-serve-static-core' {
interface Request {
user?: UserPayload;
}
}
/**
* Core authentication function - verifies JWT and validates Host user
* Can be used by both Express middleware and Lambda handlers
*/
export async function verifyHostToken(token: string): Promise<{ id: number; role?: string }> {
if (!token) {
throw new ApiError(httpStatus.UNAUTHORIZED, 'Please authenticate');
}
try {
const decoded = jwt.verify(token, config.jwt.secret) as unknown as DecodedToken;
const userId = decoded.id ?? (decoded.sub ? Number(decoded.sub) : null);
if (!userId) {
throw new ApiError(httpStatus.UNAUTHORIZED, 'Invalid token payload');
}
// ✅ Fetch user from Prisma (Host user only)
const user = await prisma.user.findUnique({
where: { id: userId },
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');
}
// ✅ Check if user is active
if (user.isActive === false) {
throw new ApiError(httpStatus.FORBIDDEN, 'Your account is deactivated by admin.');
}
// ✅ Check Host role (role_xid = 4)
if (user.roleXid !== ROLE.HOST) {
throw new ApiError(httpStatus.FORBIDDEN, 'Access denied.');
}
return { id: user.id, role: user.role?.roleName };
} catch (error) {
if (error instanceof jwt.TokenExpiredError) {
throw new ApiError(httpStatus.UNAUTHORIZED, 'Your session has expired. Please log in again.');
}
if (error instanceof ApiError) {
throw error;
}
throw new ApiError(httpStatus.FORBIDDEN, 'Invalid or expired authentication token.');
}
}
/**
* Verifies JWT and validates Host user (role_xid = 4)
*/
const verifyCallback = async (
req: Request,
resolve: (value?: unknown) => void,
reject: (reason?: Error) => void
) => {
const token = req.header('x-auth-token') || req.cookies?.accessToken;
try {
const userInfo = await verifyHostToken(token);
// Attach user to request
req.user = { id: userInfo.id.toString(), role: userInfo.role };
resolve();
} catch (error) {
return reject(error as Error);
}
};
/**
* Express middleware — use as `auth()` in routes
*/
const authForHost =
() =>
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;