Rate Limit

Better Auth는 트래픽 관리와 악용 방지를 돕는 내장 rate limiter를 포함하고 있습니다. 기본적으로 프로덕션 모드에서 rate limiter는 다음과 같이 설정됩니다:

  • Window: 60초
  • Max Requests: 100개의 요청

auth.api를 사용하여 만든 서버 측 요청은 rate limiting의 영향을 받지 않습니다. Rate limit는 클라이언트가 시작한 요청에만 적용됩니다.

betterAuth 함수에 rateLimit 객체를 전달하여 이러한 설정을 쉽게 커스터마이징할 수 있습니다.

auth.ts
import { betterAuth } from "better-auth";

export const auth = betterAuth({
    rateLimit: {
        window: 10, // 초 단위 시간 윈도우
        max: 100, // 윈도우 내 최대 요청 수
    },
})

Rate limiting은 기본적으로 개발 모드에서 비활성화됩니다. 활성화하려면 enabledtrue로 설정하세요:

auth.ts
export const auth = betterAuth({
    rateLimit: {
        enabled: true,
        //...기타 옵션
    },
})

기본 설정 외에도 Better Auth는 특정 경로에 대한 커스텀 규칙을 제공합니다. 예를 들어:

  • /sign-in/email: 10초 내에 3개의 요청으로 제한됩니다.

또한 플러그인도 특정 경로에 대한 커스텀 규칙을 정의합니다. 예를 들어 twoFactor 플러그인은 다음과 같은 커스텀 규칙을 가지고 있습니다:

  • /two-factor/verify: 10초 내에 3개의 요청으로 제한됩니다.

이러한 커스텀 규칙은 민감한 작업이 더 엄격한 제한으로 보호되도록 보장합니다.

Rate Limit 설정하기

연결 IP 주소

Rate limiting은 연결 IP 주소를 사용하여 사용자가 만든 요청 수를 추적합니다. 기본적으로 확인되는 헤더는 프로덕션 환경에서 일반적으로 사용되는 x-forwarded-for입니다. 사용자의 IP 주소를 추적하기 위해 다른 헤더를 사용하는 경우 이를 지정해야 합니다.

auth.ts
export const auth = betterAuth({
    //...기타 옵션
    advanced: {
        ipAddress: {
          ipAddressHeaders: ["cf-connecting-ip"], // Cloudflare 특정 헤더 예제
      },
    },
    rateLimit: {
        enabled: true,
        window: 60, // 초 단위 시간 윈도우
        max: 100, // 윈도우 내 최대 요청 수
    },
})

Rate Limit Window

auth.ts
import { betterAuth } from "better-auth";

export const auth = betterAuth({
    //...기타 옵션
    rateLimit: {
        window: 60, // 초 단위 시간 윈도우
        max: 100, // 윈도우 내 최대 요청 수
    },
})

특정 경로에 대한 커스텀 규칙도 전달할 수 있습니다.

auth.ts
import { betterAuth } from "better-auth";

export const auth = betterAuth({
    //...기타 옵션
    rateLimit: {
        window: 60, // 초 단위 시간 윈도우
        max: 100, // 윈도우 내 최대 요청 수
        customRules: {
            "/sign-in/email": {
                window: 10,
                max: 3,
            },
            "/two-factor/*": async (request)=> {
                // rate limit window와 max를 반환하는 커스텀 함수
                return {
                    window: 10,
                    max: 3,
                }
            }
        },
    },
})

특정 경로에 대해 rate limiting을 비활성화하려면 false로 설정하거나 커스텀 규칙 함수에서 false를 반환할 수 있습니다.

auth.ts
import { betterAuth } from "better-auth";

export const auth = betterAuth({
    //...기타 옵션
    rateLimit: {
        customRules: {
            "/get-session": false,
        },
    },
})

스토리지

기본적으로 rate limit 데이터는 메모리에 저장되며, 이는 많은 사용 사례, 특히 서버리스 환경에는 적합하지 않을 수 있습니다. 이를 해결하기 위해 데이터베이스, 보조 스토리지 또는 커스텀 스토리지를 사용하여 rate limit 데이터를 저장할 수 있습니다.

데이터베이스 사용

auth.ts
import { betterAuth } from "better-auth";

export const auth = betterAuth({
    //...기타 옵션
    rateLimit: {
        storage: "database",
        modelName: "rateLimit", //선택 사항, 기본적으로 "rateLimit"이 사용됩니다
    },
})

데이터베이스에 rate limit 테이블을 생성하려면 migrate를 실행하세요.

npx @better-auth/cli migrate

보조 스토리지 사용

보조 스토리지가 설정되어 있다면 이를 사용하여 rate limit 데이터를 저장할 수 있습니다.

auth.ts
import { betterAuth } from "better-auth";

export const auth = betterAuth({
    //...기타 옵션
    rateLimit: {
		storage: "secondary-storage"
    },
})

커스텀 스토리지

위의 솔루션 중 어느 것도 사용 사례에 맞지 않는 경우 customStorage를 구현할 수 있습니다.

auth.ts
import { betterAuth } from "better-auth";

export const auth = betterAuth({
    //...기타 옵션
    rateLimit: {
        customStorage: {
            get: async (key) => {
                // rate limit 데이터 가져오기
            },
            set: async (key, value) => {
                // rate limit 데이터 설정
            },
        },
    },
})

Rate Limit 오류 처리하기

요청이 rate limit를 초과하면 Better Auth는 다음 헤더를 반환합니다:

  • X-Retry-After: 사용자가 다른 요청을 할 수 있을 때까지의 시간(초).

클라이언트 측에서 rate limit 오류를 처리하려면 전역적으로 또는 요청별로 관리할 수 있습니다. Better Auth 클라이언트는 Better Fetch를 감싸고 있으므로 rate limit 오류를 처리하기 위해 fetchOptions를 전달할 수 있습니다

전역 처리

auth-client.ts
import { createAuthClient } from "better-auth/client";

export const authClient = createAuthClient({
    fetchOptions: {
        onError: async (context) => {
            const { response } = context;
            if (response.status === 429) {
                const retryAfter = response.headers.get("X-Retry-After");
                console.log(`Rate limit 초과. ${retryAfter}초 후에 재시도하세요`);
            }
        },
    }
})

요청별 처리

auth-client.ts
import { authClient } from "./auth-client";

await authClient.signIn.email({
    fetchOptions: {
        onError: async (context) => {
            const { response } = context;
            if (response.status === 429) {
                const retryAfter = response.headers.get("X-Retry-After");
                console.log(`Rate limit 초과. ${retryAfter}초 후에 재시도하세요`);
            }
        },
    }
})

스키마

rate limit 데이터를 저장하기 위해 데이터베이스를 사용하는 경우 다음 스키마가 필요합니다:

테이블 이름: rateLimit

Field NameTypeKeyDescription
idstring데이터베이스 ID
keystring-각 rate limit 키의 고유 식별자
countinteger-초 단위 시간 윈도우
lastRequestbigint-윈도우 내 최대 요청 수

On this page