Quick tip for you guys. What if in your project users can login not only with email but also with some other field, like "username" or "user_id" or whatever? By default, Laravel allows only one field like 'email'. That's easy to change. Let's imagine that you already have a field username in your users table and need to check the login form result. So there are only two input fields - login and password. And login may be either email or username. How can we check both? Let's see how you can change that in all Laravel starters kits.
Laravel Breeze
Breeze tries to authenticate the user in the App/Http/Requests/Auth/LoginRequest.php
class, in authenticate()
method.
public function authenticate(){ $this->ensureIsNotRateLimited(); $login_type = filter_var($this->input('login'), FILTER_VALIDATE_EMAIL ) ? 'email' : 'username'; $this->merge([ $login_type => $this->input('login') ]); if (! Auth::attempt($this->only($login_type, 'password'), $this->boolean('remember'))) { RateLimiter::hit($this->throttleKey()); throw ValidationException::withMessages([ 'login' => trans('auth.failed'), ]); } RateLimiter::clear($this->throttleKey());}
Before that, don't forget to change the validation rules.
App/Http/Requests/Auth/LoginRequest.php:
public function rules(){ return [ 'email' => ['required', 'string', 'email'], 'login' => ['required', 'string'], 'password' => ['required', 'string'], ];}
Let's look a little deeper:
$login_type = filter_var($request->input('login'), FILTER_VALIDATE_EMAIL ) ? 'email' : 'username';
This line of code is checking whether the user inputted an email or some other string - which then is interpreted as a username.
$request->merge([ $login_type => $request->input(‘login')]);
This one is adding a variable into $request array - by default, we have 'login' variable, but what we need is 'email' or 'username' - so it's inserted here.
if (! Auth::attempt($this->only($login_type, 'password'), $this->boolean('remember'))) { RateLimiter::hit($this->throttleKey()); throw ValidationException::withMessages([ 'login' => trans('auth.failed'), ]); }
And finally, we're checking the credentials, but only the particular one we need - it comes from $login_type
variable. Simple, isn't it?
Laravel Jetstream
Jetstream uses Laravel Fortify for handling authentication. To save additional data, we will need to customize user authentication. Typically this should be done in the JetstreamServiceProvider
, in the boot()
method.
public function boot(){ // ... Fortify::authenticateUsing(function (Request $request) { $user = User::where('email', $request->login) ->orWhere('username', $request->login) ->first(); if ($user && Hash::check($request->password, $user->password)) { return $user; } });}
Laravel UI
You need to know that there is AuthenticatesUsers trait. It’s called every time someone logs in. You can check what methods this trait has in github repository. For our needs there is a username()
method that looks like this:
public function username(){ return 'email';}
So we need to override this method:
public function username(){ $login_type = filter_var(request()->input('login'), FILTER_VALIDATE_EMAIL) ? 'email' : 'name'; request()->merge([ $login_type => request()->input('login') ]); return $login_type;}
Also, I have a video about logging in with email, name, or phone. You can check it out here.
Is there a new one for laravel 9 ?
Not at the moment. But adding it to my to-do list, to update this article in upcoming weeks.
Just updated the article, for three starter kits and Laravel 9!