Laravel Auth: Login With Email Or Username In One Field

5 2,215

A quick great tip for you guys. Laravel default authentication allows you to login with an email only but we can also use some other field like username. Laravel by default only allows one field email for login but we can also use username with it as well.

In this tutorial, we will see how we can login with only two fields login and password. Login can either be email or username.

Let’s create a laravel project that allows to login with email or username in one field.

Setting Up Project

First create a new laravel project named login with laravel installer. We will be using laravel 5.6 in this tutorial.

laravel new login

Setup database credentials in .env file.

Run the following command to scaffold basic login and registration.

php artisan make:auth

Open create_users_table.php present in database/migrations directory. Add the username field in the up to store the username. To do this, copy the code below and replace it with the up method.

public function up()
{
    Schema::create('users', function (Blueprint $table) {
        $table->increments('id');
        $table->string('name');
        $table->string('username');
        $table->string('email')->unique();
        $table->string('password');
        $table->rememberToken();
        $table->timestamps();
    });
}

Now migrate the database by running the following command.

php artisan migrate

Registering Users

After adding username column in the database, it is also required to change laravel default authentication to accept username and save it in the database.

Register View

First let’s add username input field to Users registration form. Go to register.blade.php present in resources/views/auth directory. Add the following code after the name row to add a username input 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">
                <strong>{{ $errors->first('username') }}</strong>
            </span>
        @endif
    </div>
</div>

The above code is very simple. I have just copied the Name input row and changed the attributes with username.

Full code for register.blade.php

Register Controller

Front end is set up and only the back-end logic is remaining. Go to RegisterController.php file in app/Http/Controllers/Auth directory.

In the validator method, add the validation for the username field as well. Here’s the updated validator method.

protected function validator(array $data)
{
    return Validator::make($data, [
        'name' => 'required|string|max:255',
        'username' => 'required|string|max:255|unique:users',
        'email' => 'required|string|email|max:255|unique:users',
        'password' => 'required|string|min:6|confirmed',
    ]);
}

Username is required, needs to be a string, can contain a maximum of 255 characters and it should be unique in the users table in the username column.

In the create method, add the username field so that username will also be saved in the database along with other fields. Here’s the updated create method.

protected function create(array $data)
{
    return User::create([
        'name' => $data['name'],
        'username' => $data['username'],
        'email' => $data['email'],
        'password' => Hash::make($data['password']),
    ]);
}

Well, we have completely setup username field for the registration.

Log in with username or email

Now that username is added while registering users. Let’s give users the ability to login with either email or username.

Login View

First we need to make some changes to the login view particularly in E-Mail Address input field row. Go to login.blade.php file present in resources/views/auth directory. Now replace the first row in the form which the E-Mail Address input field with the contents below.

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

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

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

Don’t worry, let me explain you everything above. Basically we will send the input of the login with the name login. Laravel will accept it and it will find either the input is email or username. It will be merged in the request with the key email or username. So, in the value attribute on input tag, we are setting it to the old('username') if it evaluates to true otherwise old('email').

We are doing the same when checking for the error. If either username or email is in the errors array we output the respective error.

Full source code for login.blade.php

Login Controller

Let’s setup back-end logic for our login. Go to LoginController.php file present in app/Http/Controllers/Auth directory. Here’s the updated code for the Login Controller file.

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;

class LoginController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Login Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles authenticating users for the application and
    | redirecting them to your home screen. The controller uses a trait
    | to conveniently provide its functionality to your applications.
    |
    */

    use AuthenticatesUsers;

    /**
     * Where to redirect users after login.
     *
     * @var string
     */
    protected $redirectTo = '/home';

    /**
     * Login username to be used by the controller.
     *
     * @var string
     */
    protected $username;

    /**
     * Create a new controller instance.
     */
    public function __construct()
    {
        $this->middleware('guest')->except('logout');

        $this->username = $this->findUsername();
    }

    /**
     * Get the login username to be used by the controller.
     *
     * @return string
     */
    public function findUsername()
    {
        $login = request()->input('login');

        $fieldType = filter_var($login, FILTER_VALIDATE_EMAIL) ? 'email' : 'username';

        request()->merge([$fieldType => $login]);

        return $fieldType;
    }

    /**
     * Get username property.
     *
     * @return string
     */
    public function username()
    {
        return $this->username;
    }
}

Let me explain every change made in the Login Controller. We have added a new username property which we will use to store whether the login field is email or username. This field will only have two values email or username. In the constructor, we are calling the findUsername method. In this method we get the value of the login input. We check weather the field is a valid email, if yes we set $fieldType to email otherwise username. Then we add the $fieldType with the input login in the request by using the merge method. Merge method basically merge a new input into the current request’s array. Then we return the $fieldType which could either be email or username.

The last method we added in the class is the username method. This method is override over the username method that laravel uses to get the login username to be used.

That’s all what is required to login with email or username in one field.

Find the full source code for the project at GitHub.

You might also like