Laravel Custom Package for Enforcing Passage Passwordless Authentication in the Server(Backend)
Bringing all of Passage Passwordless Authentication server(backend) enforcement features to your Laravel application by just installing a package
Introduction
Hi, I would like to start by saying I appreciate 1Password and Hashnode for providing this opportunity for developers to learn, explore their creativity, and have an opportunity to earn in the process.
Bringing the power of passage to Laravel with a Laravel Package
This Laravel package was developed (Created) to automate/abstract the process of enforcing Passage passwordless authentication on the backend(Server side). Better said, this package was created to Enforce authentication in the backend(Server side) after authenticating with Passage passwordless authentication solution. Laravel is all about abstracting as much of the development process as they can from the developers, allowing them to concentrate/focus on implementing features and requirements of their Organization/Clients, leaving Laravel to sweat the details. Hence I felt the process of backend authentication enforcement of Passage authentication solution could be abstracted from the developer and provided as a Laravel package instead to allow Laravel developers to integrate more easily with Passage Passwordless Authentication solution. The creation(development) of this package was also fuelled by the fact that at the moment, there was no complete backend integration package for Laravel and PHP as a whole but other frameworks like Node and Python Flask already have SDKs(Software Development Kits). Laravel has a large community of developers who would appreciate Passage Passwordless Authentication system and would be more than happy to work with it and apply its features to their web applications.
This project is located here on GitHub.
A Brief Overview of Passage
Before we dive into the package development process properly, let us briefly get acquainted with Passage and how it can be integrated into your application/website. Passage is an authentication system that allows your users to securely sign into your website/web application without a password. Sounds great right? Too good to be true. Passage also eradicates some issues that traditional web applications face like forgotten passwords, email verification, and always entering passwords when logging in to a user account.
Passage Integration Process Proper
First of all, we head to https://passage.1password.com to create an app to get an app_id. This app_id would be used in creating a passage element in the front end of your web application/website. It is recommended to use Passage elements in your front end as shown below. Code Here (Although it is possible to use the raw passage js SDK to implement passwordless authentication according to your specific/custom needs). This creates an authentication modal(Login and Registration pages) for your users. After successful Registration or Login, Passage returns an authentication cookie to the client(browser) with the key "psg_auth_token". Backend Authentication Enforcement The cookie received from Passage by the client(browser) is actually a JWT token. This token needs to be parsed by your backend(server side) to get the authenticated user credentials and Enforce Passage passwordless authentication in the backend(server side) of your web application/website.
Click here to see the official Passage documentation.
Creating the Laravel package
This package was created following these steps
1 - A Get route ("/passwordless_login") is created to return a passwordless_auth view. The passage element would be placed in this view, after successful authentication, the user is redirected to a redirect route set in your passage application. This redirect route would be implemented in the second step
2 - A Get Redirect route is implemented, this is where the user would be redirected after successful authentication by Passage.
3 - A middleware is created and set to run before the user is allowed to access the redirect route. This middleware checks for a cookie with the key psg_auth_token. If this cookie is available, it parses the cookie value using a JWT parser. The JWT parser recommended by Passage for PHP applications is lcobucci/jwt. This JWT parser parses the psg_auth_token JWT token and extracts the claims. The sub claim contains a unique id for the authenticated user. This id can be used to get more details about the authenticated user like the user's email. See details here These user details and id are used to create a user in the database. In the case of login, the server checks to see if a user exists in the database with the parsed psg_auth_token sub claim(id). If the user exists, the server logs in that user. In this case, we are using Laravel so we get the user id with the sub id and use it to log in the authenticated user as shown below.
/* ---------------------------------------------- */
/* Getting JWT Claims from the parsed Passage JWT */
/* ---------------------------------------------- */
$passage_auth_token = $token->claims()->get('sub');
$user_key = User::where('psg_auth_token_sub', $passage_auth_token)->value('id');
/* -------------------------------------- */
/* Attempt to Login Passage JWT sub claim */
/* -------------------------------------- */
if (Auth::loginUsingId($user_key)){
$request->session()->regenerate();
return $next($request);
}
4 - A migration is created to modify the users table and add passage enabling changes to the table (to add a nullable "psg_auth_token_sub" column. The column is set to nullable as a user is expected to be able to exist without a psg_auth_token_sub(id). "The Legacy auth Users"). The psg_auth_token_sub column would be used to store the parsed psg_auth_token sub value. This package also allows existing Legacy authentication users to enable passwordless authentication on their account whenever they please providing flexibility in authentication for your web application/website. This can be done in the user's profile.
5 - A Get route "/enable_auth" is created to return an enable_passwordless_auth view page. A button is created to trigger the registration process. Once the button Enable Passwordless Auth is clicked, the view gets the authenticated user's email and uses it as an identifier to initiate a Passage Passwordless Authentication registration process for the authenticated user. If the registration is successful, the user is prompted to Login using the passwordless authentication modal to confirm enablement success.
Installing The Package
To install this package, you should follow the steps below
1 - You would need Composer installed on your system(PC). Composer is a dependency manager for PHP applications. (More like NPM(Node Package Manager) for PHP).
2 - You would need to install a fresh Laravel project. Visit https://laravel.com/docs to see details on how to create a new Laravel project.
3 - Run the following command below composer require package_name
4 - You would need to create an env variable PASSAGE_APP_ID. The value of this variable would be a string (your Passage App_Id gotten from your Passage application). This value would be used to create the passage element in the passwordless_login view and perform other operations in the server like getting the authenticated user's details.
5 - In your Laravel project, update your composer.json file and include the following array somewhere in the object:
"repositories": [
{
"type": "vcs",
"url": "https://github.com/Williamsonwuesi/Onepasswordpassage"
}
]
5 - In your command prompt, navigate to your project directory and run composer require Williamsonwuesi/Onepasswordpassage
6 - Now, open config/app.php file and scroll down to the providers array. In that array, you would find a section for the package service providers. Add the code below in that section:
/*
* Package Service Providers...
*/
Williamsonwuesi\Onepasswordpassage\Providers\OnepasswordpassageProvider::class,
7 - In your command prompt run the php artisan migrate
command to add passage enabling modifications to the user's table as stated above.
8 - Create a login page and create a link leading to the passwordless login route as an alternative to your Legacy login method. You should create a Legacy register route as well, this route would return the legacy registration page so the user can still sign up the traditional way if they please. That way you wouldn't have to enforce it on your users to use the passwordless authentication modal. They can switch to it and back whenever they please.
Now a user can register, log in and enable passage functionality on their user account whenever they like. The authentication system with the package is built to automatically sync itself. You should place a link to the enable_passkey route in the user profile. This would allow your legacy authentication users to enable Passage passwordless authentication functionality whenever they please. The whole authentication system is designed to automatically sync itself allowing your users to use whatever authentication modal they choose(Passage passwordless authentication modal or Your Legacy authentication modal).
Conclusion
I hope to expand this package, the aim is to bring all of Passage and 1Password features to Laravel and the Laravel community.
Once again I want to say a very big Thank You to 1Password and Hashnode for this golden opportunity to explore my creativity and learn. I learned a lot in the process.
Thank you for your time. I hope you enjoyed this article.
Until next time. Bye for now.๐