bWgibb
bWgibb

Reputation: 31

supabase auth error AuthApiError: "Database error finding user from email link"

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

Answers (2)

bk3
bk3

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

dshukertjr
dshukertjr

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

Related Questions