Laravel provides simple authentication system out-of-the box. It provides register, login, logout and Email verification features in single command. But have you wonder, you can even create authentication system without using password. By using this feature, user don't have to remember the password.
In this article, we will go through how you can create register and login system without password in Laravel. We will use only email address to register and login. In the register, we will send link in the given email for email verification, while we will send login link everytime when user input email.
We will go through step by step from the beginning. The tutorial covers below steps:
- Step 1: Create fresh Laravel application
- Step 2: Configure database and mail settings
- Step 3: Update user migration file and run migration
- Step 4: Create authentication routes
- Step 5: Create controller class
- Step 6: Create mailable class for login and register
- Step 7: Create mail templates for login and register
- Step 8: Create blade view files for login and register
- Step 9: Testing register and login feature
So let's start the tutorial with fresh Laravel application.
Step 1: Create fresh Laravel application
In the beginning of the tutorial, we will create fresh Laravel application using Composer command. To create Laravel application, open the Terminal and run following command.
composer create-project laravel/laravel passwordless --prefer-dist
After the project is created, change Terminal directory to project root.
cd passwordless
Step 2: Configure database and mail settings
We will also need to configure database and mail settings into Laravel application. Laravel application stores all environment variables at .env
file of root directory. Open the project into your favourite IDE.
Now open .env file and change database and email credentials accoring to your MySQL settings and mail credentials.
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=passwordless
DB_USERNAME=root
DB_PASSWORD=secret
MAIL_MAILER=smtp
MAIL_HOST=us-v1.mailjet.com
MAIL_PORT=587
MAIL_USERNAME=26**********7ba26
MAIL_PASSWORD=YPAMv*******1yoO78
MAIL_ENCRYPTION=tls
MAIL_FROM_NAME="Laravelcode"
MAIL_FROM_ADDRESS=harsukh21@gmail.com
Step 3: Update user migration file and run migration
We are using users table for authentication, but we are not using password field, instead we will use token
field. So open user migration file at database/migrations
directory and update password fields to below.
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->boolean('email_verified')->default(0)->comment('1 for verified and 0 for not verified');
$table->string('token');
$table->rememberToken();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('users');
}
}
After updating migration, run migrate command into Terminal to create users table into database.
php artisan migrate
Step 4: Create authentication routes
In this step, we will add required routes for register and login feature. Laravel routes are stored at routes directory. Open routes/web.php
file and add following routes into it.
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\AuthController;
Route::get('register', [AuthController::class, 'registerForm'])->name('registerForm');
Route::post('register', [AuthController::class, 'register'])->name('register');
Route::get('verify', [AuthController::class, 'verify'])->name('verify');
Route::get('login', [AuthController::class, 'loginForm'])->name('loginForm');
Route::post('send-link', [AuthController::class, 'sendLink'])->name('sendLink');
Route::get('login-verify', [AuthController::class, 'login'])->name('loginVerify');
Route::get('dashboard', [AuthController::class, 'dashboard'])->name('dashboard');
Route::get('logout', [AuthController::class, 'logout'])->name('logout');
Step 5: Create controller class
We have created the required routes for authentication. Now we need to create controller class and class methods where we will input application logic. For the simplicity of tutorial, we have created only one controller for all routes. You can create seperate controller for register and login feature. Run the following command into Terminal to generate controller class.
php artisan make:controller AuthController
This will create AuthController class at App/Http/Controllers/AuthController.php
file. Now open this file and add class methods as we have registered into routes.
<?php
namespace App\Http\Controllers;
use Auth;
use Mail;
use App\Models\User;
use App\Mail\LoginMail;
use App\Mail\RegisterMail;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
class AuthController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest')->except(['logout', 'dashboard']);
$this->middleware('auth')->only(['logout', 'dashboard']);
}
/**
* register form.
*
* @return void
*/
public function registerForm()
{
return view('register');
}
/**
* register form submit.
*
* @return void
*/
public function register(Request $request)
{
$input = $request->validate([
'name' => 'required|string|max:255',
'email' => 'required|email|string|max:255|unique:users',
]);
$token = Str::random(30);
$user = new User;
$user->name = $input['name'];
$user->email = $input['email'];
$user->email_verified = '0';
$user->token = $token;
$user->save();
Mail::to($input['email'])->send(new RegisterMail($token));
return redirect()->back()->with('success', 'Verification mail sent, please check your inbox.');
}
/**
* register verified.
*
* @return void
*/
public function verify(Request $request)
{
$input = $request->validate([
'token' => 'required|string',
]);
$user = User::where('token', $input['token'])
->where('email_verified', '0')
->first();
if ($user != null) {
User::where('token', $input['token'])
->update([
'email_verified' => '1',
'token' => ''
]);
Auth::login($user);
return redirect()->route('dashboard')->with('success', 'You are successfully registered.');
}
return redirect()->back()->with('error', 'Verification link is not valid.');
}
/**
* login form.
*
* @return void
*/
public function loginForm()
{
return view('login');
}
/**
* login link sent to mail.
*
* @return void
*/
public function sendLink(Request $request)
{
$input = $request->validate([
'email' => 'required|email',
]);
$user = User::where('email', $input['email'])
->where('email_verified', '1')
->first();
if ($user != null) {
$token = Str::random(30);
User::where('email', $input['email'])
->where('email_verified', '1')
->update(['token' => $token]);
Mail::to($input['email'])->send(new LoginMail($token));
return redirect()->back()->with('success', 'Login link sent, please check your inbox.');
}
return redirect()->back()->with('error', 'Email is not registered.');
}
/**
* login process.
*
* @return void
*/
public function login(Request $request)
{
$input = $request->validate([
'token' => 'required|string',
]);
$user = User::where('token', $input['token'])
->where('email_verified', '1')
->first();
if ($user != null) {
User::where('token', $input['token'])
->where('email_verified', '1')
->update(['token' => '']);
Auth::login($user);
return redirect()->route('dashboard')->with('success', 'You are successfully logged in.');
}
return redirect()->back()->with('error', 'Login link is not valid.');
}
/**
* logout process.
*
* @return void
*/
public function logout(Request $request)
{
auth()->guard('web')->logout();
\Session::flush();
return redirect()->route('loginForm')->with('success', 'you are successfully logged out.');
}
/**
* dashboard page
*
* @return void
*/
public function dashboard()
{
return view('dashboard');
}
}
Step 6: Create mailable class for login and register
As per the above step, we are sending email verification and login mail to the registered email address. To send the email, we need to create mailable class and mail templates. In this step, we will create mailable classes RegisterMail
and LoginMail
. In the next step, we will create mail template file. Run the following Artisan commands one by one to generate mailable class.
php artisan make:mail RegisterMail
php artisan make:mail LoginMail
This will create Mailable classes at App/Mail
directory. Open RegisterMail class and add below code into it.
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class RegisterMail extends Mailable
{
use Queueable, SerializesModels;
public $token;
/**
* Create a new message instance.
*
* @return void
*/
public function __construct($token)
{
$this->token = $token;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->view('registerMail')
->subject('Email verification mail.')
->with('token', $this->token);
}
}
And put the below code into LoginMail.php file
.
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class LoginMail extends Mailable
{
use Queueable, SerializesModels;
public $token;
/**
* Create a new message instance.
*
* @return void
*/
public function __construct($token)
{
$this->token = $token;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->view('loginMail')
->subject('Click on the link to login.')
->with('token', $this->token);
}
}
Step 7: Create mail templates for login and register
We have configured mailable class. Now we will create mail template blade file with link. We will send this template with email. Laravel blade files are located at resources/views
directory.
For email verification mail, create registerMail.blade.php
file at resources/views directory and input below HTML code into it.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Verify the email address by clicking the link</title>
<style type="text/css">
.container {
text-align: center;
margin: 50px;
}
.btn {
background-color: #ccc;
padding: 10px 20px;
display: inline-block;
}
</style>
</head>
<body>
<div class="container">
<h2>{{ config('app.name') }}</h2>
<div class="text-center">
<a class="btn" href="{{ route('verify', ['token' => $token]) }}">Click to Verify</a>
</div>
</div>
</body>
</html>
And for login mail, create loginMail.blade.php
file and input below HTML code into it.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Login by clicking the link</title>
<style type="text/css">
.container {
text-align: center;
margin: 50px;
}
.btn {
background-color: #ccc;
padding: 10px 20px;
display: inline-block;
}
</style>
</head>
<body>
<div class="container">
<h2>{{ config('app.name') }}</h2>
<div class="text-center">
<a class="btn" href="{{ route('loginVerify', ['token' => $token]) }}">Click to Login</a>
</div>
</div>
</body>
</html>
Step 8: Create blade view files for login, register and dashboard
In this final steps, we will create all front end blade files for view.
Create below blade views into resources/views
directory.
register.blade.php
file to register user.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Please register</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="row">
<div class="m-3">
<h2>{{ config('app.name') }}</h2>
@if(\Session::has('error'))
<div class="alert alert-danger my-1 w-50">{{ \Session::get('error') }}</div>
{{ \Session::forget('error') }}
@endif
@if(\Session::has('success'))
<div class="alert alert-success my-1 w-50">{{ \Session::get('success') }}</div>
{{ \Session::forget('success') }}
@endif
<p class="lead">Please register</p>
<form action="{{ route('register') }}" method="post" class="w-50">
@csrf
<div class="mb-3">
<label for="name" class="form-label">Name</label>
<input type="text" class="form-control" id="name" name="name" placeholder="Name">
@error('name')
<div class="alert alert-danger my-1">{{ $message }}</div>
@enderror
</div>
<div class="mb-3">
<label for="email" class="form-label">Email address</label>
<input type="email" class="form-control" id="email" name="email" placeholder="name@example.com">
@error('email')
<div class="alert alert-danger my-1">{{ $message }}</div>
@enderror
</div>
<input type="submit" class="btn btn-primary">
</form>
</div>
</div>
</div>
</body>
</html>
login.blade.php
file to send login link.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Please login</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="row">
<div class="m-3">
<h2>{{ config('app.name') }}</h2>
@if(\Session::has('error'))
<div class="alert alert-danger my-1 w-50">{{ \Session::get('error') }}</div>
{{ \Session::forget('error') }}
@endif
@if(\Session::has('success'))
<div class="alert alert-success my-1 w-50">{{ \Session::get('success') }}</div>
{{ \Session::forget('success') }}
@endif
<p class="lead">Please login</p>
<form action="{{ route('sendLink') }}" method="post" class="w-50">
@csrf
<div class="mb-3">
<label for="email" class="form-label">Email address</label>
<input type="email" class="form-control" id="email" name="email" placeholder="name@example.com">
@error('email')
<div class="alert alert-danger my-1">{{ $message }}</div>
@enderror
</div>
<input type="submit" class="btn btn-primary">
</form>
</div>
</div>
</div>
</body>
</html>
And dashboard.blade.php
file after successfully authenticated.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Dashboard</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container m-3">
<h2>{{ config('app.name') }}</h2>
<a href="{{ route('logout') }}">Logout</a>
<div class="row">
<div class="text-center">
<p class="lead">Welcome! {{ Auth::user()->name }}</p>
</div>
</div>
</div>
</body>
</html>
Step 9: Testing register and login feature
So, application coding part is completed. Now we can start testing application. First start Laravel server using following command into Terminal.
php artisan serve
In your browser, go to the url http://localhost:8000/register
. Input name and email address and register.
Check for the email in your inbox and click Verify button in mail.
To test login feature, go to http://localhost:8000/login
. Enter email address and login. You will get login link in the registered email address.
Conclusion
We have completed the article. So far, we have created register and login feature without password. This type of feature provides extra layer of security without OTP. We will also create another article on how to authenticate using OTP feature.
I hope you liked this article. Thank you for giving time in reading article. Happy coding.