import { CanActivate, ExecutionContext, Injectable, UnauthorizedException, } from "@nestjs/common"; import { JwtService } from "@nestjs/jwt"; import type { Request } from "express"; export interface JwtPayload { sub: string; username: string; role: "user" | "admin"; } function bearerToken(request: Request): string | null { const header = request.headers.authorization; if (!header?.startsWith("Bearer ")) return null; return header.slice("Bearer ".length); } @Injectable() export class JwtAuthGuard implements CanActivate { constructor(private readonly jwt: JwtService) {} async canActivate(context: ExecutionContext): Promise { const request = context.switchToHttp().getRequest(); const token = bearerToken(request); if (!token) throw new UnauthorizedException("missing bearer token"); try { const payload = await this.jwt.verifyAsync(token); (request as Request & { user: JwtPayload }).user = payload; return true; } catch { throw new UnauthorizedException("invalid or expired token"); } } }