workspace-v1/shared/catalog/auth/_reference/jwt.strategy.reference.ts
rckrdmrd cb4c0681d3 feat(workspace): Add new projects and update architecture
New projects created:
- michangarrito (marketplace mobile)
- template-saas (SaaS template)
- clinica-dental (dental ERP)
- clinica-veterinaria (veterinary ERP)

Architecture updates:
- Move catalog from core/ to shared/
- Add MCP servers structure and templates
- Add git management scripts
- Update SUBREPOSITORIOS.md with 15 new repos
- Update .gitignore for new projects

Repository infrastructure:
- 4 main repositories
- 11 subrepositorios
- Gitea remotes configured

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 04:43:28 -06:00

97 lines
2.8 KiB
TypeScript

/**
* JWT STRATEGY - REFERENCE IMPLEMENTATION
*
* @description Estrategia de autenticación JWT para NestJS/Passport.
* Valida tokens JWT y extrae payload del usuario.
*
* @usage Copiar y adaptar según necesidades del proyecto.
* @origin gamilit/apps/backend/src/modules/auth/strategies/jwt.strategy.ts
*/
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { ConfigService } from '@nestjs/config';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
// Adaptar import según proyecto
// import { User } from '../entities';
/**
* Payload del JWT
*
* @property sub - ID del usuario (auth.users.id)
* @property email - Email del usuario
* @property role - Rol del usuario
* @property iat - Issued at (timestamp)
* @property exp - Expiration (timestamp)
*/
interface JwtPayload {
sub: string;
email: string;
role: string;
iat: number;
exp: number;
}
/**
* Usuario validado que se inyecta en req.user
*/
interface ValidatedUser {
id: string;
email: string;
role: string;
}
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
constructor(
private readonly configService: ConfigService,
@InjectRepository(User, 'auth')
private readonly userRepository: Repository<User>,
) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: configService.get<string>('JWT_SECRET'),
});
}
/**
* Validar payload del JWT
*
* @description Este método es llamado por Passport después de verificar
* la firma y expiración del token. El valor retornado se asigna a req.user.
*
* @param payload - Payload decodificado del JWT
* @returns Usuario validado para inyectar en request
* @throws UnauthorizedException si el usuario no existe o está inactivo
*/
async validate(payload: JwtPayload): Promise<ValidatedUser> {
// Opción 1: Solo validar que el payload es válido (más rápido)
// return { id: payload.sub, email: payload.email, role: payload.role };
// Opción 2: Verificar que el usuario existe en BD (más seguro)
const user = await this.userRepository.findOne({
where: { id: payload.sub },
select: ['id', 'email', 'role'],
});
if (!user) {
throw new UnauthorizedException('Usuario no encontrado');
}
// Opción 3: También verificar status (si aplica)
// if (user.status !== 'active') {
// throw new UnauthorizedException('Usuario inactivo');
// }
return {
id: user.id,
email: user.email,
role: user.role,
};
}
}