Set Up Passwordless Login in Laravel
In the last article, we discussed the difference between a passwordless login system and a password login system. In this article, you will learn to develop a passwordless login system in Laravel.
What is Passwordless login?
We discussed in detail the passwordless login system in another article. But in brief, passwordless login allows users to log in to an app without entering a password. To know more about it and make it more secure, please head over to this article.
Required packages
Generate Passwordless login link with default configurations
Laravel Passwordless Login is a package built by grosv for easily setting up passwordless authentication in any Laravel app. It provides a LoginUrl
class and PasswordlessLogin
trait to be used for generating a unique URL for logging in to a given account.
First of all, cd into your laravel app and require the package using composer.
composer require grosv/laravel-passwordless-login
Once the package is installed, we’ll need to get the email of the user. To achieve this, we can create a route asking for the user’s email id.
In this case, I will create /login/magiclink
to ask the user for their email id.
Route::prefix('login')->group(function() {
Route::get('magiclink', 'MagiclinkController@getEmail')->name('login.magiclink');
});
The route will hit the MagiclinkController
and getEmail
action. The getEmail
function will return a view where we can ask the user to enter his email.
// get user email
public function getEmail() {
return view('Magiclink.email');
}
Finally, prepare a view at resources/view/Magiclink/email.blade.php
.
@extends('layouts.login')
@section('content')
@if (isset($_GET['send']))
<div class="alert alert-success">
@if ($_GET['send'] == 'success')
Magiclink was sent!
@endif
</div>
@endif
<h4>Get Magic Link for passwordless login</h4>
<h6 class="font-weight-light">Enter your registered email</h6>
<form class="pt-3" action="{{ route('login.send.magiclink') }}" method="post">
@csrf
<div class="form-group">
<label for="exampleInputEmail">Email</label>
<div class="input-group">
<div class="input-group-prepend bg-transparent">
<span class="input-group-text bg-transparent border-right-0">
<i class="mdi mdi-email text-primary"></i>
</span>
</div>
<input type="email" class="form-control form-control-lg border-left-0" id="exampleInputEmail" placeholder="Email" name="email" required>
</div>
</div>
<div class="my-3">
<button type="submit" class="btn btn-block btn-primary btn-lg font-weight-medium auth-form-btn" href="">SUBMIT</button>
</div>
<div class="text-center mt-4 font-weight-light">
Don't have an account? <a href="register-2.html" class="text-primary">Create</a>
</div>
</form>
@endsection
Next, we will set up the email handling and link generating route. This is the route where we will send the above form with the email.
The route is going to be /login/send/magiclink
.
Route::prefix('login')->group(function() {
Route::post('send/magiclink', 'MagiclinkController@sendEmail')->name('login.send.magiclink');
});
This post type route will be handled in MagiclinkController
and sendEmail
function. Since it is a post route, we will need to send a csrf token in the form; otherwise, it’ll generate a 419 error.
First of all, it is important to validate the data entered by the user. Ensure that the user did not send the email field empty and the entered field contains an actual email by using the validate method.
Import User
and LoginUrl
class.
use App\User;
use Grosv\LaravelPasswordlessLogin\LoginUrl;
Secondly, fetch the user using the email id provided by the user.
$user = User::where('email', '=', $request->email)->first();
LoginUrl
Class accepts the user object we have just created.
$generator = new LoginUrl($user);
Finally, generate the URL by calling the generate function on the generator instance.
$url = $generator->generate();
That’s it. This will create a unique URL for logging in to the user account. We can send this URL to the email id using the Mail class.
http://127.0.0.1:8000/login/magiclink?expires=1598865132&uid=1&user_type=app-user&signature=b9a86dc652bb3e4882b6dc8de4afba4c9150bcfd68eaeb63a58cbf94aa827606
public function send_email(Request $request) {
$request->validate([
'email' => 'required|email'
]);
$user = User::where('email', $request->email)->first();
if($user != null && $user->count() != 0) {
$generator = new LoginUrl($user);
$url = $generator->generate();
Mail::to($user)->queue(new Magiclink($url));
return redirect("/login/magiclink?send=success");
}
return "No user found with email <strong>$request->email</strong>.";
}
By default, the URL is valid for 30 minutes and will redirect the user to the application’s root ‘/’ after successful login. We can alter the redirect route by calling the setRedirectUrl method on the instance.
$generator->setRedirectUrl('/dashboard');
This is the basic functionality. If you want a little more from this package, use the trait provided by the class. The trait PasswordlessLogin
allows setting up different configurations such as the user model, guard, login route, URL expiration time, and even set the URL to be used only once.
To use PasswordlessLogin
trait, open the User model, or any other model such as Admin or Contributor, etc.
Import the PasswordlessLogin
trait in the model.
use Grosv\LaravelPasswordlessLogin\Traits\PasswordlessLogin;
Use the trait in the User
class –
use PasswordlessLogin;
And finally, set the configurations by using the following functions in the model –
public function getGuardNameAttribute(): string
{
return 'web';
}
public function shouldRememberLoginAttribute(): bool
{
return true;
}
public function getLoginRouteExpiresInAttribute(): int
{
return 10;
}
public function getRedirectUrlAttribute(): string
{
return '/dashboard';
}
Once the functions are in place, we can use the createPasswordlessLoginLink() function on the user instance for which we want to create the login link.
We are now ready to use trait to create passwordless login link.
Using PasswordlessLogin Trait
Import the PasswordlessLogin trait in the controller.
use Grosv\LaravelPasswordlessLogin\Traits\PasswordlessLogin;
Fetch the user from the database –
$user = User::where('email', '=', $request->email)->first();
Call createPasswordlessLoginLink method on the user –
$url = $user->createPasswordlessLoginLink();
It will generate a unique URL with the custom configurations that we set in the User model. In the same way, we can use the PasswordlessLogin
trait in any other user Model such as Admin with different configurations.
Setting configurations in .env file
If you do not have multiple user models, you can use LoginUrl
class and modify default configurations by setting the following configuration in .env file.
LPL_USER_MODEL=App\User
LPL_REMEMBER_LOGIN=false
LPL_LOGIN_ROUTE=/login/magiclink
LPL_LOGIN_ROUTE_NAME=login.magiclink
LPL_LOGIN_ROUTE_EXPIRES=10
LPL_REDIRECT_ON_LOGIN=/dashboard
LPL_USER_GUARD=web
LPL_USE_ONCE=true
LPL_INVALID_SIGNATURE_MESSAGE="Expired or Invalid Link"
Summary
Passwordless login is a friendly way of logging a user into the application. But we will have to be very careful when sending a login link to any user. Make sure to send the login link to the correct user.
Also, we can set up 2FA to avoid any such mistakes. 2FA is another guard that will make sure that the correct user logs in to an account.