Passwordless email logins
Email logins using Magic Links or One-Time Passwords (OTPs)
Supabase Auth provides several passwordless login methods. Passwordless logins allow users to sign in without a password, by clicking a confirmation link or entering a verification code.
Passwordless login can:
- Improve the user experience by not requiring users to create and remember a password
- Increase security by reducing the risk of password-related security breaches
- Reduce support burden of dealing with password resets and other password-related flows
Supabase Auth offers two passwordless login methods that use the user's email address:
With Magic Link
Magic Links are a form of passwordless login where users click on a link sent to their email address to log in to their accounts. Magic Links only work with email addresses and are one-time use only.
Enabling Magic Link
Email authentication methods, including Magic Links, are enabled by default.
Configure the Site URL and any additional redirect URLs. These are the only URLs that are allowed as redirect destinations after the user clicks a Magic Link. You can change the URLs on the Auth Providers page for hosted projects, or in the configuration file for self-hosted projects.
By default, a user can only request a magic link once every 60 seconds and they expire after 1 hour.
Signing in with Magic Link
Call the "sign in with OTP" method from the client library.
Though the method is labelled "OTP", it sends a Magic Link by default. The two methods differ only in the content of the confirmation email sent to the user.
If the user hasn't signed up yet, they are automatically signed up by default. To prevent this, set the shouldCreateUser
option to false
.
_10async function signInWithEmail() {_10 const { data, error } = await supabase.auth.signInWithOtp({_10 email: 'valid.email@supabase.io',_10 options: {_10 // set this to false if you do not want the user to be automatically signed up_10 shouldCreateUser: false,_10 emailRedirectTo: 'https://example.com/welcome',_10 },_10 })_10}
That's it for the implicit flow.
If you're using PKCE flow, edit the Magic Link email template to send a token hash:
_10<h2>Magic Link</h2>_10_10<p>Follow this link to login:</p>_10<p><a href="{{ .SiteURL }}/auth/confirm?token_hash={{ .TokenHash }}&type=magiclink">Log In</a></p>
At the /auth/confirm
endpoint, exchange the hash for the session:
_10const { error } = await supabase.auth.verifyOtp({ token_hash, type })
With OTP
Email one-time passwords (OTP) are a form of passwordless login where users key in a six digit code sent to their email address to log in to their accounts.
Enabling email OTP
Email authentication methods, including Email OTPs, are enabled by default.
Email OTPs share an implementation with Magic Links. To send an OTP instead of a Magic Link, alter the Magic Link email template. For a hosted Supabase project, go to Email Templates in the Dashboard. For a self-hosted project or local development, see the Email Templates guide.
Modify the template to include the {{ .Token }}
variable, for example:
_10<h2>One time login code</h2>_10_10<p>Please enter this code: {{ .Token }}</p>
By default, a user can only request an OTP once every 60 seconds and they expire after 1 hour. This is configurable via Auth > Providers > Email > Email OTP Expiration
. An expiry duration of more than 86400 seconds (one day) is disallowed to guard against brute force attacks. The longer an OTP remains valid, the more time an attacker has to attempt brute force attacks. If the OTP is valid for several days, an attacker might have more opportunities to guess the correct OTP through repeated attempts.
Signing in with email OTP
Step 1: Send the user an OTP code
Get the user's email and call the "sign in with OTP" method from your client library.
If the user hasn't signed up yet, they are automatically signed up by default. To prevent this, set the shouldCreateUser
option to false
.
_10const { data, error } = await supabase.auth.signInWithOtp({_10 email: 'valid.email@supabase.io',_10 options: {_10 // set this to false if you do not want the user to be automatically signed up_10 shouldCreateUser: false,_10 },_10})
If the request is successful, you receive a response with error: null
and a data
object where both user
and session
are null. Let the user know to check their email inbox.
_10{_10 "data": {_10 "user": null,_10 "session": null_10 },_10 "error": null_10}
Step 2: Verify the OTP to create a session
Provide an input field for the user to enter their one-time code.
Call the "verify OTP" method from your client library with the user's email address, the code, and a type of email
:
_10const {_10 data: { session },_10 error,_10} = await supabase.auth.verifyOtp({_10 email,_10 token: '123456',_10 type: 'email',_10})
If successful, the user is now logged in, and you receive a valid session that looks like:
_10{_10 "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJhdXRoZW50aWNhdGVkIiwiZXhwIjoxNjI3MjkxNTc3LCJzdWIiOiJmYTA2NTQ1Zi1kYmI1LTQxY2EtYjk1NC1kOGUyOTg4YzcxOTEiLCJlbWFpbCI6IiIsInBob25lIjoiNjU4NzUyMjAyOSIsImFwcF9tZXRhZGF0YSI6eyJwcm92aWRlciI6InBob25lIn0sInVzZXJfbWV0YWRhdGEiOnt9LCJyb2xlIjoiYXV0aGVudGljYXRlZCJ9.1BqRi0NbS_yr1f6hnr4q3s1ylMR3c1vkiJ4e_N55dhM",_10 "token_type": "bearer",_10 "expires_in": 3600,_10 "refresh_token": "LSp8LglPPvf0DxGMSj-vaQ",_10 "user": {...}_10}