import { Injectable, CanActivate, ExecutionContext, UnauthorizedException, } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { Reflector } from '@nestjs/core'; import * as jwt from 'jsonwebtoken'; import { IS_PUBLIC_KEY } from './public.decorator'; @Injectable() export class JwtAuthGuard implements CanActivate { constructor( private readonly configService: ConfigService, private readonly reflector: Reflector, ) { } canActivate(context: ExecutionContext): boolean { // 1. Check if route is public const isPublic = this.reflector.getAllAndOverride(IS_PUBLIC_KEY, [ context.getHandler(), context.getClass(), ]); if (isPublic) { return true; } const request = context.switchToHttp().getRequest(); const token = this.extractToken(request); if (!token) { throw new UnauthorizedException('Missing authentication token'); } try { const secret = this.configService.get('JWT_SECRET'); if (!secret) { throw new UnauthorizedException('JWT secret not configured'); } const payload = jwt.verify(token, secret) as any; // 2. Role Check (from HEAD) // Only allow admin users to access backoffice if (payload.role !== 'admin' && payload.role !== 'superadmin') { throw new UnauthorizedException('Admin access required'); } request.user = payload; return true; } catch { throw new UnauthorizedException('Invalid or expired token'); } } private extractToken(request: any): string | null { // 1. Try Authorization header first const authHeader = request.headers?.authorization; if (authHeader && authHeader.startsWith('Bearer ')) { return authHeader.slice(7); } // 2. Fallback to cookies (support both names) const cookies = request.cookies; if (cookies?.jwt) { return cookies.jwt; } if (cookies?.auth_token) { return cookies.auth_token; } return null; } }