How to Create a Phone Number-Based Authentication Flow (Part 2)

In the first part of the series, we saw how to implement the backend of our architecture. In this second part, we'll walk through the implementation of a mobile application that leverages the Number Verification API to verify end-users. Using a phone number as a second-factor authentication (2FA) method eliminates the need for traditional SMS-based verification, providing a secure and better user experience.

Prerequisites

To follow this tutorial, you’ll need the following:

Vonage API Account

To complete this tutorial, you will need a Vonage API account. If you don’t have one already, you can sign up today and start building with free credit. Once you have an account, you can find your API Key and API Secret at the top of the Vonage API Dashboard.

Other requirements include:

Architecture

Let’s quickly recap what we implemented in the first part of the series on the backend side. The backend implements the following endpoints:

  • login: Initiates user authentication via a POST request from the mobile app, calling the Network Enablement API to start the flow. The method returns the authorization URL that must be sent from the mobile device.

  • callback: Completes the authentication flow via a callback from the authentication server, using the Number Verification API to validate the user. The method returns the verification result to the mobile application.

Sequence diagram that shows the API calls to integrate Number Verification APINumber Verification API call flow

Thus, the mobile application will implement the requests to those endpoints while providing a user interface to facilitate interaction and display the results of the end-user verification process.

UI Implementation

Let’s start by implementing the user interface to verify the user. The application contains three main elements:

  • A TextField will allow users to input their phone numbers. By default, it shows a placeholder value corresponding to a phone number from the Virtual Operator that users can modify.

  • A Button labeled "Login" triggers the login and verification flow when clicked. It initiates a coroutine to handle the network requests and update the UI accordingly. This button simulates the process of logging in to the system.

  • After the verification process, a Text message will be displayed to indicate whether the authentication was successful or failed. This message appears below the button in bold text. We will use this text component to display error messages when needed.

The following screenshot shows how the UI will look like:

The image shows an screenshot of the mobile application's UIMobile app UI

Initialization of the Authentication Flow

The sendLogin function sends a login request to the backend server. Here's a detailed description of what it does:

  1. Sends the user's phone number to the login backend endpoint.

  2. Awaits a server response, typically including a verification URL or other relevant details.

  3. Returns the result of the HTTP request, encapsulated in a Result type for safe error handling.

suspend fun sendLogin(url: String, phoneNumber: String): Result<String> {
    val client = OkHttpClient()

    val jsonBody = """{ "phone": "$phoneNumber" }""".trimIndent()
    val requestBody = jsonBody.toRequestBody("application/json".toMediaType())

    val request = Request.Builder()
        .url(url)
        .post(requestBody)
        .header("Content-Type", "application/json")
        .build()

    return withContext(Dispatchers.IO) {
        try {
            val response = client.newCall(request).execute()
            if (response.isSuccessful) {
                Result.success(response.body?.string().orEmpty())
            } else {
                Result.failure(IOException("HTTP error: ${response.code}"))
            }
        } catch (e: IOException) {
            Result.failure(e)
        }
    }
}

Authorization Request

The mobile application must send an authorization request to the authentication server, verifying that the request comes from the same phone number provided in the initial sendLogin request.

The sendAuthRequest function sends the authentication request using the Vonage Client SDK to bypass WiFi connecting and use mobile data instead. This authorization request aims to validate whether the user's phone number is verified by communicating with the mobile operator.

suspend fun sendAuthRequest(url: String): Result<Boolean> {
    val params = VGCellularRequestParameters(
        url = url,
        headers = emptyMap(),
        queryParameters = emptyMap(),
        maxRedirectCount = 15
    )

    return withContext(Dispatchers.IO) {
        val response = VGCellularRequestClient.getInstance()
            .startCellularGetRequest(params, true)

        val status = response.optInt("http_status")
        val isVerified = response.optJSONObject("response_body")
            ?.optString("devicePhoneNumberVerified", "false")?.toBoolean() ?: false

        if (status == 200 && isVerified) {
            Result.success(true)
        } else {
            Result.failure(IOException("Verification failed"))
        }
    }
}

Source Code

The complete source code for this tutorial can be found in this GitHub repository.

Conclusions

In this second part of the series, we focused on the mobile application, learning how to interact with a backend that integrates the Number Verification API to deliver a secure two-factor authentication experience.

Across this blog series, we have learned how to implement a phone number-based authentication flow to provide a secure, user-friendly alternative to traditional SMS-based verification methods. The key takeaways from this 2FA implementation include:

  • Using the Number Verification API reduces the dependency on potentially vulnerable SMS channels, reducing the risk of fraud and interception.

  • Combining the Number Verification API and other 2FA methods would improve the user experience as the end-user verification process could be done behind the scenes.

Happy hacking!

Get in Touch

Do you have questions? We are here to help! Join us on the Vonage Developer Community Slack or message us on X, and we will respond to you. 

Alvaro NavarroSenior Developer Advocate

Alvaro is a developer advocate at Vonage, focusing on Network APIs. Passionate about Developer Experience, APIs, and Open Source. Outside work, you can often find him exploring comic shops, attending sci-fi and horror festivals or crafting stuff with those renowned tiny plastic building blocks.

Ready to start building?

Experience seamless connectivity, real-time messaging, and crystal-clear voice and video calls-all at your fingertips.

Subscribe to Our Developer Newsletter

Subscribe to our monthly newsletter to receive our latest updates on tutorials, releases, and events. No spam.