Add Two-Factor Authentication to Android Apps with Nexmo’s Verify API

Published May 10, 2018 by Chris Guzman

Two-factor authentication (2FA) adds an extra layer of security for users that are accessing sensitive information. In this tutorial, we will cover how to implement two-factor authentication for a user’s phone number with Nexmo’s Verify API endpoints.

After reading the blog post about how to set up a server to use Nexmo Verify you’re now ready to set up an Android app to network with the server.

Prequisites

This app will have only two dependencies: Retrofit for making network calls and Moshi for serializing and deserializing JSON.

The app will need to do a few things. Store a requestId so that a verification request can be canceled or completed. As well as make a network call to three endpoints:

  1. Start a verification
  2. check a verification code
  3. cancel a verification request

To get started, I’ve set up a simple demo app with a login screen asking for the user’s email address, password, and phone number for two-factor authentication (2FA). Clone the following repo and navigate to the getting started branch:

Integrating with Proxy Server

In the blog post about how to set up a proxy server for the Verify API, we covered three endpoints:

  • Make a verification request.
  • Check a verification code.
  • Cancel a verification request.

So we’re going to need to have our app send POSTs to those three endpoints. To do this we’re going to use Retrofit and Moshi.

Making Network Requests

The build.gradle file should include the following dependencies. Retrofit for networking, Moshi for JSON parsing, and OkHttp for logging.

We can start using them to network with our proxy API.

First, we’ll set up an interface for the three endpoints our app needs to hit:

I won’t go over each of the models for the responses, but you can view them in more detail here. For the purpose of this tutorial I’ve matched the structure of the models to the JSON that Verify API expects.

Now that there is an interface of endpoints, we can write a VerifyUtil that will instantiate Retrofit and make the network requests:

I’ve made VerifyUtil a singleton that can be called from any Activity.

Let’s start by making some changes to our LoginActivity. The signInBtn already has an OnClickListener that calls start2FA() so we can add to that method.

Login Activity

Whenever someone clicks on the “Sign In” button, the app will send the phone number to the proxy API we’ve set up in the earlier blog. This app will ignore anything in the email or password screens since this app is a proof of concept.

If there is an error with the request, the proxy API will send a 400 response and we’ll handle it in the else block of the onResponse() callback. If there’s any other error, the proxy server will respond with a 500 and the app can handle the error in the onFailure() callback.

If the request is successful, the app will store the phone number the user sent and the responseId the proxy server returned, then the app will start the PhoneNumberConfirmActivity so that the user can enter their code. It’s important to store the phone number and request ID because those fields are needed to cancel or check the status of any verification request. And while a user may remember their phone number to cancel or check the status of a verification, they can’t be expected to remember a multi-character, randomly generated request ID string. So when the app makes a verification request, we’ll store the requestId in SharedPreferences to retrieve later in case the user backgrounds the app or the activity is restarted.

PhoneNumberConfirmActivity

Once a user enters the phone number and the server responds with a 200, the app will start the PhoneNumberConfirmActivity. I’ve already started the activity on the getting-started branch

The basic structure of the activity is already built. All that’s left is to use the requestId and phone number to confirm the PIN code or cancel the verification.

First, we’ll start with fetching the phone number and requestId from SharedPreferences. We’ll need the phone number and requestId to confirm the verification code or cancel the verification process.

Then once the user clicks on the “Confirm” button, the app needs to send the PIN code and the requestId to the proxy API. We can wire up the “Confirm” button’s OnClickListener to kick off that request.

The network request to confirm the PIN code is similar to the request made earlier to start the verification process. If all goes well the server will respond with a 200 OK and we can let the user know they are authenticated. If the server responds with a 400 or 500 then we can check the errorText of the response and alert the user of the issue either with a toast or by displaying the error in the verifyTxt TextView I’ve created.

There may be times when users want to cancel a verification request. This may be because they entered the wrong phone number, want to log in with another account, or just don’t want to verify themselves at this time. The app needs to handle this scenario so we can add a “Cancel” button to our activity and wire it up to send a cancellation network request. I’ve already added the “Cancel” button and added an OnClickListener with a callback of cancelRequest(), now we can just add the networking code to that method.

Wrapping It Up

Now we’ve implemented all of the endpoints necessary to follow a verification flow. If you’d like to see the finished product of this Android app, the source code is on the finished branch on GitHub.

Next Steps

If you’d like you can implement the rest of the endpoints in the Verify API. Note that this will require you to add more endpoints in the API proxy server.
You can also add additional endpoints to cover the Number Insights API. This will also require you to add more endpoints in the API proxy server.
There’s also an iOS version of this post. Read more from our developer advocate Eric Giannini.

Risks/Disclaimer

You may want to inspect the SSL certificate of the responses from your proxy API to ensure the client app isn’t subject to a MITM attack. For more details, visit the Android developer docs.

Leave a Reply

Your email address will not be published.