Laravel 5.7: Adding Support for Login with Username or Email

I've already published a few articles on Laravel Login to support username or email. In this article, I'm going to cover the process of adding the username or email support with Laravel 5.7 default authentication system.

The process below helps you to understand the following things.

  • Adds support for email verification which is supported by default in the framework now.
  • Adds support for register with the username, which is not available on a default authentication system.
  • Adds support for login with either username or email.

The reason behind writing this article is peoples, preferring my previous articles about Laravel login and register with username or email support for earlier versions of Laravel.

Compatibility

If you are starting your fresh Laravel 5.7 project, and want to add the support for username or email for login and register, you could follow the steps from the beginning.

For any existing project just upgraded to Laravel 5.7, it is, of course, useful to follow the article to customize your authentication system.

Customization

Let's begin with the registration part to add support for username or email login with Laravel 5.7.

Register

For a fresh Laravel 5.7 setup, begin with generating the default auth scaffolding with an artisan console command, which ships with the framework out of the box.

Routes

// no email verification
Auth::routes();

// after adding, email verification
Auth::routes(['verify' => true]);


I would like to recommend you to follow the earlier article [Email Verification after Registration with Laravel 5.7] side by side with this article to implement email verification with Laravel 5.7 authentication system.

Database

For existing project add a new migration file using an artisan command to add a new field to the users' table, and for the new fresh project, you can easily edit the migration file generated with auth scaffolding and add a single line below.

$table->string('username')->unique();

To fill value in the database for username field, we've to add a key username to the $fillable property under app/User.php database model.

protected $fillable = ['name', 'email', 'password', 'username'];

View

The user registration form also requires a little bit of customization to add the username field.

<div class="form-group row">
    <label for="username" class="col-md-4 col-form-label text-md-right">{{ __('Username') }}</label>

    <div class="col-md-6">
        <input id="username" type="text" class="form-control{{ $errors->has('username') ? ' is-invalid' : '' }}" name="username" value="{{ old('username') }}" required>

        @if ($errors->has('username'))
            <span class="invalid-feedback" role="alert">
                <strong>{{ $errors->first('username') }}</strong>
            </span>
        @endif
    </div>
</div>

Controller

The default auth system ships with a controller class, which handles the necessary methods for the registration system. We've to edit a few methods under that class to add the username to the database.

Login

We've already added the necessary routes, email verification steps linked with another article. For the login system to support username or email we need to override a few methods on the login controller.

The login form requires a very little change on the input type field from email to text.

<input id="email" type="text" class="form-control{{ $errors->has('email') ? ' is-invalid' : '' }}" name="email" value="{{ old('email') }}" required autofocus>

The controller class for login also ships with the framework and uses an AuthenticatesUsers trait, which handles the specific methods necessary for the default auth system.

To apply the new changes we need, we have to override the methods under the controller class for the login system.

    // LoginController.php

    /**
     * Get the needed authorization credentials from the request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    protected function credentials(Request $request)
    {
        $field = $this->field($request);

        return [
            $field => $request->get($this->username()),
            'password' => $request->get('password'),
        ];
    }

    /**
     * Determine if the request field is email or username.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return string
     */
    public function field(Request $request)
    {
        $email = $this->username();

        return filter_var($request->get($email), FILTER_VALIDATE_EMAIL) ? $email : 'username';
    }

    /**
     * Validate the user login request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return void
     */
    protected function validateLogin(Request $request)
    {
        $field = $this->field($request);

        $messages = ["{$this->username()}.exists" => 'The account you are trying to login is not registered or it has been disabled.'];

        $this->validate($request, [
            $this->username() => "required|exists:users,{$field}",
            'password' => 'required',
        ], $messages);
    }

Code

The full source code for the all above customization is available on the github repository.

Conclusion

Thanks for following up my regular articles, and reading up to the end. If you have any feedback for me, feel free to leave your comment. Do not forget to share if you think worth sharing, and reading my articles.

Happy Coding!