Auth

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 1 hour.

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
_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