import { Injectable, UnauthorizedException } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { PassportStrategy } from '@nestjs/passport'; import { Strategy, ExtractJwt } from 'passport-jwt'; import { AuthService } from './auth.service'; export interface JwtPayload { sub: string; // User ID email: string; iat: number; // Issued at exp: number; // Expires at iss: string; // Issuer aud: string; // Audience } @Injectable() export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') { constructor( private readonly configService: ConfigService, private readonly authService: AuthService, ) { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), ignoreExpiration: false, secretOrKey: configService.get('JWT_SECRET'), issuer: 'seo-image-renamer', audience: 'seo-image-renamer-users', }); } async validate(payload: JwtPayload) { try { // Verify the user still exists and is active const user = await this.authService.validateUserById(payload.sub); if (!user) { throw new UnauthorizedException('User not found'); } if (!user.isActive) { throw new UnauthorizedException('User account is inactive'); } // Return user object that will be attached to request return { id: user.id, email: user.email, plan: user.plan, quotaRemaining: user.quotaRemaining, isActive: user.isActive, }; } catch (error) { throw new UnauthorizedException('Invalid token'); } } }