Home

Phone Auth with Twilio

tip

Authenticating users via SMS can become expensive. Adjust your project's rate limits and configure CAPTCHA to control the bill. Read more about this in the Production Checklist.

In this guide we'll show you how to authenticate your users with SMS based One-Time Password (OTP) tokens.

There are two reasons to use Supabase SMS OTP tokens:

  • You want users to log in with a phone number and password, and verify the phone number on signup with SMS
  • You want users to log in with a phone number ONLY (i.e. passwordless login)

What you'll need:

  • Twilio account (sign up)
  • Supabase project (create one here)
  • Mobile phone capable of receiving SMS

SMS Authentication can be done with either Twilio Verify or Twilio Programmable Messaging. Twilio Verify is a specialized OTP solution and is recommended for most developers that need over-the-phone authentication. Alternatively you can use Twilio Programmable Messaging which offers generic SMS sending support.

Twilio Verify#

To set up Twilio Verify, you will need to:

  1. Create a new verification service in the Twilio dashboard.
  2. Switch Phone Provider to Twilio Verify
  3. Configure the Twilio Verify Service ID field using the Verification Service ID obtained in 1.

When using Twilio Verify, OTPs are generated by Twilio. This means that:

  • Unlike other providers, the OTP expiry duration and message content fields are not configurable via the Supabase dashboard. Please head to Twilio Verify to configure these settings.
  • The token remains the same during its validity period until the verification is successful. This means if your user make another request within that period, they will receive the same token.
  • Twilio Verify has a separate set of rate limits that apply. Visit Twilio's Rate Limit and Timeouts page to find out more.

caution

At this time, Twilio Verify is only supported on the whatsapp and sms channels.

Twilio (Programmable Messaging)#

In this section we'll cover:

What you'll need:

Video#

Steps#

Finding your Twilio credentials#

Start by logging into your Twilio account and starting a new project: https://www.twilio.com/console/projects/create

Give your project a name and verify the mobile number you'll be using to test with. This is the number that will be receiving the SMS OTPs.

Name your twilio project verify your own phone number

Select 'SMS', 'Identity & Verification', and 'With code' as options on the welcome form.

Form Fields

When you're back on the Twilio console screen, you need to scroll down and click 'Get a trial phone number' - this is the number that you'll be sending SMSs from.

Get a trial phone number

Successful phone number

You should now be able to see all three values you'll need to get started:

  • Account SID
  • Auth Token
  • Sender Phone Number

All the credentials you'll need

Now go to the Auth > Providers page in the Supabase dashboard and select "Phone" from the Auth Providers list.

You should see an option to enable the Phone provider.

Toggle it on, and copy the 3 values over from the Twilio dashboard. Click save.

Note: for "Twilio Message Service SID" you can use the Sender Phone Number generated above.

Plug in Twilio credentials

Now the backend should be setup, we can proceed to add our client-side code!

info

The Twilio Content SID field is specific to Twilio Programmable Messaging (WhatsApp) senders. Disregard this field if you are only sending SMS messages. Refer to the section on WhatsApp OTP Logins for further details.

SMS custom template#

The SMS message sent to a phone containing an OTP code can be customized. This is useful if you need to mention a brand name or display a website address.

Go to the Auth > Providers page in the Supabase dashboard and select "Phone" from the Auth Providers list. Scroll to the very bottom of the "Phone" section to the "SMS Message" input - you can customize the SMS message here.

Use the variable .Code in the template to display the OTP code. Here's an example in the SMS template.

example in the SMS template

Using OTP with password based logins#

In this scenario we'll be using the user's mobile phone number and a corresponding password as an alternative to signing up with an email address. Note: please thoroughly consider potential security implications when signing up with a combination of phone number and password. Phone numbers are sometimes recycled by phone networks when users cancel their phone contracts or move countries, thereby granting access to the user's account to the subsequent owner of the phone number. In the near future Supabase will support multifactor authentication, which will mitigate this risk, but for now you may want to consider allowing your users to recover their account by some other means in an emergency.

Using supabase-js on the client you'll want to use the same signUp method that you'd use for email based sign ups, but with the phone param instead of the email param:


_10
const {
_10
data: { user, session },
_10
error,
_10
} = await supabase.auth.signUp({
_10
phone: '+13334445555',
_10
password: 'some-password',
_10
})

The user will now receive an SMS with a 6-digit pin that you will need to receive from them within 60-seconds before they can login to their account.

You should present a form to the user so they can input the 6 digit pin, then send it along with the phone number to verifyOtp:


_10
const {
_10
data: { session },
_10
error,
_10
} = await supabase.auth.verifyOtp({
_10
phone: '+13334445555',
_10
token: '123456',
_10
type: 'sms',
_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
}

The access token can be sent in the Authorization header as a Bearer token for any CRUD operations on supabase-js. See our guide on Row Level Security for more info on restricting access on a user basis.

Also now that the mobile has been verified, the user can use the number and password to sign in without needing to verify their number each time:


_10
const { user, error } = await supabase.auth.signInWithPassword({
_10
phone: '+13334445555',
_10
password: 'some-password',
_10
})

Using OTP as a passwordless sign-in mechanism#

In this scenario you are granting your user's the ability to login to their account without needing to set a password on their account, all they have to do to log in is verify their mobile each time using the OTP.

In JavaScript we can use the signIn method with a single parameter: phone


_10
const { data, error } = await supabase.auth.signInWithOtp({
_10
phone: '+13334445555',
_10
})

The second step is the same as the previous section, you need to collect the 6-digit pin from the user and pass it along with their phone number to the verify method:


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

and the response should also be the same as above:


_10
{
_10
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJhdXRoZW50aWNhdGVkIiwiZXhwIjoxNjI3MjkxNTc3LCJzdWIiOiJmYTA2NTQ1Zi1kYmI1LTQxY2EtYjk1NC1kOGUyOTg4YzcxOTEiLCJlbWFpbCI6IiIsInBob25lIjoiNjU4NzUyMjAyOSIsImFwcF9tZXRhZGF0YSI6eyJwcm92aWRlciI6InBob25lIn0sInVzZXJfbWV0YWRhdGEiOnt9LCJyb2xlIjoiYXV0aGVudGljYXRlZCJ9.1BqRi0NbS_yr1f6hnr4q3s1ylMR3c1vkiJ4e_N55dhM",
_10
"token_type": "bearer",
_10
"expires_in": 3600,
_10
"refresh_token": "LSp8LglPPvf0DxGMSj-vaQ"
_10
}

The user does not have a password therefore will need to sign in via this method each time they want to access your service.

WhatsApp OTP Logins#

In some cases, you may wish to use WhatsApp as a delivery channel instead. Here are some examples our users have cited:

  • You want higher deliverability
  • You wish for a secure channel
  • Your users mostly use WhatsApp as a messaging platform

Twilio Verify can be used with WhatsApp OTPs with no additional configuration.

Complete the following steps to use WhatsApp OTP with Twilio Programmable Messaging:

  1. Go through the Twilio self sign up guide for WhatsApp.
  2. Follow the Twilio Guide for Submitting Templates and submit a Basic Authentication Message for approval.

Alternatively, you can register a Twilio Content SID which corresponds to a message template. Twilio Content SID Image

Note that you may only use one Twilio Content SID at a time. Use Twilio Verify or the Basic Authentication Message if you require internationalization for your message template.

caution

Twilio Programmable Messaging (WhatsApp) can only be used with the Basic Authentication Message. For advanced customization options, please use Twilio Verify.

The sign in process with WhatsApp is similar to the sign in process for SMS. Do note the additional whatsapp parameter added:


_10
const { data, error } = await supabase.auth.signInWithOtp({
_10
phone: '+57336567365',
_10
options: {
_10
channel: 'whatsapp',
_10
},
_10
})

You can also sign up with whatsapp as a channel:


_10
const { data, error } = await supabase.auth.signUp({
_10
phone: '+57336567365',
_10
password: 'testsupabasenow',
_10
options: {
_10
channel: 'whatsapp',
_10
},
_10
})

There is no change in the verification process, you should continue to use the sms type for verification


_10
// After receiving a WhatsApp OTP
_10
const {
_10
data: { session },
_10
error,
_10
} = await supabase.auth.verifyOtp({
_10
phone: '+57336567365',
_10
token: '123456',
_10
type: 'sms',
_10
})

Resources#