add refresh token

This commit is contained in:
Phuoc Nguyen
2025-10-21 16:30:18 +07:00
parent d316362f41
commit 71f0447af7
17 changed files with 2074 additions and 18 deletions

View File

@@ -3,21 +3,25 @@ import {
UnauthorizedException,
BadRequestException,
ConflictException,
Logger,
} from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import * as bcrypt from 'bcrypt';
import { UsersService } from '../users/users.service';
import { LoginDto, RegisterDto, AuthResponseDto } from './dto';
import { LoginDto, RegisterDto, AuthResponseDto, RefreshTokenDto } from './dto';
import { JwtPayload } from './interfaces/jwt-payload.interface';
import { UserRole } from '../users/entities/user.entity';
import { RefreshTokenService } from './services/refresh-token.service';
@Injectable()
export class AuthService {
private readonly logger = new Logger(AuthService.name);
private readonly BCRYPT_ROUNDS = 10;
constructor(
private readonly usersService: UsersService,
private readonly jwtService: JwtService,
private readonly refreshTokenService: RefreshTokenService,
) {}
/**
@@ -71,7 +75,7 @@ export class AuthService {
}
/**
* Login user and generate JWT
* Login user and generate JWT + Refresh Token
*/
async login(user: any): Promise<AuthResponseDto> {
const payload: JwtPayload = {
@@ -80,8 +84,19 @@ export class AuthService {
roles: user.roles || [],
};
// Generate access token
const accessToken = this.jwtService.sign(payload);
// Generate refresh token
const refreshToken = await this.refreshTokenService.generateRefreshToken(
user.id,
);
this.logger.log(`User logged in: ${user.email}`);
return {
access_token: this.jwtService.sign(payload),
access_token: accessToken,
refresh_token: refreshToken,
user: {
id: user.id,
email: user.email,
@@ -106,20 +121,52 @@ export class AuthService {
}
/**
* Refresh access token
* Refresh access token using refresh token
* Implements token rotation for enhanced security
*/
async refreshToken(userId: string): Promise<AuthResponseDto> {
async refreshAccessToken(
refreshTokenDto: RefreshTokenDto,
): Promise<AuthResponseDto> {
// Validate refresh token
const userId = await this.refreshTokenService.validateRefreshToken(
refreshTokenDto.refreshToken,
);
// Get user details
const user = await this.usersService.findOne(userId);
if (!user) {
throw new UnauthorizedException('User not found');
}
if (!user.isActive) {
throw new UnauthorizedException('User account is inactive');
// Revoke old refresh token (token rotation)
await this.refreshTokenService.revokeRefreshToken(
refreshTokenDto.refreshToken,
);
// Generate new tokens
this.logger.log(`Token refreshed for user: ${user.email}`);
return this.login(user);
}
/**
* Logout user and revoke refresh token
*/
async logout(refreshToken: string): Promise<void> {
if (!refreshToken) {
throw new BadRequestException('Refresh token is required');
}
return this.login(user);
await this.refreshTokenService.revokeRefreshToken(refreshToken);
this.logger.log('User logged out and refresh token revoked');
}
/**
* Revoke all refresh tokens for a user
*/
async revokeAllUserTokens(userId: string): Promise<void> {
await this.refreshTokenService.revokeAllUserTokens(userId);
this.logger.log(`All tokens revoked for user: ${userId}`);
}
/**