Laravel 7 – Login With Username Instead of Email

By default, email is the most important field for user, it is used as a unique identifier and is part of the credentials. But what if, in your case, email is just an informational field, and actual login credential is another one, like username?


First, take care of adding that field into the database/model/views.

Add field to the database.

Just add this line to some migration file:
$table->string(‘username’)->unique();
Choose to edit existing default migration file, or create a new one with php artisan make:migration add_surname_to_users_table.

Now we can run migration

php artisan migrate

Add field as fillable to User model.

By default, app/User.php has this:

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

So we need to add ‘surname’ into that array.

Add the field to View form.

We need to edit resources/views/auth/register.blade.php file. Add another field for username:

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

    <div class="col-md-6">
        <input id="username" type="text" class="form-control @error('username') is-invalid @enderror" name="username" value="{{ old('username') }}" required autocomplete="username" autofocus>

        @error('username')
            <span class="invalid-feedback" role="alert">
                <strong>{{ $message }}</strong>
            </span>
        @enderror
    </div>
</div>

Modify create() and validator() methods in RegisterController.

We just need to add lines related to username like this:

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

Then we need to edit resources/views/auth/login.blade.php file. Add another field for username like the code below and erase the field for e-mail:

<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="username" class="form-control @error('username') is-invalid @enderror" name="username" value="{{ old('username') }}" required  autofocus>

    @error('username')
      <span class="invalid-feedback" role="alert">
        <strong>{{ $message }}</strong>
      </span>
    @enderror
  </div>
</div>

Database, model and views are done. Next, take a look at app/Http/Controllers/Auth/LoginController:

class LoginController extends Controller
{
    use AuthenticatesUsers;
    // ... All other code

If we get deeper into that \vendor\laravel\ui\auth-backend\AuthenticatesUsers.php trait, we will see one method:

/**
 * Get the login username to be used by the controller.
 *
 * @return string
 */
public function username()
{
    return 'email';
}

It’s just a constant field returned by a function. And then it is used in actual validation and authentication:

protected function validateLogin(Request $request)
{
    $request->validate([
        $this->username() => 'required|string',
        'password' => 'required|string',
    ]);
}

So we need to override this method into LoginController.

class LoginController extends Controller
{
    use AuthenticatesUsers;
    // ... All other code

    public function username()
    {
        return 'username';
    }
}

That’s all! Now we can run the project and register and login by username.

I hope it can help you…