supabase / supabase-js

An isomorphic Javascript client for Supabase. Query your Supabase database, subscribe to realtime events, upload and download files, browse typescript examples, invoke postgres functions via rpc, invoke supabase edge functions, query pgvector.
https://supabase.com
MIT License
2.86k stars 220 forks source link

Setting emailRedirectTo should set {{ .SiteURL }} in email template when using signInWithOtp #895

Open danhstevens opened 6 months ago

danhstevens commented 6 months ago

Bug report

Describe the bug

Assuming the Redirect URLs have properly been configured in Supabase configuration settings, when the emailRedirectTo parameter is specified, that URL should be represented in the email template via {{ .SiteURL }}

To Reproduce

Steps to reproduce the behavior, please provide code snippets or a repository:

  1. Make sure relevant URLs are correctly added to Supabase's Redirect URLs list
  2. Send a signInWithOtp with the emailRedirectTo as an option. Example:
supabase.auth.signInWithOtp({
  email: email,
  options: {
    emailRedirectTo: 'http://localhost:5173',
  },
});

Expected behavior

The value of {{ .SiteURL }} should match the value passed via emailRedirectTo. Instead, the default Site URL (as defined in the Supabase configuration) is set.

Additional context

emailRedirectTo should override {{ .SiteURL }} as that is what is expected and is necessary to have properly functioning email templates across different environments.

alfarih31 commented 6 months ago

I made a turn around by create an edge function to do the redirection. It is inspired by MS Defender safe link auth-email-templates#email-prefetching.

Deno.serve(async (req: Request) => {
  if (req.method !== 'GET') {
    return new Response({}, { status: 405 });
  }

  try {
    const origin = new URL(req.url);

    const confirmationUrl = new URL(origin.searchParams.get('confirmation_url'));
    const redirectUrl = new URL(confirmationUrl.searchParams.get('redirect_to'));

    redirectUrl.searchParams.set('token_hash', confirmationUrl.searchParams.get('token'));
    redirectUrl.searchParams.set('type', confirmationUrl.searchParams.get('type'));

    return Response.redirect(redirectUrl.toString(), 301);
  } catch (err) {
    return new Response({ error: err }, { status: 500 });
  }
});

After deploying this function you'll get an Endpoint URL and set SiteURL with the Endpoint URL. Also modify email template to pass the {{ .ConfirmationURL }} as query parameters confirmation_url as stated in auth-email-templates#email-prefetching. Here is an example for the email templates:

<h2>Magic Link</h2>

<p>Follow this link to login:</p>
<p><a href="{{ .SiteURL }}?confirmation_url={{ .ConfirmationURL }}">Log In</a></p>
ShinyObjectLabs commented 6 months ago

I also ran into a similar issue, but I don't think the fix should be to override {{ .SiteURL }} as a redirect URL is not related to the Site URL.

Instead, the root cause is the fact {{ .RedirectURL }} does not appear to work in the email templates, although the docs state it should be supported for signInWithOtp.

The redirect URLs are configured correctly because I can see the parameter in the {{ .ConfirmationURL }}.

https://supabase.com/docs/guides/auth/auth-email-templates#terminology

nienkedekker commented 5 months ago

Running into the same issue here. Any updates? 🙂

ArianSha commented 5 months ago

Yes! This is really annoying during development on localhost, when you want to test out the different email confirmations. In the official example, they have removed the usage of ".ConfirmationURL" to ".SiteURL" with ".TokenHash", which makes me believe that ".confirmationURL" will be entirely removed/changed soon.

https://supabase.com/docs/guides/auth/server-side/email-based-auth-with-pkce-flow-for-ssr?framework=nextjs

lyonsbp commented 4 months ago

Im also having this issue, seems impossible to have both localhost and prod logins redirect correctly. My sign up function looks like this:

export async function action({ request, context }: ActionFunctionArgs) {
  const cookies = parse(request.headers.get("Cookie") ?? "");
  const headers = new Headers();
  const formData = await request.formData();

  const supabase = createServerClient(
    context.env.SUPABASE_PROJECT_URL!,
    context.env.SUPABASE_ANON_KEY!,
    {
      cookies: {
        get(key) {
          return cookies[key];
        },
        set(key, value, options) {
          headers.append("Set-Cookie", serialize(key, value, options));
        },
        remove(key, options) {
          headers.append("Set-Cookie", serialize(key, "", options));
        }
      }
    }
  );

  const { data, error } = await supabase.auth.signUp({
    email: formData.get("email") as string,
    password: formData.get("password") as string,
    options: {
      emailRedirectTo: context.env.AUTH_REDIRECT_URI // resolves to "http://localhost:8788" in the dev env, is set to prod url on Cloudflare
    }
  });

  if (error) {
    return new Response(JSON.stringify(error), {
      headers
    });
  }

  return new Response(JSON.stringify(data), {
    headers
  });
}
anthonyg56 commented 4 months ago

I'm having the same issue, is there any updates on this?

bawgz commented 3 months ago

I also ran into a similar issue, but I don't think the fix should be to override {{ .SiteURL }} as a redirect URL is not related to the Site URL.

Instead, the root cause is the fact {{ .RedirectURL }} does not appear to work in the email templates, although the docs state it should be supported for signInWithOtp.

The redirect URLs are configured correctly because I can see the parameter in the {{ .ConfirmationURL }}.

https://supabase.com/docs/guides/auth/auth-email-templates#terminology

Stumbled upon this issue also expecting {{ .SiteURL }} to be overwritten with the redirect URL. I did not know {{ .RedirectURL }} was an option and I tried it out and it's working for me!