refresh token

This commit is contained in:
2025-11-11 09:50:18 +03:30
parent 4c274c3118
commit e34b93aa83
8 changed files with 51 additions and 7 deletions
@@ -0,0 +1,18 @@
import { UseGuards, applyDecorators } from '@nestjs/common';
import { Throttle, ThrottlerGuard } from '@nestjs/throttler';
import {
AUTH_THROTTLE_LIMIT,
AUTH_THROTTLE_TTL,
AUTH__REFRESH_THROTTLE_LIMIT,
AUTH__REFRESH_THROTTLE_TTL,
} from '../constants';
export const RateLimit = (limit: number, ttl: number) =>
applyDecorators(Throttle({ default: { limit, ttl } }), UseGuards(ThrottlerGuard));
// Predefined rate limits for common scenarios
export const StrictRateLimit = () => RateLimit(AUTH_THROTTLE_LIMIT, AUTH_THROTTLE_TTL); // 5 requests per minute
export const StandardRateLimit = () => RateLimit(30, 60000); // 30 requests per minute
export const MailSendRateLimit = () => RateLimit(10, 60000); // 10 emails per minute
export const RefreshTokenRateLimit = () => RateLimit(AUTH__REFRESH_THROTTLE_LIMIT, AUTH__REFRESH_THROTTLE_TTL); // 10 emails per minute
+1 -1
View File
@@ -1,5 +1,5 @@
import { Entity, Property } from '@mikro-orm/core';
import { BaseEntity } from 'src/common/entities/base.entity';
import { BaseEntity } from '../../../common/entities/base.entity';
@Entity({ tableName: 'admins' })
export class Admin extends BaseEntity {
+9
View File
@@ -4,6 +4,8 @@ import { RequestOtpDto } from './dto/request-otp.dto';
import { ApiTags, ApiOperation, ApiBody, ApiResponse } from '@nestjs/swagger';
import { VerifyOtpDto } from './dto/verify-otp.dto copy';
import { Throttle } from '@nestjs/throttler';
import { RefreshTokenRateLimit } from 'src/common/decorators/rate-limit.decorator';
import { RefreshTokenDto } from './dto/refresh-token.dto';
@ApiTags('auth')
@Controller('auth')
@@ -46,4 +48,11 @@ export class AuthController {
adminOtpVerify(@Body() dto: VerifyOtpDto) {
return this.authService.verifyOtpAdmin(dto.phone, dto.otp); // assuming dto has `otp` property
}
@RefreshTokenRateLimit()
@ApiOperation({ summary: 'refresh the user access token / refresh token' })
@Post('refresh')
refreshToken(@Body() refreshTokenDto: RefreshTokenDto) {
return this.authService.refreshToken(refreshTokenDto.refreshToken);
}
}
+2 -1
View File
@@ -6,6 +6,7 @@ import { UserModule } from '../users/user.module';
import { JwtModule } from '@nestjs/jwt';
import { ConfigService } from '@nestjs/config';
import { AdminModule } from '../admin/admin.module';
import { TokensService } from './services/tokens.service';
@Module({
imports: [
@@ -24,6 +25,6 @@ import { AdminModule } from '../admin/admin.module';
AdminModule,
],
controllers: [AuthController],
providers: [AuthService],
providers: [AuthService, TokensService],
})
export class AuthModule {}
+9
View File
@@ -0,0 +1,9 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsNotEmpty, IsString } from 'class-validator';
export class RefreshTokenDto {
@ApiProperty({ description: 'Refresh token' })
@IsString({ message: 'Refresh token must be a string' })
@IsNotEmpty({ message: 'Refresh token is required' })
refreshToken: string;
}
+9 -2
View File
@@ -7,6 +7,7 @@ import { randomInt } from 'crypto';
import { JwtService } from '@nestjs/jwt';
import { AdminService } from '../../admin/admin.service';
import { AuthEntityType } from 'src/modules/auth/guards/auth.guard';
import { TokensService } from './tokens.service';
@Injectable()
export class AuthService {
@@ -16,6 +17,7 @@ export class AuthService {
private readonly userService: UserService,
private readonly jwtService: JwtService,
private readonly adminService: AdminService,
private readonly tokensService: TokensService,
) {}
async requestOtp(dto: RequestOtpDto) {
@@ -55,9 +57,10 @@ export class AuthService {
const user = await this.userService.findOrCreateByPhone(phone);
const accessToken = await this.issueToken(user.id, AuthEntityType.USER);
// const accessToken = await this.issueToken(user.id, AuthEntityType.USER);
const tokens = await this.tokensService.generateTokens(user);
return { success: true, message: 'User registered successfully!', accessToken };
return { success: true, message: 'User registered successfully!', tokens };
}
async verifyOtpAdmin(phone: string, code: string) {
@@ -88,4 +91,8 @@ export class AuthService {
};
return this.jwtService.signAsync(payload);
}
refreshToken(oldRefreshToken: string) {
return this.tokensService.refreshToken(oldRefreshToken);
}
}
@@ -1,8 +1,8 @@
import { Entity, ManyToOne, Opt, Property } from '@mikro-orm/core';
import { User } from './user.entity';
import { BaseEntity } from 'src/common/entities/base.entity';
@Entity()
import { BaseEntity } from '../../../common/entities/base.entity';
@Entity({ tableName: 'refreshtokens' })
export class RefreshToken extends BaseEntity {
@Property({ type: 'varchar', length: 255 })
token!: string;
+1 -1
View File
@@ -1,6 +1,6 @@
import { Entity, Property, OneToMany, Collection } from '@mikro-orm/core';
import { RefreshToken } from './refresh-token.entity';
import { BaseEntity } from 'src/common/entities/base.entity';
import { BaseEntity } from '../../../common/entities/base.entity';
@Entity({ tableName: 'users' })
export class User extends BaseEntity {