auth-helpers: [Invite user by email] Code Exchange Route doesn't generate Supabase client and session.

Supabase’s instruction I followed is here.

In app/auth/callback/route.ts file, added the following code snippet.

import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs'
import { cookies } from 'next/headers'
import { NextResponse } from 'next/server'

import type { NextRequest } from 'next/server'
import type { Database } from '@/lib/database.types'

export async function GET(request: NextRequest) {
  const requestUrl = new URL(request.url)
  const code = requestUrl.searchParams.get('code')

  console.log(`/auth/callback`, code);

  if (code) {
    const supabase = createRouteHandlerClient<Database>({ cookies })
    await supabase.auth.exchangeCodeForSession(code)
  }

  // URL to redirect to after sign in process completes
  return NextResponse.redirect(requestUrl.origin)
}

I created a magic link successfully via API. When it was accepted, code was found NULL. Therefore, Supabase didn’t create its client and generate the session.

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Reactions: 1
  • Comments: 23 (12 by maintainers)

Most upvoted comments

Spent the entire day dealing with this issue and not even knowing what the root cause was. Had to break out the debugger and step through the code manually to determine that I indeed wasn’t doing anything wrong on my end.

So basically, out of the box, there is NO way anymore to create a user and send them an invite link, since inviteUserByEmail() only supports the implicit auth flow.

Two months ago, auth-helpers dropped support for this flow, and yet there’s no mention of this in the official Supabase documentation for this function.

I would really have appreciated a mention of this in the docs for inviteUserByEmail(), so I didn’t have to go down this rabbit hole.

Anyway, this clunky workaround works for me:

const hashParams = new URLSearchParams(window.location.hash.substring(1));
const access_token = hashParams.get('access_token');
const refresh_token = hashParams.get('refresh_token');

const { data, error } = await supabase.auth.setSession({
  access_token,
  refresh_token,
});

@bjarkebech yes this is being worked on. The screen recording above shows a working version, we just need to get some of these changes wrapped up in the CLI tool. This change will require a change to your email templates.

I’m running into the same problem. There really needs to be a complete example regarding how to handle inbound requests from invite emails.

We have published a new guide on how to handle this from the email perspective and framework side of things. Note that this guide does not mention supabase.auth.admin.generateLink() but the same setup will still work. Here is a link from the part that you would need to follow https://supabase.com/docs/guides/auth/server-side/email-based-auth-with-pkce-flow-for-ssr#create-api-endpoint-for-handling-tokenhash

If you are using the Supabase CLI and want to customize your email templates, you can do this now by following this guide https://supabase.com/docs/guides/cli/customizing-email-templates

Spent the entire day dealing with this issue and not even knowing what the root cause was. Had to break out the debugger and step through the code manually to determine that I indeed wasn’t doing anything wrong on my end.

So basically, out of the box, there is NO way anymore to create a user and send them an invite link, since inviteUserByEmail() only supports the implicit auth flow.

Two months ago, auth-helpers dropped support for this flow, and yet there’s no mention of this in the official Supabase documentation for this function.

I would really have appreciated a mention of this in the docs for inviteUserByEmail(), so I didn’t have to go down this rabbit hole.

Anyway, this clunky workaround works for me:

const hashParams = new URLSearchParams(window.location.hash.substring(1));
const access_token = hashParams.get('access_token');
const refresh_token = hashParams.get('refresh_token');

const { data, error } = await supabase.auth.setSession({
  access_token,
  refresh_token,
});

The issue with this approach is that the magic link does not expire after clicking on it. The user can continue to click on it multiple times and be logged in automatically. This may be a security risk in an application as anyone with future access to the invite email can log into the user’s account.

@hamishtaplin we are working on the local dev email templates support at the moment and will have something ready for the general public soon. I’ve attached a preview video of the PoC.

https://github.com/supabase/auth-helpers/assets/79497/300d7b4d-96e1-4f42-bb3c-1af147858bae

@silentworks can you confirm that you are working on implementing the PKCE flow for the magic link in inviteUserByEmail()?

If not, which other path would you suggest for inviting users by email?