import { Injectable } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { PassportStrategy } from '@nestjs/passport'; import { Strategy } from 'passport-jwt'; import { Request } from 'express'; import type { AuthUser, JwtPayload } from '../types/auth-user'; /** * Custom extractor that reads JWT from the httpOnly "session" cookie. */ function cookieExtractor(req: Request): string | null { if (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('JWT_SECRET', 'fallback-secret'), }); } async validate(payload: JwtPayload): Promise { return { id: payload.sub, username: payload.username, role: payload.role, tenantId: payload.tenantId, // Ein vor dieser Aenderung ausgestelltes Token traegt diesen Anspruch // nicht; der strenge Vergleich ergibt dann false, laufende Sitzungen // verhalten sich unveraendert (260921-fi3, D-01 — keine Aussperrwelle). mustChangePassword: payload.mustChangePassword === true, }; } }