import { Injectable, UnauthorizedException, ConflictException } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import { ConfigService } from '@nestjs/config'; import * as bcrypt from 'bcrypt'; import { UsersService } from '../users/users.service'; import { RegisterDto } from './dto/register.dto'; import { LoginDto } from './dto/login.dto'; @Injectable() export class AuthService { constructor( private usersService: UsersService, private jwtService: JwtService, private configService: ConfigService, ) {} async register(registerDto: RegisterDto) { const existingUser = await this.usersService.findByEmail(registerDto.email); if (existingUser) { throw new ConflictException('Email already registered'); } const hashedPassword = await bcrypt.hash(registerDto.password, 12); const user = await this.usersService.create({ ...registerDto, password: hashedPassword, }); const tokens = await this.generateTokens(user.id, user.email, user.role); return { user: { id: user.id, email: user.email, firstName: user.firstName, lastName: user.lastName, role: user.role, }, ...tokens, }; } async login(loginDto: LoginDto) { const user = await this.usersService.findByEmail(loginDto.email); if (!user) { throw new UnauthorizedException('Invalid credentials'); } const isPasswordValid = await bcrypt.compare(loginDto.password, user.password); if (!isPasswordValid) { throw new UnauthorizedException('Invalid credentials'); } if (!user.isActive) { throw new UnauthorizedException('Account is deactivated'); } const tokens = await this.generateTokens(user.id, user.email, user.role); return { user: { id: user.id, email: user.email, firstName: user.firstName, lastName: user.lastName, role: user.role, }, ...tokens, }; } async refreshToken(refreshToken: string) { try { const payload = this.jwtService.verify(refreshToken, { secret: this.configService.get('jwt.refreshSecret'), }); const user = await this.usersService.findById(payload.sub); if (!user || !user.isActive) { throw new UnauthorizedException(); } return this.generateTokens(user.id, user.email, user.role); } catch { throw new UnauthorizedException('Invalid refresh token'); } } private async generateTokens(userId: string, email: string, role: string) { const payload = { sub: userId, email, role }; const [accessToken, refreshToken] = await Promise.all([ this.jwtService.signAsync(payload), this.jwtService.signAsync(payload, { secret: this.configService.get('jwt.refreshSecret'), expiresIn: this.configService.get('jwt.refreshExpiresIn'), }), ]); return { accessToken, refreshToken }; } }