add refresh token
This commit is contained in:
@@ -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}`);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user