Home

Login With Email 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. By default, a user can only request an OTP once every 60 seconds and they expire after 24 hours.

Setting up email OTP#

To set up email OTP for your Supabase app:

  • Enable the email provider in your Supabase Project
  • The Site URL represents the default URL that the user will be redirected to after clicking on the email signup confirmation link.
  • If a user has not signed up yet, signing in with an OTP will automatically sign up the user. To prevent users from signing up this way, you can set the shouldCreateUser option to false.
  • Navigate to the email template settings and 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>

Signing in a user with email OTP#

When your user signs in, call signInWithOtp() with their email address:


_10
const { data, error } = await supabase.auth.signInWithOtp({
_10
email: 'example@email.com',
_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 was successful, you receive a response with error: null and a data object where both user and session are null. In this case you can let the user know to check their email inbox.


_10
{
_10
"data": {
_10
"user": null,
_10
"session": null
_10
},
_10
"error": null
_10
}

Verify OTP to create session#

Provide an input field for the user to key in the one-time code. To verify the code and complete the user's sign in, call verifyOtp() with their email address, the code, and type: "email":


_10
const {
_10
data: { session },
_10
error,
_10
} = await supabase.auth.verifyOtp({
_10
email,
_10
token: '123456',
_10
type: 'email',
_10
})

If successful the user will now be logged in and you should receive a valid session 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
}

Resources#