Verify - passwordless authentication

Although logging in with usernames and passwords is very common, passwords can be hard to remember, insecure and do not always offer the best usability.

By implementing passwordless login you replace static passwords with single use codes delivered by Nexmo in an SMS or a Voice calls. Your users can forget about passwords.

This tutorial is based on the Passwordless Authentication use case. You download the code from https://github.com/Nexmo/ruby-passwordless-login.

In this tutorial

You see how easy it is to build a simple app that uses the Nexmo Verify API to log a user
in without any password.

The following sections explain the code in this tutorial. They show you how to:

Prerequisites

To work through this tutorial you need:

Create a basic Web app

For your customer interface, use Sinatra and rack to create a single page Web app:

app.rb
# web server and flash messages
require 'sinatra'
require 'rack-flash'
use Rack::Flash
app.rb
# enable sessions and set the
# session secret
enable :sessions
set :session_secret, '123456'

# specify a default layout
set :erb, layout: :layout

# Index
# - tries to show the current
#   user's phone number if it
#   is present
#
get '/' do
  @user = session[:user]
  erb :index
end

In the HTML you display the user's phone number and either:

  • If the user is already logged in, a logout link
  • A link to the login page.
views/index.erb
<h1>
  Hello <%= @user %>
</h1>

<% if @user %>
  <a href="/logout">Logout</a>
<% else %>
  <a href="/login">Login</a>
<% end %>

Collect a phone number

Using Verify you send a one time PIN to a user with 2 API calls. In the first call you send the user's phone number to Verify, Nexmo generates the PIN and delivers it to the user's phone. In the second call you send Verify the PIN entered by your user into your app, Verify checks that it is the same PIN.

When your user Login in your app, show them the login form:

app.rb
# Login
# - presents the user with a
#   form to fill in their
#   phone number
#
get '/login' do
  erb :login
end

The form captures the phone number in E.164 format expected by Voice API. For example, 441632960960.

views/login.erb
<form action="/start_login"
      method="post">

  <div class="field">
    <label for="number">
      Phone number
    </label>
    <input type="text" name="number">
  </div>

  <div class="actions">
    <input type="submit" value="Continue">
  </div>

</form>

When your user has submitted this form, you send a verification request.

Send verification request

To send the verification request, add the Nexmo REST API client for Ruby to your application:

Gemfile
gem 'nexmo'

Set your API key and secret in order to initialize the nexmo library.

app.rb
# nexmo library
require 'nexmo'
nexmo = Nexmo::Client.new(
  key: ENV['NEXMO_API_KEY'],
  secret: ENV['NEXMO_API_SECRET']
)

Note: best practice is to store your API credentials in your environment variables.

Send the user's phone number to Verify:

app.rb
# Start Verification
# - starts the verification
#   process, sending a code to
#   the user's phone number
#   and then redirecting them
#   to verify the code
#
post '/start_login' do
  # start verification request
  response = nexmo.start_verification(
    number: params['number'],
    brand: 'MyApp'
  )

  # any status that's not '0'
  # is an error
  if response['status'] == '0'
    # store the number so we
    # can show it later
    session[:number] = params['number']
    # store the verification
    # ID so we can verify the
    # user's code against it
    session[:verification_id] =
      response['request_id']

    redirect '/verify'
  else
    flash[:error] =
      response['error_text']

    redirect '/login'
  end
end

Verify returns the request_id that you need for the next step.

Collect the PIN

When the user receives the PIN they enter it into the UI of your app. The app uses request_id to send a Verify check request for the PIN.

The app uses the following form to collect the PIN entered by the user:

app.rb
# Code Verify
# - shows the user a form to
#   fill in the code they
#   received via text message
#
get '/verify' do
  erb :verify
end
views/verify.erb
<form action="/finish_login"
      method="post">

  <div class="field">
    <label for="number">
      Code
    </label>
    <input type="text" name="code">
  </div>

  <div class="actions">
    <input type="submit" value="Verify">
  </div>
</form>

Verify the PIN

To verify the PIN submitted by the user you use the Nexmo library to make a Verify Check request. You pass in the request_id and the PIN entered by the user.

The Verify API response tells you if the the user entered the correct PIN. If status is 0, log the user in.

app.rb
# Finish Verification
# - finishes the verification
#   process, confirming the
#   user submitted code
#   against the verification ID
#
post '/finish_login' do
  # check the code with nexmo
  response = nexmo.check_verification(
    session[:verification_id],
    code: params[:code]
  )

  # any status that's not '0'
  # is an error
  if response['status'] == '0'
    # set the current user to
    # the number
    session[:user] = session[:number]

    redirect '/'
  else
    flash[:error] =
      response['error_text']

    redirect '/login'
  end
end

Conclusion

That's it. You can now log a user into your Web app using their phone number. To do this you collected their phone number, used Verify to send the user a PIN, collected this PIN from the user and validated it with Verify.

Previous   Next