Reputation: 31
I have a nextjs 14/supabase app (using app router and ssr). When a new user signs up via email and clicks the accept invite link, they get an error "Database error finding user from email link".
I've configurated the email link to be as follows:
{{ .SiteURL }}/auth/confirm?token_hash={{.TokenHash}}&type=email&next={{.SiteURL}}/projects"
My auth/confirm/route.ts file is as follows:
import { EmailOtpType } from "@supabase/supabase-js"
import { cookies } from "next/headers"
import { NextRequest, NextResponse } from "next/server"
export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url)
const token_hash = searchParams.get("token_hash")
const next = searchParams.get("next")
const type = searchParams.get("type")
const cookieStore = cookies()
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
get(name) {
return cookieStore.get(name)?.value
},
set(name, value, options) {
cookieStore.set({ name, value, ...options })
},
remove(name, options) {
cookieStore.set({ name, value: "", ...options })
},
},
},
)
if (token_hash && type) {
const { error } = await supabase.auth.verifyOtp({
type: assertOtpType(type),
token_hash,
})
console.log({ error })
if (!error) {
return NextResponse.redirect(next!)
}
}
return NextResponse.redirect(process.env.SITE_URL + "/error")
}
function assertOtpType(type: string): EmailOtpType {
if (type !== "email") {
throw new Error("Invalid OTP type")
}
return type
}
I have my auth.users
table and my public.users
table. There is a trigger and a function to insert the new user in the public.users
table. This seems to work when the user signs up. It's just when the confirm with the email link that things break.
When the user signs up, I do notice a cookie is created sb-vfhoyptcwlciarlfXXXX-auth-token-code-verifier
with value %22b37534612078b7ddc7450ebee93be7ad6da263e945c18f6418d8f45568196013adbd864a392f197c20f9108ac3046cbee1030dXXXXXXXXXXXXXXX
(changed some values to X's in case this is not safe to post).
Here is the code for when the user signs up:
import { createClientServer } from "@/supabase/server"
export const signUp = async (formData: FormData, captchaToken: string) => {
const email = formData.get("email") as string
const password = formData.get("password") as string
const supabase = createClientServer()
const origin = process.env.SITE_URL
const { error } = await supabase.auth.signUp({
email,
password,
options: {
emailRedirectTo: `${origin}/projects`,
captchaToken: captchaToken,
},
})
if (error) {
console.error(error)
} else {
console.log("Check your email for the confirmation link.")
}
}
Any ideas on this error?
Upvotes: 0
Views: 487
Reputation: 167
I've encountered this kind of issue with reset-password workflow
my verify OTP return Email link is invalid or has expired every time.
I thought the problem was from supabase or SMTP and I fixed it by calling my function at the mounted step of my component I use nuxt 3 (3.11.2)
I don't know react but I think there a equivalent to onMounted function
here's my code
onMounted(async () => {
await getUserFromToken()
})
async function getUserFromToken() {
try {
const tokenHash = route.query.th
const type = route.query.type
if (tokenHash && type) {
const { data, error } = await supabase.auth.verifyOtp({
token_hash: tokenHash,
type,
})
if (error) throw error
console.log(data)
email.value = data.user.email
console.log(email.value)
}
} catch (error) {
console.error(error)
}
}
on supabase dashboard: Authentication -> Email templates -> reset password
<p><a href="{{ .SiteURL }}/reset-pwd?th={{ .TokenHash }}&type=recovery">Reset Password</a></p>
Upvotes: 0
Reputation: 18680
I think you just have a malformatted confirmation link in your auth email template.
Just replace {{ .SiteURL }}/auth/confirm?token_hash={{.TokenHash}}&type=email&next={{.SiteURL}}/projects
with {{ .ConfirmationURL }}
in your email template, and it should work just fine.
Upvotes: 0