Username? Email? Both? Yes!

James Hamann
Laravel Tips
Published in
3 min readMay 24, 2024

People need to be able to log in to your application right? Of course! And sometimes people don’t want to log in via a 3rd party source like Google or Facebook. As much as we might not want to do it, supporting user name and password logins is still a requirement for web apps today (and frankly that might be a good thing, considering the power big tech companies already leverage over the internet).

Those who use Laravel (top-tier people if you ask me) might be aware of starter kits like Laravel Breeze and Jetstream, which provide you with authentication pages and functionality out the gate. These are great, but the boilerplate they provide only contains authentication logic for using someone’s email. What if people want to use a username? Yes, they are out there. And we want to give the people what they want right?

We can roll our own authentication logic to implement both username and email login, or we can modify what happens with breeze or jetstream. Let’s look at rolling our own first. And really, all we are doing is providing a route and a login function. You can do this with a controller if you like. For simplicity, let’s make it an anonymous function:

Route::post('/login', function(Request $request) {
$credentials = $request->validate([
'email_or_username' => 'required',
'password' => 'required|(other good pass requirements)'
]);
})

Alright, breaking this down. Under the hood, the auth methods provided by breeze or jetstream expect email to be passed in the request. But our application expects either, and just needs the field to be required. And that can be tricky! We first need to figure out what we are working with here. We could use regex, but I am always wary of rolling my own regex when validating emails. Maybe it is a case of being able to pass the blame, but if I am using a framework, I want to rely on what is good enough for the framework. Thankfully, Laravel gives us a way to validate an email on demand the same way it would under the hood, by letting us create validators.

$emailValidator = Validator::make($credentials, [
'email_or_username' => 'email'
]);

$type = $emailValidator->fails() ? 'username' : 'email';

Since we know we have an email or username field, in this validator we only need to check if it passes the email test. If it doesn’t, we know we have a username! Next, we can use the Auth facade to attempt to authenticate a user with the given type and value:

$authenticated = Auth::attempt([
$type => $credentials['email_or_username'],
'password' => $credentials['$password']
]);

return $authenticated ? redirect('/loggedin') : redirect(back()->withErrors([...]));

This is a very simplified version of how to handle someone who is logged in versus a failed attempt, but the principal of handling either a username or a password can apply to any scenario. Require either, use a validator to test for one, then use the auth facade to authenticate with whichever type is appropriate. Easy peasy!

If you are already using Breeze or Jetstream and want to change to using either email or username, the process if fairly simple. It’s a little more complicated for Jetstream, but not much. You will need to use the `Fortify::authenticateUsing` method and call it in your Jetstream service provider. This method receives the request as a parameter like any route method so we can use the exact same code and logic for authenticating, except you will want to return the logged in user instead of a response. More info can be found in the official documentation.

For breeze, the controllers you would use to login a user are readily available to you! Just modify `App\Http\Requests\Auth\LoginRequest.php` with the logic for accepting email or username. Of course, for both of these solutions, you will also need to modify the views that are used to pass the login request.

Let people use a username or email to login, whichever they prefer. Thankfully, Laravel makes it very easy!

--

--

James Hamann
Laravel Tips

I'm a father, a software developer, and a poet. It's a strange combo. I feel a lot of things. I love words and people.