Rate limiting doesn't work for /send-verification-email #972

Closed
opened 2026-03-13 08:12:54 -05:00 by GiteaMirror · 3 comments
Owner

Originally created by @devcraftsio on GitHub (Apr 4, 2025).

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

  1. Create a table using the following model
model RateLimit {
  id          String @id @default(uuid()) @db.Uuid
  key         String
  count       Int
  lastRequest BigInt @map("last_request")

  @@map("rate_limits")
  @@schema("public")
}
  1. Set following rate limiting config:
emailVerification: {
  sendOnSignUp: true,
  sendVerificationEmail: async ({ user, url, token }, request) => {
    await resend.emails.send({
      from: `${process.env.NEXT_PUBLIC_SITE_NAME}`,
      to: [user.email],
      subject: 'Verify your email address',
      react: VerifyEmailTemplate({ url }),
    });
  },
},
rateLimit: {    
    enabled: true,
    storage: 'database',
    modelName: 'rateLimit',
    window: 5 * 60,
    max: 1
}
  1. Call auth.api.sendVerificationEmail from server component a couple of times

Current vs. Expected behavior

Current behavior

Error isn't thrown and email is sent. Additionally, no new rows are added to the rateLimit table for the verification requests, but others such as /get-session and /sign-up/email are recorded, so doesn't seem to be an issue with database config

Expected behavior

  • Rows should be added to the rateLimit table
  • Emails shouldn't be sent after hitting the limit

What version of Better Auth are you using?

1.2.5

Provide environment information

Next.js v14.2.26

Which area(s) are affected? (Select all that apply)

Backend, Client

Auth config (if applicable)

import { betterAuth } from 'better-auth';
import { prisma } from './prisma';
import { prismaAdapter } from 'better-auth/adapters/prisma';
import { nextCookies } from 'better-auth/next-js';
import { Resend } from 'resend';
import VerifyEmailTemplate from '@/app/components/email-templates/verify';

export const auth = betterAuth({
  database: prismaAdapter(prisma, { provider: 'postgresql' }),
  plugins: [nextCookies()],
  emailAndPassword: { enabled: true },

  emailVerification: {
    sendOnSignUp: true,
    sendVerificationEmail: async ({ user, url, token }, request) => {
      await resend.emails.send({
        from: `${process.env.NEXT_PUBLIC_SITE_NAME}`,
        to: [user.email],
        subject: 'Verify your email address',
        react: VerifyEmailTemplate({ url }),
      });
    },
  },
  advanced: {
    generateId: false,
  },
  rateLimit: {
    enabled: true,
    storage: 'database',
    modelName: 'rateLimit',
    window: 5 * 60,
    max: 1,
  },
});

Additional context

Image
Additionally I tried editing the rows manually, but rate limiting for that endpoint still doesn't work

Originally created by @devcraftsio on GitHub (Apr 4, 2025). ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce 1. Create a table using the following model ``` model RateLimit { id String @id @default(uuid()) @db.Uuid key String count Int lastRequest BigInt @map("last_request") @@map("rate_limits") @@schema("public") } ``` 2. Set following rate limiting config: ``` emailVerification: { sendOnSignUp: true, sendVerificationEmail: async ({ user, url, token }, request) => { await resend.emails.send({ from: `${process.env.NEXT_PUBLIC_SITE_NAME}`, to: [user.email], subject: 'Verify your email address', react: VerifyEmailTemplate({ url }), }); }, }, rateLimit: { enabled: true, storage: 'database', modelName: 'rateLimit', window: 5 * 60, max: 1 } ``` 3. Call `auth.api.sendVerificationEmail` from server component a couple of times ### Current vs. Expected behavior **Current behavior** Error isn't thrown and email is sent. Additionally, no new rows are added to the `rateLimit` table for the verification requests, but others such as /get-session and /sign-up/email are recorded, so doesn't seem to be an issue with database config **Expected behavior** - Rows should be added to the `rateLimit` table - Emails shouldn't be sent after hitting the limit ### What version of Better Auth are you using? 1.2.5 ### Provide environment information ```bash Next.js v14.2.26 ``` ### Which area(s) are affected? (Select all that apply) Backend, Client ### Auth config (if applicable) ```typescript import { betterAuth } from 'better-auth'; import { prisma } from './prisma'; import { prismaAdapter } from 'better-auth/adapters/prisma'; import { nextCookies } from 'better-auth/next-js'; import { Resend } from 'resend'; import VerifyEmailTemplate from '@/app/components/email-templates/verify'; export const auth = betterAuth({ database: prismaAdapter(prisma, { provider: 'postgresql' }), plugins: [nextCookies()], emailAndPassword: { enabled: true }, emailVerification: { sendOnSignUp: true, sendVerificationEmail: async ({ user, url, token }, request) => { await resend.emails.send({ from: `${process.env.NEXT_PUBLIC_SITE_NAME}`, to: [user.email], subject: 'Verify your email address', react: VerifyEmailTemplate({ url }), }); }, }, advanced: { generateId: false, }, rateLimit: { enabled: true, storage: 'database', modelName: 'rateLimit', window: 5 * 60, max: 1, }, }); ``` ### Additional context ![Image](https://github.com/user-attachments/assets/42517ccc-3d66-47a3-96be-56ae36470dd8) Additionally I tried editing the rows manually, but rate limiting for that endpoint still doesn't work
GiteaMirror added the bug label 2026-03-13 08:12:54 -05:00
Author
Owner

@Bekacru commented on GitHub (Apr 4, 2025):

Are you by any chance calling the endpoint from the server using auth.api? Better Auth only rate limits client initiated requests.

@Bekacru commented on GitHub (Apr 4, 2025): Are you by any chance calling the endpoint from the server using `auth.api`? Better Auth only rate limits client initiated requests.
Author
Owner

@devcraftsio commented on GitHub (Apr 4, 2025):

That makes sense, just tried it from the client using authClient.sendVerificationEmail instead of auth.api.sendVerificationEmail and the rate limiting worked. Please add this information to the docs

@devcraftsio commented on GitHub (Apr 4, 2025): That makes sense, just tried it from the client using `authClient.sendVerificationEmail` instead of `auth.api.sendVerificationEmail` and the rate limiting worked. Please add this information to the docs
Author
Owner

@budivoogt commented on GitHub (Jul 4, 2025):

Are you by any chance calling the endpoint from the server using auth.api? Better Auth only rate limits client initiated requests.

I ran into the same issue. It wasn't clear to me either that you only rate limit client-initiated requests. Why are you doing that, though? Because with this implementation, you are discouraging people from doing a server-side implementation, and it makes sense that rate limits apply to those.

@budivoogt commented on GitHub (Jul 4, 2025): > Are you by any chance calling the endpoint from the server using `auth.api`? Better Auth only rate limits client initiated requests. I ran into the same issue. It wasn't clear to me either that you only rate limit client-initiated requests. Why are you doing that, though? Because with this implementation, you are discouraging people from doing a server-side implementation, and it makes sense that rate limits apply to those.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#972