Programming

Set Up Passwordless Login System in Laravel

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 about 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 how to 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 am going to create /login/magiclink to ask the user for his/her email id.

Route::prefix('login')->group(function() {

    Route::get('magiclink', '[email protected]')->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
Get user email
Get user email

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', '[email protected]')->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 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. Make sure that the email field was not sent 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 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 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 root of the application ‘/’ 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 createPasswordlessLoginLink() function on the user instance that we want to create the login link for.

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 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 just to avoid any such mistake. 2FA is another guard that will make sure that the correct user logs in to an account.



LinuxAndUbuntu hosting is sponsored by massiveGRID

Leave a Comment

* By using this form you agree with the storage and handling of your data by this website.

This website uses cookies to improve your experience. We'll assume you're ok with this. Thank you! Ok Read More