fix: handle auth email callbacks explicitly
This commit is contained in:
+6
-1
@@ -7,4 +7,9 @@ if (!supabaseUrl || !supabaseKey) {
|
|||||||
throw new Error('Missing Supabase environment variables')
|
throw new Error('Missing Supabase environment variables')
|
||||||
}
|
}
|
||||||
|
|
||||||
export const supabase = createClient(supabaseUrl, supabaseKey)
|
export const supabase = createClient(supabaseUrl, supabaseKey, {
|
||||||
|
auth: {
|
||||||
|
// Email confirmation and password recovery are handled by route components.
|
||||||
|
detectSessionInUrl: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|||||||
@@ -22,33 +22,48 @@ function startCountdown() {
|
|||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
try {
|
try {
|
||||||
|
const search = new URLSearchParams(window.location.search)
|
||||||
const hash = window.location.hash.slice(1)
|
const hash = window.location.hash.slice(1)
|
||||||
const params = new URLSearchParams(hash)
|
const params = new URLSearchParams(hash)
|
||||||
|
const code = search.get('code')
|
||||||
const accessToken = params.get('access_token')
|
const accessToken = params.get('access_token')
|
||||||
const refreshToken = params.get('refresh_token')
|
const refreshToken = params.get('refresh_token')
|
||||||
const type = params.get('type')
|
const type = params.get('type')
|
||||||
const error = params.get('error')
|
const error = search.get('error') ?? params.get('error')
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
state.value = 'failed'
|
state.value = 'failed'
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === 'signup' && accessToken && refreshToken) {
|
if (code || (type === 'signup' && accessToken && refreshToken)) {
|
||||||
const confirmClient = createClient(
|
const confirmClient = createClient(
|
||||||
import.meta.env.VITE_SUPABASE_URL,
|
import.meta.env.VITE_SUPABASE_URL,
|
||||||
import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY,
|
import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY,
|
||||||
|
{
|
||||||
|
auth: {
|
||||||
|
detectSessionInUrl: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (code) {
|
||||||
|
const { error: exchangeError } = await confirmClient.auth.exchangeCodeForSession(code)
|
||||||
|
if (exchangeError) {
|
||||||
|
state.value = 'failed'
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
const { error: setSessionError } = await confirmClient.auth.setSession({
|
const { error: setSessionError } = await confirmClient.auth.setSession({
|
||||||
access_token: accessToken,
|
access_token: accessToken!,
|
||||||
refresh_token: refreshToken,
|
refresh_token: refreshToken!,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (setSessionError) {
|
if (setSessionError) {
|
||||||
state.value = 'failed'
|
state.value = 'failed'
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await confirmClient.auth.signOut()
|
await confirmClient.auth.signOut()
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,20 @@ function showInvalidRecoveryLink() {
|
|||||||
state.value = 'invalid'
|
state.value = 'invalid'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getRecoveryParams() {
|
||||||
|
const search = new URLSearchParams(window.location.search)
|
||||||
|
const hash = new URLSearchParams(window.location.hash.slice(1))
|
||||||
|
|
||||||
|
return {
|
||||||
|
code: search.get('code'),
|
||||||
|
accessToken: hash.get('access_token'),
|
||||||
|
refreshToken: hash.get('refresh_token'),
|
||||||
|
type: hash.get('type'),
|
||||||
|
error: search.get('error') ?? hash.get('error'),
|
||||||
|
errorDescription: search.get('error_description') ?? hash.get('error_description'),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function getResetErrorMessage(value: unknown) {
|
function getResetErrorMessage(value: unknown) {
|
||||||
const message = value instanceof Error ? value.message : ''
|
const message = value instanceof Error ? value.message : ''
|
||||||
if (
|
if (
|
||||||
@@ -47,6 +61,47 @@ function startCountdown() {
|
|||||||
}, 1000)
|
}, 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function initializeRecoverySession() {
|
||||||
|
const {
|
||||||
|
code,
|
||||||
|
accessToken,
|
||||||
|
refreshToken,
|
||||||
|
type,
|
||||||
|
error: recoveryError,
|
||||||
|
errorDescription,
|
||||||
|
} = getRecoveryParams()
|
||||||
|
|
||||||
|
if (recoveryError || errorDescription) {
|
||||||
|
showInvalidRecoveryLink()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (code) {
|
||||||
|
const { error } = await supabase.auth.exchangeCodeForSession(code)
|
||||||
|
if (error) throw error
|
||||||
|
} else if (type === 'recovery' && accessToken && refreshToken) {
|
||||||
|
const { error } = await supabase.auth.setSession({
|
||||||
|
access_token: accessToken,
|
||||||
|
refresh_token: refreshToken,
|
||||||
|
})
|
||||||
|
if (error) throw error
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data: { session }, error } = await supabase.auth.getSession()
|
||||||
|
if (error || !session?.user) {
|
||||||
|
showInvalidRecoveryLink()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
window.history.replaceState(null, '', window.location.pathname)
|
||||||
|
state.value = 'ready'
|
||||||
|
} catch (e) {
|
||||||
|
error.value = getResetErrorMessage(e)
|
||||||
|
state.value = 'invalid'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function handleResetPassword() {
|
async function handleResetPassword() {
|
||||||
error.value = ''
|
error.value = ''
|
||||||
|
|
||||||
@@ -85,14 +140,8 @@ async function handleResetPassword() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(() => {
|
||||||
const { data: { session }, error: sessionError } = await supabase.auth.getSession()
|
void initializeRecoverySession()
|
||||||
if (sessionError || !session?.user) {
|
|
||||||
showInvalidRecoveryLink()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
state.value = 'ready'
|
|
||||||
})
|
})
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user