Rate limiting (Magic Links)
NextAuth does not have a built-in functionality to rate limit magic link emails.
Instead, you can use a service like Upstash to secure your /api/auth/signin/email
endpoint (responsible for signing up with magic links).
-
Sign up on Upstash
-
Create a new Redis database
-
Add the
UPSTASH_REDIS_REST_URL
andUPSTASH_REDIS_REST_TOKEN
to your.env.local
file -
Install the packages:
terminal
npm install @upstash/redis @upstash/ratelimit
- Create a new
middleware.js
file in the root directory (the same level as the/app
folder) and add the following content:
/middleware.js
import { NextResponse } from "next/server";
import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";
const redis = new Redis({
url: process.env.UPSTASH_REDIS_REST_URL,
token: process.env.UPSTASH_REDIS_REST_TOKEN,
});
const ratelimit = new Ratelimit({
redis: redis,
limiter: Ratelimit.slidingWindow(5, "60 s"),
});
export default async function middleware(request) {
const ip = request.ip ?? "127.0.0.1";
const { success } = await ratelimit.limit(ip);
return success
? NextResponse.next()
: NextResponse.redirect(new URL("/blocked", request.url));
}
export const config = {
matcher: ["/api/auth/signin/email"],
};
💡
We are rate limiting the user to 5 requests per minute based on their IP using the sliding window algorithm. You can refer to the Upstash ratelimit SDK documentation for more information on customizing it.
- Create a new
/app/blocked/page.js
file. This is the page the user will be redirected to when they hit the rate limit. Add the following content:
/app/blocked/page.js
"use client";
import config from "@/config";
import { signIn } from "next-auth/react";
import React from "react";
import Link from "next/link";
const Blocked = () => {
return (
<main className="relative bg-neutral text-neutral-content h-screen w-full flex flex-col justify-center gap-8 items-center p-10">
<h1 className="text-xl md:text-2xl font-medium">Hm, Access Blocked</h1>
<p>Try again in 1 minute</p>
<div>
<button
onClick={() =>
signIn(undefined, {
callbackUrl: config.auth.callbackUrl,
})
}
className="link"
>
Login
</button>{" "}
or{" "}
<Link className="link" href="/">
Home
</Link>
</div>
</main>
);
};
export default Blocked;
- That’s it! You have successfully rate limited the Magic Link sign-ins. Now, when a user hits the rate limit, they will be redirected to the
/blocked
page.
Last updated on