Phone Auth with MessageBird
Overview
In this guide we'll show you how to authenticate your users with SMS based OTP (One-Time Password) tokens.
There are two reasons to use Supabase SMS OTP tokens:
- You want users to log in with mobile + password, and the mobile should be verified via SMS
- You want users to log in with mobile ONLY (i.e. passwordless login)
We'll cover:
- Finding your MessageBird credentials
- Using OTP with password based logins
- Using OTP as a passwordless sign-in mechanism
What you'll need:
- A MessageBird account (sign up here: https://dashboard.messagebird.com/en/sign-up)
- A Supabase project (create one here: https://app.supabase.com)
- A mobile phone capable of receiving SMS
Steps
Finding your MessageBird credentials
Start by logging into your MessageBird account and verify the mobile number you'll be using to test with: https://dashboard.messagebird.com/en/getting-started/sms
This is the number that will be receiving the SMS OTPs.
Navigate to the dashboard settings to set the default originator. The messagebird originator is the name or number from which the message is sent. For more information, you can refer to the messagebird article on choosing an originator here
You will need the following values to get started:
- Live API Key / Test API Key
- MessageBird originator
Now go to the Auth > Settings page in the Supabase dashboard (https://app.supabase.com/project/YOUR-PROJECT-REF/auth/settings).
You should see an option to enable Phone Signup.
Toggle it on, and copy the 2 values over from the messagebird dashboard. Click save.
Note: If you use the Test API Key, the OTP will not be delivered to the mobile number specified but messagebird will log the response in the dashboard. If the Live API Key is used instead, the OTP will be delivered and there will be a deduction in your free credits.
Plugin MessageBird credentials
Now the backend should be setup, we can proceed to add our client-side code!
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 Auth > Templates page in the Supabase dashboard (https://app.supabase.com/project/YOUR-PROJECT-REF/auth/templates).
Use the variable .Code
in the template to display the code.
Using OTP with password based logins
In this use scenario we'll be using the user's mobile phone number as an alternative to an email address when signing up along with a password. You may want to think hard about the permanency of this however. It is not uncommon for mobile phone numbers to be recycled by phone networks when users cancel their phone contracts or move countries, therefore granting access to the user's account to whoever takes over the phone number in the future. Soon we'll add multi-factor auth, which will mitigate this risk, but for now you may want to give some thought to 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
:
- JavaScript
- HTTP
let { user, error } = await supabase.auth.signUp({
phone: '+13334445555',
password: 'some-password',
})
curl -X POST 'https://cvwawazfelidkloqmbma.supabase.co/auth/v1/signup' \
-H "apikey: SUPABASE_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone": "+13334445555",
"password": "some-password"
}'
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
:
- JavaScript
- HTTP
let { session, error } = await supabase.auth.verifyOTP({
phone: '+13334445555',
token: '123456',
})
curl -X POST 'https://cvwawazfelidkloqmbma.supabase.co/auth/v1/verify' \
-H "apikey: SUPABASE_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "sms",
"phone": "+13334445555",
"token": "123456"
}'
If successful the user will now be logged in and you should receive a valid session like:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJhdXRoZW50aWNhdGVkIiwiZXhwIjoxNjI3MjkxNTc3LCJzdWIiOiJmYTA2NTQ1Zi1kYmI1LTQxY2EtYjk1NC1kOGUyOTg4YzcxOTEiLCJlbWFpbCI6IiIsInBob25lIjoiNjU4NzUyMjAyOSIsImFwcF9tZXRhZGF0YSI6eyJwcm92aWRlciI6InBob25lIn0sInVzZXJfbWV0YWRhdGEiOnt9LCJyb2xlIjoiYXV0aGVudGljYXRlZCJ9.1BqRi0NbS_yr1f6hnr4q3s1ylMR3c1vkiJ4e_N55dhM",
"token_type": "bearer",
"expires_in": 3600,
"refresh_token": "LSp8LglPPvf0DxGMSj-vaQ"
}
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:
- JavaScript
- HTTP
let { user, error } = await supabase.auth.signIn({
phone: '+13334445555',
password: 'some-password',
})
curl -X POST 'https://cvwawazfelidkloqmbma.supabase.co/auth/v1/token?grant_type=password' \
-H "apikey: SUPABASE_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone": "+13334445555",
"password": "some-password"
}'
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
- JavaScript
- HTTP
let { user, error } = await supabase.auth.signIn({
phone: '+13334445555',
})
curl -X POST 'https://cvwawazfelidkloqmbma.supabase.co/auth/v1/otp' \
-H "apikey: SUPABASE_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone": "+13334445555"
}'
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:
- JavaScript
- HTTP
let { session, error } = await supabase.auth.verifyOTP({
phone: '+13334445555',
token: '123456',
})
curl -X POST 'https://cvwawazfelidkloqmbma.supabase.co/auth/v1/verify' \
-H "apikey: SUPABASE_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "sms",
"phone": "+13334445555",
"token": "123456"
}'
and the response should also be the same as above:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJhdXRoZW50aWNhdGVkIiwiZXhwIjoxNjI3MjkxNTc3LCJzdWIiOiJmYTA2NTQ1Zi1kYmI1LTQxY2EtYjk1NC1kOGUyOTg4YzcxOTEiLCJlbWFpbCI6IiIsInBob25lIjoiNjU4NzUyMjAyOSIsImFwcF9tZXRhZGF0YSI6eyJwcm92aWRlciI6InBob25lIn0sInVzZXJfbWV0YWRhdGEiOnt9LCJyb2xlIjoiYXV0aGVudGljYXRlZCJ9.1BqRi0NbS_yr1f6hnr4q3s1ylMR3c1vkiJ4e_N55dhM",
"token_type": "bearer",
"expires_in": 3600,
"refresh_token": "LSp8LglPPvf0DxGMSj-vaQ"
}
The user does not have a password therefore will need to sign in via this method each time they want to access your service.