S
Supabase3mo ago
Ethan

Magic Link Redirects, Local Development, and Docker

I know there have been other post on this topic but I am still having some issues getting magic link auth redirects to work in my local docker development instance. Problem: Magic Link redirects and auth flow is broken in my docker development. Links are sent, and appear in InBucket, but upon clicking the link, the user is redirected to the url http://127.0.0.1:54321/auth/v1/verify?token=pkce_....&type=magiclink&redirect_to=http://127.0.0.1:3000/auth/confirm, and upon landing on the page, the user is not authed. I do see the authenticated user in supabase's auth and my custom profiles (setup via a function and trigger), but the user session is null. In addition to this, the Supbase UI via docker does not have the options to easily edit Redirect URLs, email templates, etc. My Email Template (prod):
<h2>You have requested to login to your account.</h2>

<p>Follow this link to login:</p>
<p><a href="{{ .RedirectTo }}/auth/confirm?token_hash={{ .TokenHash }}&type=email">Log In</a></p>
<h2>You have requested to login to your account.</h2>

<p>Follow this link to login:</p>
<p><a href="{{ .RedirectTo }}/auth/confirm?token_hash={{ .TokenHash }}&type=email">Log In</a></p>
SignIn function:
export async function signInWithEmail(email: string) {
const supabase = await createClient()

const { data, error } = await supabase.auth.signInWithOtp({
email: email,
options: {
// set this to false if you do not want the user to be automatically signed up
// shouldCreateUser: false,
// I set this to this URL for development only
// Previously set to localhost:3000 w/ no docker and it worked
emailRedirectTo: 'http://127.0.0.1:3000/auth/confirm',
},
})

console.log("sign in started", data)
}
export async function signInWithEmail(email: string) {
const supabase = await createClient()

const { data, error } = await supabase.auth.signInWithOtp({
email: email,
options: {
// set this to false if you do not want the user to be automatically signed up
// shouldCreateUser: false,
// I set this to this URL for development only
// Previously set to localhost:3000 w/ no docker and it worked
emailRedirectTo: 'http://127.0.0.1:3000/auth/confirm',
},
})

console.log("sign in started", data)
}
I also saw a post that mentioned being able to set the site URL in the supbase/config.toml could help site_url = "http://localhost:3000" And for additional context, here is my app/api/auth/confirm/route.ts Conclusion: I am still unsure how to approach using magic link logins in docker vs just localhost:3000. Any help or feedback would be appreciated.
4 Replies
Ethan
EthanOP3mo ago
In addition to this, here is my `/app/api/auth/confirm/route.ts
import { type EmailOtpType } from '@supabase/supabase-js'
import { type NextRequest } from 'next/server'

import { createClient } from '@/utils/supabase/server'
import { redirect } from 'next/navigation'

export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url)
const token_hash = searchParams.get('token_hash')
const type = searchParams.get('type') as EmailOtpType | null
const next = searchParams.get('next') ?? '/'

if (token_hash && type) {
const supabase = await createClient()

const { error } = await supabase.auth.verifyOtp({
type,
token_hash,
})

await supabase.auth.getUser()

if (!error) {
// redirect user to specified redirect URL or root of app
redirect('/')
}
}

// redirect the user to an error page with some instructions
redirect('/error')
}
import { type EmailOtpType } from '@supabase/supabase-js'
import { type NextRequest } from 'next/server'

import { createClient } from '@/utils/supabase/server'
import { redirect } from 'next/navigation'

export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url)
const token_hash = searchParams.get('token_hash')
const type = searchParams.get('type') as EmailOtpType | null
const next = searchParams.get('next') ?? '/'

if (token_hash && type) {
const supabase = await createClient()

const { error } = await supabase.auth.verifyOtp({
type,
token_hash,
})

await supabase.auth.getUser()

if (!error) {
// redirect user to specified redirect URL or root of app
redirect('/')
}
}

// redirect the user to an error page with some instructions
redirect('/error')
}
I am new to docker development and I think my core issue is understanding the redirects and endpoints. Note: I thought 127.0.0.1 was the same as localhost:3000, so maybe the cause is something unrelated to magic link email templates and directs?
Ethan
EthanOP3mo ago
This helped me fix the issue with redirects in Docker. Thank you @inder ! I added the following to supbase/config.toml
[auth]
enabled = true
# The base URL of your website. Used as an allow-list for redirects and for constructing URLs used
# in emails.
site_url = "http://localhost:3000"
# A list of *exact* URLs that auth providers are permitted to redirect to post authentication.
additional_redirect_urls = ["https://localhost:3000"]
[auth.email.template.magic_link]
subject = "Your Magic Link"
content_path = "./supabase/auth/email/magic-link.html"
[auth]
enabled = true
# The base URL of your website. Used as an allow-list for redirects and for constructing URLs used
# in emails.
site_url = "http://localhost:3000"
# A list of *exact* URLs that auth providers are permitted to redirect to post authentication.
additional_redirect_urls = ["https://localhost:3000"]
[auth.email.template.magic_link]
subject = "Your Magic Link"
content_path = "./supabase/auth/email/magic-link.html"
and then in the email template and functions:
<h2>You have requested to login to your account.</h2>

<p>Follow this link to login:</p>
<p><a href="{{ .RedirectTo }}/auth/confirm?token_hash={{ .TokenHash }}&type=email">Log In</a></p>
<h2>You have requested to login to your account.</h2>

<p>Follow this link to login:</p>
<p><a href="{{ .RedirectTo }}/auth/confirm?token_hash={{ .TokenHash }}&type=email">Log In</a></p>
export async function signInWithEmail(email: string) {
const supabase = await createClient()

const { data, error } = await supabase.auth.signInWithOtp({
email: email,
options: {
// set this to false if you do not want the user to be automatically signed up
// shouldCreateUser: false,
emailRedirectTo: 'http://localhost:3000',
},
})

console.log("sign in started", data)
}
export async function signInWithEmail(email: string) {
const supabase = await createClient()

const { data, error } = await supabase.auth.signInWithOtp({
email: email,
options: {
// set this to false if you do not want the user to be automatically signed up
// shouldCreateUser: false,
emailRedirectTo: 'http://localhost:3000',
},
})

console.log("sign in started", data)
}
---
inder
inder3mo ago
browser sees 127.0.0.1 and localhost as separate urls. So if auth cookie is set on 127.0.0.1, it won't be seen on localhost

Did you find this page helpful?