Implementing Passwordless Login with Supabase Magic Links
Eliminate password friction by implementing Supabase Magic Links. Learn how to set up passwordless OTP authentication, handle redirects, and secure your flow against phishing.
26 Jan 2026, 14:55 UTC

The Password Friction Problem
Passwords are a significant point of friction in user onboarding. They lead to forgotten credentials, repetitive password reset requests, and security vulnerabilities when users reuse simple passwords across multiple sites. For many modern applications, requiring a password for initial access is an unnecessary barrier.
The solution is Magic Links: a passwordless authentication flow where a user enters their email and receives a time-bound, single-use URL. Clicking this link proves ownership of the email address and establishes a session immediately. This shifts the security burden from the user's memory to the security of their email provider.
How Supabase Handles OTP-based Auth
Supabase implements this via One-Time Passwords (OTP). While the term "OTP" often refers to a 6-digit code, Supabase uses it to power both numeric codes and magic links. When a magic link is requested, Supabase generates a unique token, associates it with the user's email in the database, and sends it via an SMTP (Simple Mail Transfer Protocol) server.
The system relies on a Redirect URL. Because the user clicks the link in an external email client, Supabase needs to know where to send the user back to your application after the token is verified. This redirect carries the session data back to your frontend, where the Supabase client library parses it to establish the local session.
Implementation Example
To implement this flow, you need the @supabase/supabase-js library installed in your frontend project. Ensure you have added your site's URL to the "Redirect URLs" list in the Supabase Dashboard under Auth > URL Configuration.
Requesting the Magic Link
Run this function from your client-side login form. This triggers the email dispatch.
async function requestMagicLink(email) {
const { data, error } = await supabase.auth.signInWithOtp({
email: email,
options: {
// This must be explicitly whitelisted in your Supabase dashboard
emailRedirectTo: 'https://your-app.com/welcome',
},
});
if (error) {
console.error('Error requesting link:', error.message);
return;
}
alert('Check your email for the login link!');
}Handling the Session
When the user clicks the link, they are redirected to your emailRedirectTo URL. The Supabase client automatically detects the fragments in the URL and creates a session. You can verify the state using a listener:
supabase.auth.onAuthStateChange((event, session) => {
if (event === 'SIGNED_IN') {
console.log('User authenticated successfully:', session.user.email);
// Redirect user to their dashboard or update UI state
}
});Operational Trade-offs and Limitations
| Consideration | Risk/Limitation | Mitigation |
|---|---|---|
| Deliverability | Default Supabase SMTP limits can cause emails to land in spam. | Connect a custom SMTP provider (SendGrid, Postmark, etc.) in the Auth settings. |
| Token Expiry | Links expire (default 15 mins), leading to "Invalid Link" errors. | Provide a clear "Resend Link" button on the login page. |
| Device Switching | User requests link on desktop but clicks it on mobile. | Supabase handles this via the token; the session will be established on the device that clicks the link. |
Security Warning: Phishing and Domain Spoofing
Magic links are susceptible to phishing if users are conditioned to click links in emails without scrutiny. To mitigate this, always enforce strict Domain Whitelisting in your Supabase project settings. Never allow wildcard redirects (e.g., *) in production, as this could allow an attacker to steal session tokens by redirecting users to a malicious domain.
Verification Checklist
To confirm your implementation is working correctly, perform these three checks:
- Flow Check: Trigger the link, click it, and verify that
supabase.auth.getSession()returns a valid user object in the browser console. - Expiry Check: Set the OTP expiration to 1 minute in the dashboard. Wait 61 seconds before clicking the link; the application should return an authentication error.
- Redirect Check: Attempt to use a redirect URL that is not in your whitelist. Supabase should default to your site's base URL rather than the requested unauthorized path.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.