import { Inject, Injectable, Logger, UnauthorizedException } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import * as bcrypt from 'bcrypt'; import { isEmpty } from 'lodash'; import { AccountsEntity } from '../database/entities'; import { ACCESS_TOKEN_JWT_SERVICE } from './strategies/jwt/jwt-access-token.module'; import { REFRESH_TOKEN_JWT_SERVICE } from './strategies/jwt/jwt-refresh-token.module'; import { UsersAuthService } from './users/users-auth.service'; @Injectable() export class AuthService { private readonly logger = new Logger(AuthService.name); constructor( private readonly usersAuthService: UsersAuthService, @Inject(ACCESS_TOKEN_JWT_SERVICE) private readonly accessTokenJwtService: JwtService, @Inject(REFRESH_TOKEN_JWT_SERVICE) private readonly refreshTokenJwtService: JwtService ) {} public async signJwts(user: AccountsEntity) { const payload = { username: user.username, sub: user.id }; const accessToken = await this.accessTokenJwtService.signAsync(payload); const refreshToken = await this.refreshTokenJwtService.signAsync(payload); await this.usersAuthService.setCurrentRefreshTokenHash(user.id, refreshToken); return { accessToken, refreshToken }; } public async getAuthenticatedUser(username: string, password: string): Promise { try { const account = await this.usersAuthService.getUserByUsername(username); if (!account) throw new UnauthorizedException(`Username not found`); await this.verifyPassword(password, account.password); return account; } catch (error) { throw new UnauthorizedException(`Wrong credentials`); } } private async verifyPassword(plainTextPassword: string, hashedPassword: string | null) { const isPasswordMatching = hashedPassword && !isEmpty(hashedPassword) ? await bcrypt.compare(plainTextPassword, hashedPassword) : null; if (!isPasswordMatching) { throw new UnauthorizedException(`Wrong password`); } } }