refresh token
This commit is contained in:
@@ -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,5 +1,5 @@
|
|||||||
import { Entity, Property } from '@mikro-orm/core';
|
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' })
|
@Entity({ tableName: 'admins' })
|
||||||
export class Admin extends BaseEntity {
|
export class Admin extends BaseEntity {
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import { RequestOtpDto } from './dto/request-otp.dto';
|
|||||||
import { ApiTags, ApiOperation, ApiBody, ApiResponse } from '@nestjs/swagger';
|
import { ApiTags, ApiOperation, ApiBody, ApiResponse } from '@nestjs/swagger';
|
||||||
import { VerifyOtpDto } from './dto/verify-otp.dto copy';
|
import { VerifyOtpDto } from './dto/verify-otp.dto copy';
|
||||||
import { Throttle } from '@nestjs/throttler';
|
import { Throttle } from '@nestjs/throttler';
|
||||||
|
import { RefreshTokenRateLimit } from 'src/common/decorators/rate-limit.decorator';
|
||||||
|
import { RefreshTokenDto } from './dto/refresh-token.dto';
|
||||||
|
|
||||||
@ApiTags('auth')
|
@ApiTags('auth')
|
||||||
@Controller('auth')
|
@Controller('auth')
|
||||||
@@ -46,4 +48,11 @@ export class AuthController {
|
|||||||
adminOtpVerify(@Body() dto: VerifyOtpDto) {
|
adminOtpVerify(@Body() dto: VerifyOtpDto) {
|
||||||
return this.authService.verifyOtpAdmin(dto.phone, dto.otp); // assuming dto has `otp` property
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { UserModule } from '../users/user.module';
|
|||||||
import { JwtModule } from '@nestjs/jwt';
|
import { JwtModule } from '@nestjs/jwt';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { AdminModule } from '../admin/admin.module';
|
import { AdminModule } from '../admin/admin.module';
|
||||||
|
import { TokensService } from './services/tokens.service';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -24,6 +25,6 @@ import { AdminModule } from '../admin/admin.module';
|
|||||||
AdminModule,
|
AdminModule,
|
||||||
],
|
],
|
||||||
controllers: [AuthController],
|
controllers: [AuthController],
|
||||||
providers: [AuthService],
|
providers: [AuthService, TokensService],
|
||||||
})
|
})
|
||||||
export class AuthModule {}
|
export class AuthModule {}
|
||||||
|
|||||||
Executable
+9
@@ -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;
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import { randomInt } from 'crypto';
|
|||||||
import { JwtService } from '@nestjs/jwt';
|
import { JwtService } from '@nestjs/jwt';
|
||||||
import { AdminService } from '../../admin/admin.service';
|
import { AdminService } from '../../admin/admin.service';
|
||||||
import { AuthEntityType } from 'src/modules/auth/guards/auth.guard';
|
import { AuthEntityType } from 'src/modules/auth/guards/auth.guard';
|
||||||
|
import { TokensService } from './tokens.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthService {
|
export class AuthService {
|
||||||
@@ -16,6 +17,7 @@ export class AuthService {
|
|||||||
private readonly userService: UserService,
|
private readonly userService: UserService,
|
||||||
private readonly jwtService: JwtService,
|
private readonly jwtService: JwtService,
|
||||||
private readonly adminService: AdminService,
|
private readonly adminService: AdminService,
|
||||||
|
private readonly tokensService: TokensService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async requestOtp(dto: RequestOtpDto) {
|
async requestOtp(dto: RequestOtpDto) {
|
||||||
@@ -55,9 +57,10 @@ export class AuthService {
|
|||||||
|
|
||||||
const user = await this.userService.findOrCreateByPhone(phone);
|
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) {
|
async verifyOtpAdmin(phone: string, code: string) {
|
||||||
@@ -88,4 +91,8 @@ export class AuthService {
|
|||||||
};
|
};
|
||||||
return this.jwtService.signAsync(payload);
|
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 { Entity, ManyToOne, Opt, Property } from '@mikro-orm/core';
|
||||||
|
|
||||||
import { User } from './user.entity';
|
import { User } from './user.entity';
|
||||||
import { BaseEntity } from 'src/common/entities/base.entity';
|
import { BaseEntity } from '../../../common/entities/base.entity';
|
||||||
@Entity()
|
@Entity({ tableName: 'refreshtokens' })
|
||||||
export class RefreshToken extends BaseEntity {
|
export class RefreshToken extends BaseEntity {
|
||||||
@Property({ type: 'varchar', length: 255 })
|
@Property({ type: 'varchar', length: 255 })
|
||||||
token!: string;
|
token!: string;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Entity, Property, OneToMany, Collection } from '@mikro-orm/core';
|
import { Entity, Property, OneToMany, Collection } from '@mikro-orm/core';
|
||||||
import { RefreshToken } from './refresh-token.entity';
|
import { RefreshToken } from './refresh-token.entity';
|
||||||
import { BaseEntity } from 'src/common/entities/base.entity';
|
import { BaseEntity } from '../../../common/entities/base.entity';
|
||||||
|
|
||||||
@Entity({ tableName: 'users' })
|
@Entity({ tableName: 'users' })
|
||||||
export class User extends BaseEntity {
|
export class User extends BaseEntity {
|
||||||
|
|||||||
Reference in New Issue
Block a user