Laravel Auth: Login With Email Or Username (In One Field)

Tutorial last revisioned on December 15, 2022 with Laravel 9

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.

avatar

Is there a new one for laravel 9 ?

avatar

Not at the moment. But adding it to my to-do list, to update this article in upcoming weeks.

avatar

Just updated the article, for three starter kits and Laravel 9!

Like our articles?

Become a Premium Member for $129/year or $29/month
What else you will get:
  • 58 courses (1054 lessons, total 46 h 42 min)
  • 78 long-form tutorials (one new every week)
  • access to project repositories
  • access to private Discord

Recent Premium Tutorials