Enhancing Security with Two-Factor Authentication in Laravel using Inertia
Time to read: 7 minutes
Enhancing Security with Two-Factor Authentication in Laravel Using Inertia
Two-factor Authentication (2FA) significantly boosts the security of any application by introducing an additional layer of verification. This ensures that only authorized users with proper authentication can access the application.
In this tutorial, we will guide you through the process of implementing a Two-Factor Authentication system in a Laravel and Vue.js application, utilizing Inertia.js.
To achieve this, we'll cover the following steps:
Set up authentication in a Laravel application using Laravel Breeze, Inertia.js, and Vue.js.
Integrate a One-Time Password (OTP) system into our authentication process using the Twilio Verify API.
Develop middleware to restrict access to the dashboard until a specified phone number has been successfully verified.
With that said, let's dive into the implementation.
Prerequisites
To follow along effectively with this tutorial, the following technologies are required:
PHP 8.2 (ideally 8.3)
Composer installed globally
A Twilio account. Click here to create a free account if you don't already have one.
Access to a MySQL database, whether locally or through a hosted service
Prior experience with Laravel would be ideal, but it is not essential
Set up the project
The first step is to create a fresh Laravel application with Composer and change into the new project's directory using the commands below.
After creating the application, the next step is to create a database and establish a connection between the application and database. Add the following to your .env file to establish a database connection.
When that is done, serve the application and view it in your browser to be sure everything works. Let's do that using the command below.
The application will be available on http://127.0.0.1:8000/, or another port if the aforementioned is already in use by another application. Your screen should look just like the image below.
Add authentication with Laravel Breeze
Let's implement an Inertia.Js authentication flow using Laravel Breeze. To get started, install Laravel Breeze using the command below in a new terminal tab or window.
Now, run the following commands to scaffold the authentication layer.
When running the breeze:install
Artisan command, you will be prompted to choose between the Vue or React frontend stacks. Please choose "Vue with Inertia".
Subsequently, the Breeze installer will ask whether you would like "Inertia SSR" or "TypeScript" support. For this tutorial, select the "Inertia SSR" option.
Now, visit the '/register' route and register as a new user to ensure that the registration feature works.
Install the Twilio PHP Helper Library
Now we have authentication, let's proceed to add 2FA using the Twilio Verify API. First, we need to install the Twilio PHP Helper Library using the Composer command below, in a new terminal tab or session.
Once the installation process is complete, for better organization and easy access, let's insert our Twilio details into our .env file. Simply add these lines to the end of your .env file:
To set up the Twilio helper library in our application, grab your Account SID, Auth Token from the Account Info section of the Twilio Console. Then, replace <<TWILIO_ACCOUNT_SID>>
, and <<TWILIO_AUTH_TOKEN>>
in the .env file respectively, with these credentials.
As for <<TWILIO_VERIFICATION_SERVICE_TOKEN>>
, we will generate this from our Twilio Console dashboard in the next section.
Create a Verification Service
Before sending out verification codes using the Twilio Verify API, The first step is to create a verification service. A verification service is a collection of basic settings used to create and confirm verifications. This includes things like the name displayed in verification messages (except in countries with brand restrictions) and the length of the verification code.
We can create a verification service via the Twilio Verify API or the Twilio Console. For this tutorial, we will use the Twilio Console for simplicity.
Once you log into your dashboard, navigate to Explore Products > Account security > Verify. Click the Create New button. Your screen should look like the one below. Fill out the form and click Continue, then click Continue again to enable Fraud Guard.
Then, grab the Service SID and, in your .env file, replace <<TWILIO_VERIFICATION_SERVICE_TOKEN>>
with the value.
Implement Two-Factor Authentication
Now that our Twilio Verification Service is ready, let's modify the current authentication to add Two-Factor Authentication to it. First, we need to add a phone number section to our Register.vue file, and to modify the users
table migration file to add a column for storing the user's phone number.
To do that, open resources/js/Pages/Auth/Register.vue and modify the content of the file to match the code below.
We added a form field to the existing form to accept the user's phone number during registration. Let's now add code for validating and saving this value in the database.
Open app/Http/Controllers/Auth/RegisterUserController.php and modify the file, like so.
After that, modify the $fillable
array in app/Models/User.php to match the following.
We also need to add a column in the database for the user's phone number. Create a migration to update the user table using the command below.
Open the new migration file (located in database/migrations and ending with _add_phone_number_to_user_table.php) and modify the contents with the code below.
Run the migration after saving the file using the following command.
Now, your register page (http://localhost:8000/register) should have a field for a phone number like the image below, and your users should be able to register with their phone number.
Add a phone verification Trait
Let's implement the logic for sending verification tokens to the user's phone and checking the verification token. We will create a Trait for this to keep things simple and maintainable. In app/Http, create a new folder named Traits; in that folder, create a new file named TwoFactorAuthenticationTrait.php. Add the following code to the file.
Our sendVerificationToken()
method sends the verification code to the provided phone number. After sending the code, it updates the status of phoneVerified
in the session. This will be very useful when we create our middleware later. After this, it redirects to the verification page. Let's create that next.
Add the phone verification file screen
Let's create a new controller for the 2FA logic using the command below.
Then, update our newly created controller to match the following.
In the controller above, we have two methods, index()
and verifyCode()
. The index()
method returns the Vue.js file for the verifying OTP page. We will create that file next. The verifyCode()
method uses the checkVerificationToken()
method from our TwoFactorAuthenticationTrait
to verify the code entered by the user. This method is called when the user submits the verification form. More on that shortly.
For now, let's create the verification page. In resources/js/Pages/Auth, create a new file named TwoFactorAuthentication.vue. Then, add the following to the created page.
Add Flash Message support
Let's add a little configuration here to enable the form above to display a flash message once the OTP is sent. Inertia.js flash message configuration is done in app/Http/Middleware/HandleInertiaRequests file. Replace the share()
method in that file with the code below.
The next thing is to create route links for displaying this page and verifying the code. To do that, add the following to the routes/web.php file.
Add the ability to send an OTP
To send our OTP and display the verification page, we need to call the sendVerificationToken()
method in our TwoFactorAuthenticationTrait.php file which we created earlier.
It is common to have the OTP page display right after a user logs in with email. To follow that convention, we need to call the sendVerificationToken()
method right after a user logs in. Our login logic can be found in app/Http/Controllers/AuthenticatedSessionController.php file. Let's modify the file's content like so.
At this point, a user will be redirected to the verification page right after login, receive an OTP on their registered phone number, and be able to verify the code using the verification form. The OTP verification page should look like the image below.
Add security middleware
Our application is almost done. Let's add a middleware to prevent access to other pages without entering the OTP code. This will redirect a user back to the verification page as long as they are not verified.
To achieve this, we will use the Session helper function in Laravel. Let's create our middleware using the command below.
Then, replace the content of the new file (app/Http/Middleware/TwoFactorAuthenticationMiddleware.php) with the code below.
Here, we simply check the session value for phoneVerified
. If it's set to pending
, it means the user's phone has not been verified and it should redirect the user to the phone.verify
route. The session
value is either pending or approved. This value is then retrieved from the Twilio Verify API response. The session
is updated in the TwoFactorAuthenticationTrait.php file as we mentioned earlier.
Register Middleware
The next step is to register the middleware in our application Kernel.php file. In app/Http/Kernel.php, add the code below to the protected $middlewareAliases
array.
Add middleware to routes
One last thing we need to do is to add this middleware to every relevant route in the application. Replace the content of routes/web.php with the code below.
Test Our Application
Now we can test the application. When a user logs in, the user will be redirected to the OTP verification page. The OTP verification page should look like the image below.
Once the correct code is entered, the user will be redirected to the dashboard. If a wrong code is entered, the middleware prevents the user from accessing the dashboard. The short video below also demonstrates how the application works.
That's how to enhance Laravel security with Two-Factor Authentication using Inertia.js
In this tutorial, we walked through the process of implementing Two-Factor verification into a Laravel application using Laravel Breeze for the authentication scaffolding and the Twilio Verify API.
We walked through the process by:
Scaffolding authentication in a Laravel application using Laravel Breeze, Inertial.js, and Vue.Js
Inject an OTP system into our authentication flow using Twilio Verify API
Create a middleware to restrict access to the dashboard until a given phone number is verified.
The importance of Two-factor verification cannot be over-emphasized. This article can be helpful even if you have an authentication system implemented from scratch. I encourage you to experiment with the code as much as you can.
You can find the complete code on GitHub.
Moses Anumadu is a software developer and online educator who loves to write clean, maintainable code. I create technical content for technical audiences. You can find me here.
Related Posts
Related Resources
Twilio Docs
From APIs to SDKs to sample apps
API reference documentation, SDKs, helper libraries, quickstarts, and tutorials for your language and platform.
Resource Center
The latest ebooks, industry reports, and webinars
Learn from customer engagement experts to improve your own communication.
Ahoy
Twilio's developer community hub
Best practices, code samples, and inspiration to build communications and digital engagement experiences.