Two-factor authentication (2FA) adds an extra layer of security for users that are accessing sensitive information.
While there are multiple modes of authenticating with something you know, are, or have, we will focus exclusively on the last. 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 iOS app to network with the server.
The app will need to do a few things. Store a request_id
as a responseId
so that a verification request can be canceled or completed. As well as make a network call to three endpoints:
Start a verification.
Check a verification code.
Cancel a verification request.
Nexmo Setup
After reading the blog post about how to set up a server to use Nexmo Verify you're now ready to set up an iOS app to network with the server.
Environment Setup
Download the starter project, a single view application:
git clone https://github.com/nexmo-community/verify-ios-demo/
Add a CocoaPods file to its root directory, and install the pod after modifying its podfile to include the following:
pod 'Alamofire'
Make sure to have an iPhone with a SIM card handy.
To correctly configure the environment we need to simulate a server as in the Glitch server app. To configure, go to the .env file and set the values as required for
API_KEY
&API_SECRET
Review the UI
With the setup out of the way let's review the user interface for verification and confirmation.
A CocoaTouch file called
VerificationViewController
that is a subclass of UIViewController; this class is assigned to a scene inMain.storyboard
so that it takesVerificationViewController
as its custom class.Three TextFields in
VerificationViewController
, outlets calledinputEmailAddress
,inputPassword
,inputTelephoneNumber
respectively.A Button in
VerificationViewController
calledloginBtn
.A Button in
VerificationViewController
, an action calledcancelVerification
.A segue called
authenticateWith2FACode
, connectingVerificationViewController
toConfirmationViewController
.A CocoaTouch file called
ConfirmationViewController
that is a subclass of UIViewController; assigned to a scene inMain.storyboard
so that it takesConfirmationViewController
as its custom class.A TextField,
ConfirmationViewController
,inputEmailAddress
.A Button in
VerificationViewController
, an action calledcancelVerification
.
Note: You are free to set the constraints for the TextFields, Buttons, or Labels however you would like!
Setting Up the Glitch Server
Let's break down what lies ahead. Nexmo's API for verification is essentially two links. The first one is https://api.nexmo.com/verify/json. This link verifies the user's telephone number. The second link is https://api.nexmo.com/verify/check/json. This link verifies that the user is in possession of the device by sending an SMS with a PIN.
In this tutorial, however, we do not directly hit either of these API endpoints. We use an SDK called Alamofire
to communicate through an intermediary Glitch server.
Steps for Setting Up Server
The first step to setting up the Glitch server is to remix the Glitch server for your own deployment. On the site there is a remix button.
Programming the UI
With the Glitch server set up, the next step is to program the app's UI to request or respond to requests with the server.
At the top of
VerificationViewController
include the lineimport Alamofire
.Within the scope of
VerificationViewController
's class declaration add the linevar responseId = String()
. We are initializing an empty string where we will hold a reference to ourresponseId
.
Note: You may want to use NSUserDefaults or one of the many different classes for local storage. Since it is a matter of preference we leave it to you as a developer to decide how to store the responseId
.
In the
@IBAction
forverifyTelephoneNumber
add the following line:self.verifyViaAPI()
, which is a function we will program to hit the first link.Create a function called
verifyViaAPI()
with the following code:
func requestVerificationWithAPI() {
//Sending SMS
let param = ["telephoneNumber": telephoneTextField.text]
Alamofire.request("https://nexmo-verify.glitch.me/request", parameters: param as Any).responseJSON { response in
print("--- Sent SMS API ----")
print("Response: \(response)")
if let json = response.result.value as? [String:AnyObject] {
self.responseId = json["request_id"] as! String
self.performSegue(withIdentifier: "authenticateWith2FA", sender: self)
}
}
}
When the verification request is sent, our next step is to segue from the one view controller to the next. During the transition, we will pass our responseId
so that our Glitch server knows with which app it is dealing. Here is how to program prepare(for:sender:)
:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let confirmationVC = segue.destination as! ConfirmationViewController
confirmationVC.responseId = responseId
}
As we pass the responseId
from one view controller to the next, we land on the ConfirmationViewController
where we confirm whether the user requesting authentication has the device associated with their number.
Second Link : SMS
In the
@IBAction
forverifyPin
add the lineself.verifyPinViaAPI()
, which is a function we will program to hit the second link.Create a function called
verifyPinViaAPI()
with the following code:
func verifyPinViaAPI() {
guard let requestId = requestId,
let code = codeTextField.text else { return }
let url = "https://nexmo-verify.glitch.me/check"
let parameters = ["request_id": requestId,
"code": code]
guard let request = URLRequestManager.getRequest(url, parameters: parameters) else { return }
Alamofire.request(request).responseJSON { [weak self] response in
print("--- Verify SMS API ----")
print("Response: \(response)")
if let json = response.result.value as? [String:AnyObject],
let status = json["status"] as? String {
// if status is zero, then success; if not something
// went wrong
if Int(status) == 0 {
DispatchQueue.main.async {
self?.dismiss(animated: true)
}
}
}
}
}
The code is similar to the first request. In this code snippet, we parse the response for a successful verification. If the status returned in the response is zero, the user is authenticated. If not, then the user must start all over again.
Cancellation
Last but not least is cancellation. Cancellation is programmed in a similar manner:
func cancelRequest() {
guard let requestId = requestId else { return }
let parameters = ["request_id": requestId]
let url = "https://nexmo-verify.glitch.me/cancel"
guard let request = URLRequestManager.getRequest(url, parameters: parameters) else { return }
Alamofire.request(request).responseJSON { response in
print("--- Cancel Request API ----")
print("Response: \(response)")
if let json = response.result.value as? [String:AnyObject],
let status = json["status"] as? String {
if Int(status) == 0 {
print("Request Cancelled Successfully")
}
}
}
}
What's Been Achieved and Learned?
You now have a verified number and double checked that your user is in possession of the device's number—and you did all of this with Nexmo's API!
With this implementation, you only know from the client side that the number is verified. In a real world app, you would need to tell your backend that the number is verified. You could accomplish that in two ways, by calling that update on the success flow from either the client or your own callbacks.
If you'd like to see the final product, you can download the completed project here.
What's Next?
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 Android version of this post. Read more from our developer advocate Chris Guzman.
Eric Giannini was the iOS developer advocate at Nexmo. He is really passionate about both Objective-C and Swift, especially the latter. Eric blogs often about this, that or the other iOS thing, hacking apps, building SDKs, or rapidly prototyping. He also meets with iOS developers or other strongly typed Swift types at conferences, Meetups, and other variadic functions.