From d32b47407b24dec5dfe46d0220ea17d92d75aab6 Mon Sep 17 00:00:00 2001 From: colinislit Date: Wed, 19 Nov 2025 12:22:52 +0100 Subject: [PATCH] callback routes --- app/auth/callback/route.ts | 23 +++++++------- app/update-password/route.ts | 56 +++++++++++++++++++++++++++++++++ docs/emails/reset-password.html | 1 - lib/auth/client.ts | 3 +- 4 files changed, 70 insertions(+), 13 deletions(-) create mode 100644 app/update-password/route.ts diff --git a/app/auth/callback/route.ts b/app/auth/callback/route.ts index 6e91f3f..c4a5471 100644 --- a/app/auth/callback/route.ts +++ b/app/auth/callback/route.ts @@ -33,18 +33,19 @@ export async function GET(request: NextRequest) { const { data, error } = await supabase.auth.exchangeCodeForSession(code) if (!error && data.user) { - // Password recovery flow detection: - // 1. Check type parameter (Supabase adds this automatically) - // 2. Check if next contains update-password (our explicit redirect) - // 3. Check if this is a recovery session by looking at the user's recovery metadata - const isRecoveryFlow = - type === 'recovery' || - next.includes('/update-password') || - requestUrl.pathname.includes('update-password') - - if (isRecoveryFlow) { + // PRIORITY: If next is /update-password, ALWAYS go there (password reset flow) + if (next === '/update-password' || next.includes('update-password')) { if (process.env.NODE_ENV === 'development') { - console.log('✅ Redirecting to /update-password (recovery flow detected)') + console.log('✅ Redirecting to /update-password (next parameter detected)') + } + return NextResponse.redirect(new URL('/update-password', request.url)) + } + + // Password recovery flow detection: + // Check type parameter (Supabase adds this automatically for recovery) + if (type === 'recovery') { + if (process.env.NODE_ENV === 'development') { + console.log('✅ Redirecting to /update-password (recovery type detected)') } return NextResponse.redirect(new URL('/update-password', request.url)) } diff --git a/app/update-password/route.ts b/app/update-password/route.ts new file mode 100644 index 0000000..28772fd --- /dev/null +++ b/app/update-password/route.ts @@ -0,0 +1,56 @@ +/** + * Update Password Route Handler + * + * Handles password reset callback from Supabase + * Exchanges the code for a session and shows the update password page + */ + +import { createClient } from '@/lib/auth/server' +import { NextResponse } from 'next/server' +import type { NextRequest } from 'next/server' + +export async function GET(request: NextRequest) { + const requestUrl = new URL(request.url) + const code = requestUrl.searchParams.get('code') + const type = requestUrl.searchParams.get('type') + + // Debug logging + if (process.env.NODE_ENV === 'development') { + console.log('🔍 Update Password Route Handler:', { + url: request.url, + code: !!code, + type, + allParams: Object.fromEntries(requestUrl.searchParams) + }) + } + + // If there's a code, exchange it for a session + if (code) { + const supabase = await createClient() + + // Exchange code for session + const { data, error } = await supabase.auth.exchangeCodeForSession(code) + + if (error) { + console.error('❌ Code exchange error:', error) + return NextResponse.redirect( + new URL('/login?error=password_reset_failed', request.url) + ) + } + + if (data.user) { + // Successfully exchanged code - redirect to update password page (without code) + // The page will check for an active session + const redirectUrl = new URL('/update-password', request.url) + // Remove code and type from URL to clean it up + redirectUrl.searchParams.delete('code') + redirectUrl.searchParams.delete('type') + return NextResponse.redirect(redirectUrl) + } + } + + // No code or exchange failed - just show the update password page + // It will check if user has an active session + return NextResponse.next() +} + diff --git a/docs/emails/reset-password.html b/docs/emails/reset-password.html index 8e1eeaf..d8c736e 100644 --- a/docs/emails/reset-password.html +++ b/docs/emails/reset-password.html @@ -102,4 +102,3 @@ - diff --git a/lib/auth/client.ts b/lib/auth/client.ts index 019d128..999bd19 100644 --- a/lib/auth/client.ts +++ b/lib/auth/client.ts @@ -128,8 +128,9 @@ export async function signUpWithPassword(email: string, password: string) { */ export async function resetPasswordForEmail(email: string) { const supabase = createClient() + // Redirect directly to /update-password - route handler will do code exchange const { error } = await supabase.auth.resetPasswordForEmail(email, { - redirectTo: `${window.location.origin}/auth/callback?next=/update-password` + redirectTo: `${window.location.origin}/update-password` }) if (error) throw error