I'm wanting to use Laravel Fortify and Livewire to create a very simple login form. I do not want to use Jetstream as it has more features that I do not need vs features I do need.
I'm using livewire throughout my app, and would like to use it for my login page to provide real time instant validation.
The problem I am encountering is I am unable to submit the form with values if I'm using wire:model on inputs.
I also can not use auth()->attempt() because it is being hijacked by Fortify.(At least, I think it is. All know is when I use it, it returns false)
How can I use livewire with fortify? I need to send the data from the livewire component to POST /login.
Here is my current set up:
FortifyServiceProvider.php
public function boot()
{
Fortify::createUsersUsing(CreateNewUser::class);
Fortify::updateUserProfileInformationUsing(UpdateUserProfileInformation::class);
Fortify::updateUserPasswordsUsing(UpdateUserPassword::class);
Fortify::resetUserPasswordsUsing(ResetUserPassword::class);
// Custom Fortify Views =============================
// Login Page
Fortify::loginView(function () {
return view('auth.login');
});
}
My auth/login.blade.php (simply calls the livewire components with the proper layout template)
<x-layouts.auth>
@livewire('auth.login')
</x-layouts.auth>
The livewire component livewire/auth/login.blade.php:
<form wire:submit.prevent="login" action="#" method="POST">
<div>
<label for="email">Email address</label>
<input wire:model="email" id="email" type="email" required autofocus>
@error('email'){{ $message }}@enderror
</div>
<div>
<label for="password">Password</label>
<input wire:model.lazy="password" id="password" type="password" required>
@error('password'){{ $message }}@enderror
</div>
<div>
<input wire:model.lazy="remember" id="remember_me" type="checkbox">
<label for="remember_me">Remember me</label>
<a href="#">Forgot your password?</a>
</div>
<div>
<button type="submit">Sign in</button>
</div>
</form>
and my Http/Livewire/Auth/Login.php file for the livewire component:
class Login extends Component
{
public $email = '';
public $password = '';
public $remember = false;
protected $rules = [
'email' => 'required|email|exists:users,email',
'password' => 'required',
];
/**
* Shows Real time validation for email field
*/
public function updatedEmail() {
$this->validate(['email' => 'email|exists:users,email']);
}
/**
* Logs user in when form is submitted
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Support\MessageBag
*/
public function login()
{
// ******* Need to submit the form to Fortify here?? ******
}
/**
* Renders the view
* @return mixed
*/
public function render()
{
return view('livewire.auth.login')
->layout('layouts.auth');
}
}
class Login extends Component { public $email = ''; public $password = ''; ......
First of all, accoring to the Livewire documentation, sensitive information(such as passwords) SHOULD NOT BE used as public properties in livewire components. Therefore you should think twice before using livewire with user authentication.
protected $rules = [ 'email' => 'required|email|exists:users,email', 'password' => 'required', ];
Next, in validation rules you are using exists:user,email which would validate real-time if an email is in the database. I would advice against using this validation with livewire real-time validation rule in production systems as it could be easily used by a malicious actor to extract email list of users of your system.
That being said, there are ways for you to authenticate(but not using Fortify) inside you login function. for example:
class LoginForm extends Component
{
public $email = '';
public $password = '';
public $remember = false;
protected $rules = [
'email' => 'required|email|exists:users,email',
'password' => 'required',
];
/*
Sometimes it's useful to validate a form field as a user types into it.
Livewire makes "real-time" validation simple with the $this->validateOnly() method.
To validate an input field after every update, we can use Livewire's updated hook:
*/
public function updated($propertyName)
{
$this->validateOnly($propertyName);
}
public function render()
{
return view('livewire.loginForm');
}
public function login()
{
$this->validate();
// Execution doesn't reach here if validation fails.
$email = $this->email;
$password = $this->password;
$credentials = ['email'=>$email, 'password'=>$password];
if (Auth::attempt($credentials)) {
// Auth success
}
else{
// Auth failed
}
}
}
Then again, when using this method, you are only using Fortify to retrieve the login page which is definitely not the intended use of Fortify. Therefore after considering all the issues, I think it is best you avoid using livewire for user authentication process.
I tried to install a new project with only Livewire and Fortify to simulate your scenario. After a long pondering, these are my findings
<form method="POST" action="{{ route('login') }}">
I hope this will give you the idea.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With