Appearance
Rate Limiting Magic Links
FreshSource: shipfa.st/docs/security/rate-limiting-magic-links
NextAuth does not have built-in rate limiting for magic links. Use Upstash Redis.
Procedure
Step 1: Upstash Setup
- Sign up on Upstash
- Create a new Redis database
- Add
UPSTASH_REDIS_REST_URLandUPSTASH_REDIS_REST_TOKENto.env.local
Step 2: Install Packages
bash
npm install @upstash/redis @upstash/ratelimitStep 3: Create Middleware
Create /middleware.js in the root directory:
javascript
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"],
};Step 4: Create Blocked Page
Create /app/blocked/page.js:
javascript
"use client";
import config from "@/config";
import { signIn } from "next-auth/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;