In part one of this article, we created our authentication setup using fortify, laravel and bootstrap.
In part two of this article, we covered updating your profile information and how to change your password from your profile page using livewire
In this tutorial, We will cover:
- adding two-factor auth to your project
Clone part one of our project
git clone --branch starter2 git@github.com:jasminetracey/lara8auth.git
cd lara8auth
Open your cloned project in IDE of choice I will be using Visual Studio Code
Install Alpine.js
We will be installing alpine.js to do some showing and hiding in the two factor form
npm install --save alpinejs
Import package in the resources/js/app.js file
...
import Alpine from 'alpinejs';
window.Alpine = Alpine;
Alpine.start();
...
Update Fortify Provider
To begin we will be updating our fortify provider to enable the 2factor page when the user logs in.
public function boot()
{
...
Fortify::twoFactorChallengeView(function () {
return view('auth.two-factor-challenge');
});
...
}
Create two-factor auth view
touch resources/views/auth/two-factor-challenge.blade.php
@extends('layouts.app')
@section('content')
<div class="container" x-data="{ recovery: false }">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Login') }}</div>
<div class="card-body">
<div class="alert alert-info" role="alert" x-show="! recovery">
{{ __('Please confirm access to your account by entering the authentication
code provided by your authenticator application.') }}
</div>
<div class="alert alert-info" role="alert" x-show="recovery">
{{ __('Please confirm access to your account by entering one of your
emergency recovery codes.') }}
</div>
<form method="POST" action="{{ route('two-factor.login') }}">
@csrf
<div class="form-group row" x-show="! recovery">
<label for="code" class="col-md-4 col-form-label text-md-right"
>{{ __('Code') }}</label
>
<div class="col-md-6">
<input
id="code"
type="text"
class="form-control @error('code') is-invalid @enderror"
name="code"
value="{{ old('code') }}"
autocomplete="one-time-code"
/>
@error('code')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row" x-show="recovery">
<label for="recovery_code" class="col-md-4 col-form-label text-md-right"
>{{ __('Recovery Code') }}</label
>
<div class="col-md-6">
<input
id="recovery_code"
type="text"
class="form-control @error('recovery_code') is-invalid @enderror"
name="recovery_code"
value="{{ old('recovery_code') }}"
autocomplete="one-time-code"
/>
@error('recovery_code')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="flex items-center justify-end mt-4"></div>
<div class="mb-0 form-group row">
<div class="col-md-3 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ __('Login') }}
</button>
</div>
<div class="col-md-5">
<button
type="button"
class="btn btn-secondary"
x-show="! recovery"
x-on:click="
recovery = true;
$nextTick(() => { $refs.recovery_code.focus() })
"
>
{{ __('Use a recovery code') }}
</button>
<button
type="button"
class="btn btn-secondary"
x-show="recovery"
x-on:click="
recovery = false;
$nextTick(() => { $refs.code.focus() })
"
>
{{ __('Use an authentication code') }}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
Update User Model
We also need to tell our user model that we will be enabling 2factor authentication so we need to add a trait TwoFactorAuthenticatable
...
use Laravel\Fortify\TwoFactorAuthenticatable;
class User extends Authenticatable implements MustVerifyEmail
{
use HasFactory, Notifiable, TwoFactorAuthenticatable;
...
Create livewire enable two-factor form
This form will be used to manage 2factor authentication. This includes enabling, disabling, and regenerating recovery codes.
From your terminal run the following command php artisan livewire:make two-factor-form
This will create our livewire component.
In your resources/views/livewire/profile-form.blade.php
add the following code to create our form fields.
<section class="my-5">
@if (session('status') == 'two-factor-authentication-enabled')
<div class="mb-4 text-sm font-medium text-green-600">
Two factor authentication has been enabled.
</div>
@endif
<div class="card">
<div class="card-body">
<h5 class="card-title">Two-Factor Authentication</h5>
@if (!empty($this->user->two_factor_secret))
@if ($showQrCode)
<p>
Two factor authentication is now enabled. Scan the following QR code using your
phone's authenticator application.
</p>
<div>{!! $this->user->twoFactorQrCodeSvg() !!}</div>
@endif
@if ($showRecoveryCodes)
<div class="mt-4">
<p>
Store these recovery codes in a secure password manager. They can be used to
recover access to your account if your two factor authentication device is lost.
</p>
<div>
@foreach (json_decode(decrypt($this->user->two_factor_recovery_codes), true) as
$code)
<div>{{ $code }}</div>
@endforeach
</div>
</div>
@endif
<div class="mt-4">
@if ($showRecoveryCodes)
<button wire:click="regenerateRecoveryCodes" class="btn btn-secondary">
Regenerate Recovery Codes
</button>
@else
<button wire:click="showRecoveryCodes" class="btn btn-secondary">
Show Recovery Codes
</button>
@endif
<button wire:click="disableTwoFactorAuth" class="btn btn-primary">
Disable Two-Factor Authentication
</button>
</div>
@else
<div>
<p>You have not enabled two factor authentication.</p>
<button wire:click="enableTwoFactorAuth" class="btn btn-primary">
Enable Two-Factor Authentication
</button>
</div>
@endif
</div>
</div>
</section>
After adding our view we need to add the code in the livewire component file app\Http\Livewire\TwoFactorForm.php to interact with fields.
We will first add two fields to the component to hide and show QRCode and the RecoveryCode. And the function to toggle showing the recovery codes.
public $showQrCode = false;
public $showRecoveryCodes = false;
public function showRecoveryCodes()
{
$this->showRecoveryCodes = true;
}
Next we will include a user property to the component because we will be interacting with a couple fields on the authenticated user.
public function getUserProperty()
{
return Auth::user();
}
The first function we will be adding is the enableTwoFactorAuth
function. This is the one that gets the ball rolling and allowing the user to setup two-factor authentication. We will be using the EnableTwoFactorAuthentication action that comes with fortify.
public function enableTwoFactorAuth(EnableTwoFactorAuthentication $enable)
{
$enable(Auth::user());
$this->showQrCode = true;
$this->showRecoveryCodes = true;
}
Remember to import the EnableTwoFactorAuthentication action
The next function will be the disableTwoFactorAuth
function. If for some reason the user no longer wishes to have to factor authentication on their account we will provide the option to disable it. Again we will be using a fortify action DisableTwoFactorAuthentication.
public function disableTwoFactorAuth(DisableTwoFactorAuthentication $disable)
{
$disable(Auth::user());
}
Remember to import the DisableTwoFactorAuthentication action
Finally we will be adding a function to regenerate recovery codes. These recovery codes allow the user to authenticate if they lose access to their mobile device.
public function regenerateRecoveryCodes(GenerateNewRecoveryCodes $generate)
{
$generate(Auth::user());
$this->showRecoveryCodes = true;
}
Remember to import the GenerateNewRecoveryCodes action
Finally, we will add our component to the resources/views/profile.blade.php page so that we can see the form when we visit the profile page.
@extends('layouts.app')
@section('content')
<div class="container">
<livewire:profile-form />
<livewire:password-change-form />
<livewire:two-factor-form />
</div>
@endsection
Now when you go to /profile
you should have the working 2factor form.
Conclusion
To find out more about laravel fortify features you can go the the github respository Fortify and for livewire documentation you can go to livewire
Thanks for reading please comment below and share if you found this article helpful.
jasminetracey / lara8auth
This is a simple auth starter setup for laravel 8 projects using bootstrap and laravel fortify
This is a simple auth starter setup for laravel 8 projects
Features
- User Login
- User Registration
- Email Verification
- Forget Password
- Reset Password
- Change Password
- Update User Profile
- TwoFactor Authentication
- Browser Session Management
Top comments (2)
This is a really great post! Well done!
Thanks