6190f3dd39
- Create LocalStrategy (username/password via argon2) and JwtStrategy (cookie extractor) - Create JwtAuthGuard with @Public() decorator support for route opt-out - Create RolesGuard checking SUPER_ADMIN/ADMIN/USER roles per D-12 - Create AuthService with validateUser, login (30-day httpOnly cookie), logout - Create AuthController with POST /auth/login, POST /auth/logout, GET /auth/me - Create LoginDto with class-validator decorators - Create @Public, @Roles, @CurrentUser decorators - Update main.ts with ValidationPipe, CORS credentials, cookie-parser - Install cookie-parser for httpOnly JWT cookie support
36 lines
923 B
TypeScript
36 lines
923 B
TypeScript
import { Injectable } from '@nestjs/common';
|
|
import { ConfigService } from '@nestjs/config';
|
|
import { PassportStrategy } from '@nestjs/passport';
|
|
import { Strategy } from 'passport-jwt';
|
|
import { Request } from 'express';
|
|
|
|
/**
|
|
* Custom extractor that reads JWT from the httpOnly "session" cookie.
|
|
*/
|
|
function cookieExtractor(req: Request): string | null {
|
|
if (req && req.cookies) {
|
|
return req.cookies['session'] || null;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
@Injectable()
|
|
export class JwtStrategy extends PassportStrategy(Strategy) {
|
|
constructor(configService: ConfigService) {
|
|
super({
|
|
jwtFromRequest: cookieExtractor,
|
|
ignoreExpiration: false,
|
|
secretOrKey: configService.get<string>('JWT_SECRET', 'fallback-secret'),
|
|
});
|
|
}
|
|
|
|
async validate(payload: any) {
|
|
return {
|
|
id: payload.sub,
|
|
username: payload.username,
|
|
role: payload.role,
|
|
tenantId: payload.tenantId,
|
|
};
|
|
}
|
|
}
|