chore: redirect after reset password (#37410)

This commit is contained in:
Ignacio Dobronich
2025-07-28 10:43:26 -03:00
committed by GitHub
parent 4bfdbe32ac
commit d2cf1dad46
6 changed files with 46 additions and 11 deletions

View File

@@ -60,10 +60,13 @@ const ConfirmResetCodeForm = ({ email }: { email: string }) => {
if (user?.factors?.length) {
await router.push({
pathname: '/forgot-password-mfa',
query: { returnTo: '/reset-password' },
query: router.query,
})
} else {
await router.push('reset-password')
await router.push({
pathname: '/reset-password',
query: router.query,
})
}
}
}

View File

@@ -7,7 +7,7 @@ import { useForm } from 'react-hook-form'
import { toast } from 'sonner'
import { z } from 'zod'
import { auth } from 'lib/gotrue'
import { auth, getReturnToPath } from 'lib/gotrue'
import {
Button,
Form_Shadcn_,
@@ -67,7 +67,7 @@ const ResetPasswordForm = () => {
// logout all other sessions after changing password
await auth.signOut({ scope: 'others' })
await router.push('/organizations')
await router.push(getReturnToPath('/organizations'))
} else {
toast.error(`Failed to save password: ${error.message}`, { id: toastId })
if (!WHITELIST_ERRORS.some((e) => error.message.includes(e))) {

View File

@@ -4,7 +4,7 @@ import type { AuthError } from '@supabase/supabase-js'
import { useQueryClient } from '@tanstack/react-query'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { useRef, useState } from 'react'
import { useRef, useState, useEffect } from 'react'
import { toast } from 'sonner'
import { object, string } from 'yup'
@@ -28,10 +28,22 @@ const SignInForm = () => {
const [captchaToken, setCaptchaToken] = useState<string | null>(null)
const captchaRef = useRef<HCaptcha>(null)
const [returnTo, setReturnTo] = useState<string | null>(null)
useEffect(() => {
// Only call getReturnToPath after component mounts client-side
setReturnTo(getReturnToPath())
}, [])
const { mutate: sendEvent } = useSendEventMutation()
const { mutate: addLoginEvent } = useAddLoginEvent()
let forgotPasswordUrl = `/forgot-password`
if (returnTo && !returnTo.includes('/forgot-password')) {
forgotPasswordUrl = `${forgotPasswordUrl}?returnTo=${encodeURIComponent(returnTo)}`
}
const onSignIn = async ({ email, password }: { email: string; password: string }) => {
const toastId = toast.loading('Signing in...')
@@ -68,9 +80,12 @@ const SignInForm = () => {
addLoginEvent({})
await queryClient.resetQueries()
const returnTo = getReturnToPath()
// since we're already on the /sign-in page, prevent redirect loops
router.push(returnTo === '/sign-in' ? '/organizations' : returnTo)
let redirectPath = '/organizations'
if (returnTo && returnTo !== '/sign-in') {
redirectPath = returnTo
}
router.push(redirectPath)
} catch (error: any) {
toast.error(`Failed to sign in: ${(error as AuthError).message}`, { id: toastId })
Sentry.captureMessage('[CRITICAL] Failed to sign in via EP: ' + error.message)
@@ -124,7 +139,7 @@ const SignInForm = () => {
{/* positioned using absolute instead of labelOptional prop so tabbing between inputs works smoothly */}
<Link
href="/forgot-password"
href={forgotPasswordUrl}
className="absolute top-0 right-0 text-sm text-foreground-lighter"
>
Forgot Password?

View File

@@ -18,7 +18,11 @@ const signInSchema = object({
code: string().required('MFA Code is required'),
})
const SignInMfaForm = () => {
interface SignInMfaFormProps {
context?: 'forgot-password' | 'sign-in'
}
const SignInMfaForm = ({ context = 'sign-in' }: SignInMfaFormProps) => {
const router = useRouter()
const signOut = useSignOut()
const queryClient = useQueryClient()
@@ -38,7 +42,15 @@ const SignInMfaForm = () => {
} = useMfaChallengeAndVerifyMutation({
onSuccess: async () => {
await queryClient.resetQueries()
router.push(getReturnToPath())
if (context === 'forgot-password') {
router.push({
pathname: '/reset-password',
query: router.query,
})
} else {
router.push(getReturnToPath())
}
},
})

View File

@@ -73,6 +73,11 @@ export const buildPathWithParams = (pathname: string) => {
}
export const getReturnToPath = (fallback = DEFAULT_FALLBACK_PATH) => {
// If we're in a server environment, return the fallback
if (typeof location === 'undefined') {
return fallback
}
const searchParams = new URLSearchParams(location.search)
let returnTo = searchParams.get('returnTo') ?? fallback

View File

@@ -86,7 +86,7 @@ const ForgotPasswordMfa: NextPageWithLayout = () => {
heading="Complete two-factor authentication"
subheading="Enter the authentication code from your two-factor authentication app before changing your password"
>
<SignInMfaForm />
<SignInMfaForm context="forgot-password" />
</ForgotPasswordLayout>
)
}