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.
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:
- Create a basic Web app - create a basic Web app that the user logs into
- Collect the user's phone number - add a form to collect the user's phone number
- Send the verification request - create a verification request and send a PIN to the user's phone number
- Collect the PIN - add a form to collect the PIN from the user
- Verify the PIN - verify that the PIN the user provided is valid and log him or her in
To work through this tutorial you need:
- A Nexmo account
- To download the tutorial from https://github.com/Nexmo/ruby-passwordless-login
- Follow the installation instructions in the tutorial readme
Create a basic Web app
# web server and flash messages require 'sinatra' require 'rack-flash' use Rack::Flash
# 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.
<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:
# 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.
<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:
Set your API key and secret in order to initialize the
# 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:
# 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:
# Code Verify # - shows the user a form to # fill in the code they # received via text message # get '/verify' do erb :verify end
<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.
# 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
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.