import { Injectable, UnauthorizedException } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { JwtService } from '@nestjs/jwt'; import { UsersService } from '../../users/services/users.service'; import { JwtPayload } from '../interfaces/jwt-payload.interface'; import { TokensResponse } from '../interfaces/tokens-response.interface'; @Injectable() export class AuthService { constructor( private readonly usersService: UsersService, private readonly jwtService: JwtService, private readonly configService: ConfigService, ) {} /** * Validate a user by GitHub ID */ async validateGithubUser( githubId: string, email: string, name: string, avatarUrl: string, ) { // Try to find the user by GitHub ID let user = await this.usersService.findByGithubId(githubId); // If user doesn't exist, create a new one if (!user) { user = await this.usersService.create({ githubId, name, avatar: avatarUrl, metadata: { email }, }); } return user; } /** * Generate JWT tokens (access and refresh) */ async generateTokens(userId: string): Promise { const payload: JwtPayload = { sub: userId }; const [accessToken, refreshToken] = await Promise.all([ this.jwtService.signAsync(payload), this.jwtService.signAsync( { ...payload, isRefreshToken: true }, { expiresIn: this.configService.get('JWT_REFRESH_EXPIRATION') || '7d', secret: this.configService.get('JWT_REFRESH_SECRET'), }, ), ]); return { accessToken, refreshToken, }; } /** * Refresh tokens using a valid refresh token */ async refreshTokens(userId: string, refreshToken: string): Promise { // Verify the refresh token try { const payload = await this.jwtService.verifyAsync(refreshToken, { secret: this.configService.get('JWT_REFRESH_SECRET'), }); // Check if the token is a refresh token and belongs to the user if (!payload.isRefreshToken || payload.sub !== userId) { throw new UnauthorizedException('Invalid refresh token'); } // Generate new tokens return this.generateTokens(userId); } catch (error) { throw new UnauthorizedException('Invalid refresh token'); } } /** * Validate a user by JWT payload */ async validateJwtUser(payload: JwtPayload) { const user = await this.usersService.findById(payload.sub); if (!user) { throw new UnauthorizedException('User not found'); } return user; } }