diff --git a/apps/backend/index.ts b/apps/backend/index.ts index ac50116..230e6fc 100755 --- a/apps/backend/index.ts +++ b/apps/backend/index.ts @@ -16,7 +16,7 @@ import signedUrlCache from '@/src/lib/signed-url-cache'; import { seed } from '@/src/db/seed'; import '@/src/jobs/jobs-index'; import { startAutomatedJobs } from '@/src/lib/automatedJobs'; -import { verifyToken } from '@/src/lib/jwt-utils'; +import { verifyToken, UserJWTPayload, StaffJWTPayload } from '@/src/lib/jwt-utils'; seed() initFunc() @@ -77,30 +77,35 @@ app.use('/api/trpc', createExpressMiddleware({ if (authHeader?.startsWith('Bearer ')) { const token = authHeader.substring(7); try { - const decoded = (await verifyToken(token)) as any; + const decoded = await verifyToken(token); // Check if this is a staff token (has staffId) - if (decoded.staffId) { + if ('staffId' in decoded) { + const staffPayload = decoded as StaffJWTPayload; // This is a staff token, verify staff exists const staff = await db.query.staffUsers.findFirst({ - where: eq(staffUsers.id, decoded.staffId), + where: eq(staffUsers.id, staffPayload.staffId), }); if (staff) { - user=staffUser staffUser = { id: staff.id, name: staff.name, }; } } else { - + const userPayload = decoded as UserJWTPayload; // This is a regular user token - user = decoded; + user = { + userId: userPayload.userId, + name: userPayload.name, + email: userPayload.email, + mobile: userPayload.mobile, + }; // Check if user is suspended const details = await db.query.userDetails.findFirst({ - where: eq(userDetails.userId, user.userId), + where: eq(userDetails.userId, userPayload.userId), }); if (details?.isSuspended) { diff --git a/apps/backend/src/lib/jwt-utils.ts b/apps/backend/src/lib/jwt-utils.ts index 739c5ff..3e95bc7 100644 --- a/apps/backend/src/lib/jwt-utils.ts +++ b/apps/backend/src/lib/jwt-utils.ts @@ -1,6 +1,20 @@ -import { SignJWT, jwtVerify, errors } from 'jose'; +import { SignJWT, jwtVerify, errors, JWTPayload } from 'jose'; import { jwtSecret } from './env-exporter'; +// JWT Payload Types +export interface UserJWTPayload extends JWTPayload { + userId: number; + name?: string; + email?: string; + mobile?: string; + roles?: string[]; +} + +export interface StaffJWTPayload extends JWTPayload { + staffId: number; + name: string; +} + // Convert string secret to Uint8Array const getSecret = () => { if (!jwtSecret) { @@ -14,7 +28,7 @@ const getSecret = () => { * Compatible with tokens signed by jsonwebtoken library */ export const signToken = async ( - payload: Record, + payload: Record, expiresIn: string = '7d' ): Promise => { const secret = getSecret(); @@ -30,7 +44,7 @@ export const signToken = async ( * Verify a JWT token * Compatible with tokens signed by jsonwebtoken library */ -export const verifyToken = async (token: string): Promise> => { +export const verifyToken = async (token: string): Promise => { try { const secret = getSecret(); const { payload } = await jwtVerify(token, secret); @@ -49,8 +63,10 @@ export const verifyToken = async (token: string): Promise> = /** * Check if an error is a JWT-related error */ -export const isJWTError = (error: any): boolean => { +export const isJWTError = (error: unknown): boolean => { return error instanceof errors.JOSEError || - error?.message?.includes('token') || - error?.message?.includes('JWT'); + (error instanceof Error && ( + error.message.includes('token') || + error.message.includes('JWT') + )); }; diff --git a/apps/backend/src/middleware/auth.middleware.ts b/apps/backend/src/middleware/auth.middleware.ts index 11495b2..b76061e 100644 --- a/apps/backend/src/middleware/auth.middleware.ts +++ b/apps/backend/src/middleware/auth.middleware.ts @@ -3,7 +3,7 @@ import { db } from '@/src/db/db_index' import { staffUsers, userDetails } from '@/src/db/schema' import { eq } from 'drizzle-orm'; import { ApiError } from '@/src/lib/api-error' -import { verifyToken } from '@/src/lib/jwt-utils' +import { verifyToken, UserJWTPayload, StaffJWTPayload } from '@/src/lib/jwt-utils' interface AuthenticatedRequest extends Request { user?: { @@ -29,13 +29,14 @@ export const authenticateUser = async (req: AuthenticatedRequest, res: Response, const token = authHeader.substring(7); console.log(req.headers) - const decoded = (await verifyToken(token)) as any; + const decoded = await verifyToken(token); // Check if this is a staff token (has staffId) - if (decoded.staffId) { + if ('staffId' in decoded) { + const staffPayload = decoded as StaffJWTPayload; // This is a staff token, verify staff exists const staff = await db.query.staffUsers.findFirst({ - where: eq(staffUsers.id, decoded.staffId), + where: eq(staffUsers.id, staffPayload.staffId), }); if (!staff) { @@ -47,12 +48,18 @@ export const authenticateUser = async (req: AuthenticatedRequest, res: Response, name: staff.name, }; } else { + const userPayload = decoded as UserJWTPayload; // This is a regular user token - req.user = decoded; + req.user = { + userId: userPayload.userId, + name: userPayload.name, + email: userPayload.email, + mobile: userPayload.mobile, + }; // Check if user is suspended const details = await db.query.userDetails.findFirst({ - where: eq(userDetails.userId, decoded.userId), + where: eq(userDetails.userId, userPayload.userId), }); if (details?.isSuspended) { diff --git a/apps/backend/src/middleware/staff-auth.ts b/apps/backend/src/middleware/staff-auth.ts index 0ce2df3..db9d9ff 100644 --- a/apps/backend/src/middleware/staff-auth.ts +++ b/apps/backend/src/middleware/staff-auth.ts @@ -3,7 +3,7 @@ import { db } from '@/src/db/db_index' import { staffUsers } from '@/src/db/schema' import { eq } from 'drizzle-orm'; import { ApiError } from '@/src/lib/api-error' -import { verifyToken } from '@/src/lib/jwt-utils' +import { verifyToken, StaffJWTPayload } from '@/src/lib/jwt-utils' // Extend Request interface to include staffUser declare global { @@ -20,9 +20,10 @@ declare global { /** * Verify JWT token and extract payload */ -const verifyStaffToken = async (token: string) => { +const verifyStaffToken = async (token: string): Promise => { try { - return await verifyToken(token); + const payload = await verifyToken(token); + return payload as StaffJWTPayload; } catch (error) { throw new ApiError('Access denied. Invalid auth credentials', 401); } @@ -47,7 +48,7 @@ export const authenticateStaff = async (req: Request, res: Response, next: NextF } // Verify token and extract payload - const decoded = (await verifyStaffToken(token)) as any; + const decoded = await verifyStaffToken(token); // Verify staffId exists in token if (!decoded.staffId) {