Two-factor authentication (2FA) can play a key role in securing your applications against password data breaches. Authentication with a one-time password (OTP) delivered to your users over SMS is an effective approach to implementing two-factor authentication. Plivo’s premium direct routes guarantee the highest possible delivery rates and the shortest possible delivery times for your 2FA SMS messages.
This guide shows how to set up SMS-based two-factor authentication using either PHLO or traditional API development. PHLO lets you create and deploy workflows from an intuitive graphical canvas in few clicks.
You can create and deploy a PHLO to handle 2FA with a few clicks on the PHLO canvas and trigger it with a few lines of code.
To get started, you need a Plivo account — sign up with your work email address if you don’t have one already. If this is your first time triggering a PHLO with Ruby, follow our instructions to set up a Ruby development environment.
Plivo provides a prototype for 2FA; all you have to do is select the PHLO and give it a friendly name.
Once you‘ve created the PHLO, download and modify the code to trigger it.
$ git clone https://github.com/plivo/2fa-ruby-demo.git
$ cd 2fa-ruby-demo
$ bundle install
Let‘s walk through what the code does.
We use the Time-Based OTP algorithm to generate a random six-digit one-time password (OTP).
1
code = rand(999_999)
With a single function, we can send an SMS message or make a call via PHLO (in the event the initial SMS message never arrives). The argument that tells PHLO whether to send an SMS message or make a call is mode, and the allowed values passed to it are sms and call.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def initiate_phlo(dst_number, mode)
code = rand(999_999)
begin
phlo = @phloclient.phlo.get(@phlo_id)
# parameters set in PHLO - params
params = {
from: @app_number,
to: dst_number,
otp: code,
mode: mode
}
phlo.run(params)
code
rescue PlivoRESTError => e
puts 'Exception: ' + e.message
end
end
We verify the OTP the user enters on their handset.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
get '/checkcode/:number/:code' do
##
# Validates the code entered by the user
#
number = params['number']
code = params['code']
original_code = r.get('number:%s:code' % number)
content_type :json
if original_code == code
r.del('number:%s:code' % number) # verification successful, delete the code
return { status: 'success', message: 'codes match, number verified' }.to_json
elsif original_code != code
return { status: 'failure', message: 'codes do not match, number not verified' }.to_json
else
return { status: 'rejected', message: 'number not found' }.to_json
end
To test the application, start the Redis server.
$ redis-server
Run the application.
$ ruby app.rb
Set up ngrok to expose your local server to the internet.
You should be able to see the application in action at https://<ngrok_identifier>.ngrok.io/.
The finished application should look like this.
Here’s how to implement 2FA using Plivo APIs.
To get started, you need a Plivo account — sign up with your work email address if you don’t have one already. If this is your first time using Plivo APIs, follow our instructions to set up a Ruby development environment.
$ git clone https://github.com/plivo/2fa-ruby-demo.git
$ cd 2fa-ruby-demo
$ bundle install
Let‘s walk through what the code does.
Use the Time-Based OTP algorithm to generate a random six-digit one-time password (OTP).
1
code = rand(999_999)
Send an SMS message with the OTP to the user’s registered mobile number using Plivo’s Send Message API.
1
2
3
4
5
6
7
8
9
10
11
def send_verification_code_sms(dst_number, message)
code = rand(999_999)
@client.messages.create(
src: @app_number,
dst: [dst_number],
text: message.gsub('__code__', code.to_s)
)
code
rescue PlivoRESTError => e
puts 'Exception: ' + e.message
end
If the SMS message doesn’t reach the mobile device, the user can request a voice OTP.
1
2
3
4
5
6
7
8
9
10
11
def send_verification_code_call(dst_number)
code = rand(999_999)
@client.calls.create(
@app_number,
[dst_number],
"https://twofa-answerurl.herokuapp.com/answer_url/#{code}"
)
code
rescue PlivoRESTError => e
puts 'Exception: ' + e.message
end
Verify the OTP the user entered on their handset.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
get '/checkcode/:number/:code' do
##
# Validates the code entered by the user.
#
number = params['number']
code = params['code']
original_code = r.get('number:%s:code' % number)
content_type :json
if original_code == code
r.del('number:%s:code' % number) # verification successful, delete the code
return { status: 'success', message: 'codes match, number verified' }.to_json
elsif original_code != code
return { status: 'failure', message: 'codes do not match, number not verified' }.to_json
else
return { status: 'rejected', message: 'number not found' }.to_json
end
To test the application, start the Redis server.
$ redis-server
Save your code and run it.
$ ruby app.rb
Set up ngrok to expose your local server to the internet.
You should be able to see the application in action at https://
The finished application should look like this.