- Add JWT auth guard with Bearer token and cookie support - Update .env.example files with PASSWORD_PEPPER documentation - Update seeder to use PASSWORD_PEPPER for password hashing - Update seeder README with hash verification examples - Fix frontend auth and page components - Update backend JWT service and seed migration
51 lines
1.5 KiB
TypeScript
51 lines
1.5 KiB
TypeScript
import {
|
|
Injectable,
|
|
CanActivate,
|
|
ExecutionContext,
|
|
UnauthorizedException,
|
|
} from '@nestjs/common';
|
|
import { ConfigService } from '@nestjs/config';
|
|
import * as jwt from 'jsonwebtoken';
|
|
|
|
@Injectable()
|
|
export class JwtAuthGuard implements CanActivate {
|
|
constructor(private readonly configService: ConfigService) { }
|
|
|
|
canActivate(context: ExecutionContext): boolean {
|
|
const request = context.switchToHttp().getRequest();
|
|
const token = this.extractToken(request);
|
|
|
|
if (!token) {
|
|
throw new UnauthorizedException('Missing authentication token');
|
|
}
|
|
|
|
try {
|
|
const secret = this.configService.get<string>('JWT_SECRET');
|
|
if (!secret) {
|
|
throw new UnauthorizedException('JWT secret not configured');
|
|
}
|
|
|
|
const payload = jwt.verify(token, secret);
|
|
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 cookie
|
|
const cookies = request.cookies;
|
|
if (cookies?.jwt) {
|
|
return cookies.jwt;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|