@@ -4,6 +4,7 @@ import { NextRequest, NextResponse } from 'next/server'
44import { loginRateLimit } from '@/lib/utils/rate-limiter'
55
66export const maxDuration = 45
7+ const MAGIC_LINK_COOLDOWN_SECONDS = 60
78
89function isValidEmail ( email : string ) {
910 const atIndex = email . lastIndexOf ( '@' )
@@ -39,20 +40,31 @@ function normalizeSupabaseAuthError(error: { message?: string; status?: number }
3940 ) {
4041 return {
4142 status : 429 ,
42- message : 'A magic link was requested recently. Please wait 60 seconds before requesting another one.' ,
43+ message : `A magic link was requested recently. Please wait ${ MAGIC_LINK_COOLDOWN_SECONDS } seconds before requesting another one.` ,
44+ retryAfter : MAGIC_LINK_COOLDOWN_SECONDS ,
4345 }
4446 }
4547
4648 if ( lowerMessage . includes ( 'invalid' ) && lowerMessage . includes ( 'email' ) ) {
4749 return {
4850 status : 400 ,
4951 message : 'Please enter a valid email address.' ,
52+ retryAfter : 0 ,
53+ }
54+ }
55+
56+ if ( lowerMessage . includes ( 'redirect' ) ) {
57+ return {
58+ status : 500 ,
59+ message : 'Magic link redirect is not configured correctly. Please contact support.' ,
60+ retryAfter : 0 ,
5061 }
5162 }
5263
5364 return {
54- status : 502 ,
55- message : 'Unable to send magic link right now. Please try again in a moment.' ,
65+ status : 503 ,
66+ message : 'Email delivery is temporarily unavailable. Please try again in a moment.' ,
67+ retryAfter : MAGIC_LINK_COOLDOWN_SECONDS ,
5668 }
5769}
5870
@@ -66,6 +78,10 @@ export async function POST(request: NextRequest) {
6678 return NextResponse . json (
6779 {
6880 error : 'Too many magic link requests. Please try again later.' ,
81+ retryAfter : Math . max (
82+ MAGIC_LINK_COOLDOWN_SECONDS ,
83+ Math . ceil ( ( ( rateLimitResult . lockedUntil || rateLimitResult . resetTime ) - Date . now ( ) ) / 1000 )
84+ ) ,
6985 lockedUntil : rateLimitResult . lockedUntil ,
7086 resetTime : rateLimitResult . resetTime ,
7187 } ,
@@ -118,8 +134,16 @@ export async function POST(request: NextRequest) {
118134 durationMs : Date . now ( ) - startedAt ,
119135 } )
120136 return NextResponse . json (
121- { error : normalizedError . message } ,
122- { status : normalizedError . status }
137+ {
138+ error : normalizedError . message ,
139+ retryAfter : normalizedError . retryAfter ,
140+ } ,
141+ {
142+ status : normalizedError . status ,
143+ headers : normalizedError . retryAfter
144+ ? { 'Retry-After' : String ( normalizedError . retryAfter ) }
145+ : undefined ,
146+ }
123147 )
124148 }
125149
0 commit comments