refactor: ( auth ) throttle only the public sign-in endpoints

This commit is contained in:
Abubeker Yasin
2026-08-27 14:45:16 +03:00
parent 979053ea4f
commit 2315ce06de
2 changed files with 16 additions and 10 deletions

View File

@@ -0,0 +1,4 @@
import { applyDecorators, UseGuards } from '@nestjs/common';
import { Throttle, ThrottlerGuard } from '@nestjs/throttler';
export const ThrottleSignIn = (limit = 20) =>
applyDecorators(UseGuards(ThrottlerGuard), Throttle({ auth: { limit, ttl: 60_000 } }));

View File

@@ -21,7 +21,7 @@ import {
ApiBearerAuth,
} from "@nestjs/swagger";
import { IsPublic } from "@tria-plc/api-common/modules/auth/decorators/public.decorator";
import { Throttle, ThrottlerGuard } from "@nestjs/throttler";
import { ThrottleSignIn } from "../../common/throttle-sign-in.decorator";
import { PassengerAuthService } from "./passenger-auth.service";
import {
RegisterDto,
@@ -37,16 +37,12 @@ import { JwtGuard } from "../../common/jwt.guard";
@ApiTags("Passenger Auth")
@Controller("auth")
// Scoped to this controller rather than registered as a global APP_GUARD: the staged sign-in
// exposes an account-existence lookup, and rate limiting is the mitigation for it. Applying the
// guard app-wide would change the behaviour of every other module at the same time.
@UseGuards(ThrottlerGuard)
@Throttle({ auth: { limit: 20, ttl: 60_000 } })
export class AuthController {
constructor(private passengerAuthService: PassengerAuthService) {}
@Post("register")
@IsPublic()
@ThrottleSignIn()
@ApiOperation({
summary: "Register new passenger account (sends SMS verification code)",
})
@@ -66,6 +62,7 @@ export class AuthController {
@Post("register/resend-code")
@IsPublic()
@ThrottleSignIn()
@HttpCode(HttpStatus.OK)
@ApiOperation({
summary: "Resend the registration verification code for a pending account",
@@ -84,6 +81,7 @@ export class AuthController {
@Post("login")
@IsPublic()
@ThrottleSignIn()
@HttpCode(HttpStatus.OK)
@ApiOperation({ summary: "Login with email and password" })
@ApiResponse({
@@ -199,11 +197,11 @@ export class AuthController {
@Post("identifier/lookup")
@IsPublic()
// Tighter than the other sign-in endpoints: this is the one that answers "does this account
// exist", so it is the one worth making expensive to sweep. Still roomy enough that a
// passenger correcting a typo two or three times is unaffected.
@ThrottleSignIn(10)
@HttpCode(HttpStatus.OK)
// Tighter than the rest of the controller: this is the endpoint that answers "does this
// account exist", so it is the one worth making expensive to sweep. Still roomy enough
// that a passenger correcting a typo two or three times is unaffected.
@Throttle({ auth: { limit: 10, ttl: 60_000 } })
@ApiOperation({
summary: "Step 1 of sign-in — decide what to ask the user for next",
description:
@@ -222,6 +220,7 @@ export class AuthController {
@Post("password-setup/request")
@IsPublic()
@ThrottleSignIn()
@HttpCode(HttpStatus.OK)
@ApiOperation({
summary: "Send the SMS code that lets an account with no password set one",
@@ -237,6 +236,7 @@ export class AuthController {
@Post("password-setup/complete")
@IsPublic()
@ThrottleSignIn()
@HttpCode(HttpStatus.OK)
@ApiOperation({
summary: "Redeem the code, set the password, and sign in",
@@ -256,6 +256,7 @@ export class AuthController {
@Post("fayda/request-password-setup")
@IsPublic()
@ThrottleSignIn()
@HttpCode(HttpStatus.OK)
@ApiOperation({
summary: "Send OTP to phone for Fayda-verified account password setup",
@@ -277,6 +278,7 @@ export class AuthController {
@Post("fayda/verify-and-login")
@IsPublic()
@ThrottleSignIn()
@HttpCode(HttpStatus.OK)
@ApiOperation({
summary: "Verify OTP and receive session token for Fayda-verified account",