What Are We Building?
Silent Authentication removes the need for a One-Time Password (OTP) when using two-factor authentication by sending a device phone number and checking its authenticity (for now, if you want to know "how," the easy answer is "magic" and the actual answer is in this breakdown of how Network APIs work).
So, our demo app will use Laravel to attempt a login for a real-world user of your app using Vonage's Silent Authentication in Verify. If the phone number is not in a supported territory or not on a supported network, it will default back to SMS.
Laravel's Rapid Prototyping
It's the speed at which Laravel code is written that makes the framework an ideal choice for showing how this auth system works in practice. It's no surprise that Laravel, as a company, have just announced $57m in Series A funding at the same time that Laravel's Cloud SaaS profile was announced to be launching.
A big headache with Web Application Developer Frameworks in all languages and flavors is what is included as a boilerplate. Node, for instance, has thousands of frameworks and libraries—and because of this, the de facto methodology for building an app is to pick every single element of your application and wire it together. While many Node developers will nod that that is the way we do it, there are some (disclaimer: me) who are not used to this way of working because we have things like...
Laravel Breeze
...which gives you everything you need to get started with an auth system. Here are some features:
Migrations for the users' table to run for the database
Templates for registering a new user on your app, which start off as an open route, but you can later guard if necessary
A forgot password trigger system pre-built for you
Login forms pre-built
A host of CLI options on how you want this front-end to work— Blade templates with Alpine.js, Livewire, or a SPA such as Vue.js or React
The purpose of this article isn't to show you how to install this or to explain the parts it wires together but to customize what Breeze does. One argument against this type of rapid prototyping is: "But what comes out is all in Laravel's styling." Sure, it is. But it's the boilerplate that matters: to make this code your own, the only thing stopping you is changing how the controllers work and what templates/routes they're outputting. Aside from that, if you really hate Tailwind, you can ditch that in about 30 seconds.
So, given that all of this comes out of the box, why not integrate the Silent Authentication API into the login mechanism? And that, reader, is exactly what I have done.
The Codebase
Here's what you'll need to test this out:
PHP 8.1 or higher (please, people, make sure you are up to date!)
Docker & docker-compose
Composer
A localhost proxy, such as ngrok or Expose
To get up and running with the code, clone the repository:
$ git clone https://github.com/Vonage-Community/sample-verify2_sms_silent_auth-laravel
And then install the project's dependencies:
$ composer install
You will need an environment file, so copy the example provided (using the command that corresponds to your Operating System), which Sail will use to create a new SQLite database file.
$ cp .env.example .env // Unix-like OS
$ copy .env.example .env // Windows
The next installation steps require your application to be booted up in Docker—this application was built using Laravel Sail, so providing your dependency installation has worked, you will be able to pull the app's containers and run them:
$ ./vendor/bin/sail up -d
The -d switch runs Docker as a daemon, rather than tracking the logs. You might notice that the environment variables file uses SQLite as the database—when writing this app I originally used MySQL, but for demo purposes SQLite is a perfectly acceptable replacement (plus, navigating the database with an IDE like VSCode or PHPStorm is more straightforward).
Using Sail's binary, we can now finish off installing the database and frontend assets:
$ ./vendor/bin/sail artisan migrate
$ ./vendor/bin/sail artisan db:seed
$ ./vendor/bin/sail yarn install
The app requires a front-end assets server or build. The quickest way here is to run a frontend dev server:
$ ./vendor/bin/sail yarn run dev
This will run Vite as a process in your terminal window, so you will need to open a new tab or terminal window.
Finally, you'll need to generate an application key:
$ ./vendor/bin/sail artisan key
The application requires a valid Vonage developer account and a JWT to make API calls, which are created by the Vonage PHP SDK automatically using your private key downloaded from the Applications Dashboard and your Application's unique App ID. Once you have these, download the private key into your app's root directory, add ./private.key as the environment variable VONAGE_PRIVATE_KEY_PATH, and App ID as VONAGE_APPLICATION_ID in your .env file. You may need to restart Sail once these variables are set.
How To Use It
With Sail booted up, you should get a splash screen when accessing localhost:80.
We're up! Now, it's time to register. Head to the top right-hand corner and click Register. You'll see most of Laravel Breeze's boilerplate, with the exception of an additional "Phone Number" field. This part is key—it will store your number in the database and then attempt to use Silent Authentication to complete it.
Access From The Outside World
One thing you might have noticed is that I haven't explained what Silent Authentication is. Well, this article is about the demo application, so if you want to read up more on it, check out this article from our blog.
The TLDR; here is: you will only be able to log in with a cellular device on a cellular connection. This means we're going to need to expose our app to the outside world. To do this, I'd recommend either using ngrok or perhaps a more logical choice might be Expose which usesReactPHP and comes from the Laravel community. Once you have an external URL, it's time to access it from your device.
Silent Authentication Workflow
So, what happens when you try to log in? Well, firstly the code checks if you are logging in for the first time, or if your last login was over 4 days ago. If those conditions are met, the Two-Factor Authentication (2FA) mechanism will automatically fire.
When clicking the button to start the authentication, the application will automatically determine if you can complete the process via Silent Auth, and if you cannot, then it will default back to SMS:
So, to get to the dashboard, you will either be automatically logged in by clicking the Silent Auth start button, or you can log in by entering the code sent to your device. For the Silent Auth request to work, you must have your WiFi connection disabled and be on cellular. This is because Vonage is, under the hood, validating the device and location.
What Did I Do?
Essentially, I needed to hijack the existing Breeze authorization flow. So, I created a new Middleware—VonageSilentAuthMiddleware—which runs on the login route. This middleware is run after a successful login with a password, so it can then only complete the auth flow if either the Silent Authentication controller passes or the SMS controller passes. Here is some of that logic in the Middleware:
// is this the first time logging in?
if (empty($user->last_login)) {
$request->session()->put('email', $user->email);
$request->session()->put('phone_number', $user->phone_number);
Auth::logout();
return redirect()->route('silent');
}
// was the last login over 4 days ago?
$lastLogin = Carbon::make($user->last_login);
if ($lastLogin->diffInDays(Carbon::now()) > 4) {
$request->session()->put('email', $user->email);
$request->session()->put('phone_number', $user->phone_number);
Auth::logout();
return redirect()->route('silent');
}
One thing you'll notice is that the user's email and phone number are put into the session. This tells the other controllers after the redirect which user to pull out of the users table to authorize once an auth mechanism is completed in a controller.
How Does The Silent Authentication Code Complete?
This is a fairly complex part of the code to explain. The tradeoff for Silent Authentication is that it is an almost frictionless experience for the end user but more complex for developers to integrate. This Laravel application essentially follows the same process as the Express.js web tutorial but with a working dashboard and user table. For a more detailed explanation of how the frontend code works to resolve the Silent Authentication request, you can find it in the tutorial.
Conclusion
You might notice that this is web-based Silent Authentication. There are some things to consider here:
The best Silent Authentication experience revolves around the iOS and Android native SDKs for mobile apps. This is because these SDKs can force the Silent Authentication request through the device's cellular connection.
However, although there are no web APIs available in the browser to do this sort of functionality, we have a fallback option as shown in this demo. Because of this: why not have Silent Auth as an option anyway, and if that fails, use a different channel to complete 2FA?
Silent Auth through our Verify API is one offering in this new era of Network APIs. For more information, check out other new APIs we have released, such as the SIM Swap API. For more information on what we offer or how these APIs work, check out our Developer Community Slack or follow us on X.