DEV Community

Kingsconsult
Kingsconsult

Posted on • Updated on

Customize Laravel Auth (Laravel Breeze Registration and Login)

Hello Artisans, after making a post on Basic Laravel Login and Registration using Laravel Breeze, I got a lot of private messages on how to customize the Registration and Login where a developer can be able to add more fields because the default Laravel User Registration fields are just limited to Name, Email and Password right from the time of the Legacy UI till the time of writing this report. But there are instances of where a developer might want to collect not just the name, but First Name, Last Name, Username, Password or even making the Email not mandatory for users who don't have email, so I decide to write this little piece.
For this article, I am going to use the app from this article Basic Laravel Login and Registration using Laravel Breeze

Click on my profile to follow me to get more updates.

Step 1: Edit the RegisteredUserController

Go to app/Http/Controllers/Auth/RegisteredUserController.php and customize the store method to this

    public function store(Request $request)
    {
        $request->validate([
            'firstname' => 'required|string|max:255',
            'lastname' => 'required|string|max:255',
            'password' => 'required|string|confirmed|min:8',
            'username' => 'required|string|max:255',
        ]);

        Auth::login($user = User::create([
            'firstname' => $request->firstname,
            'lastname' => $request->lastname,
            'username' => $request->username,
            'email' => $request->email,
            'password' => Hash::make($request->password),
        ]));

        event(new Registered($user));

        return redirect(RouteServiceProvider::HOME);
    }
Enter fullscreen mode Exit fullscreen mode

In the validate( ) method, I removed email, and added firstname, lastname and username. Also in the User::create, I added the new fields.

Step 2: Create another migration file to add the new fields to the User and login_history table

This migration field will add the new fields to our existing users table, so run the command below

php artisan make:migration add_more_fields_to_users_table --table=users

Do the same for the login_history table.
The --table=users flag will specify the type of schema facade to use.
A migrations file will be created, go to database/migrations/ Migration files

Step 3: Add the new fields and modify the name field

We are going to modify the existing name field with firstname and also add other fields, but to modify an existing fields, we need a package doctrine/dbal, The Doctrine DBAL library is used to determine the current state of the column and to create the SQL queries needed to make the requested changes to your column. Laravel docs

composer require doctrine/dbal

After this, update the composer, by running the command below

composer update

php artisan command
Then add the following fields to the up( ) method of the migration file created above

    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->renameColumn('name', 'firstname');
            $table->string('lastname');
            $table->string('username');
            $table->string('email')->nullable()->change();
        });
    }
Enter fullscreen mode Exit fullscreen mode

You will notice how we are going to rename our name field to firstname and added lastname and username, also we modify file email from mandatory to nullable().

Don't forget to do the same for the login_history.
Finally, run the migration command, but

php artisan migrate

php artisan migrate
Database
Database

Step 4: Modify the Users Model

We need to add the fields to be fill in users model, go to app/Models/User.php and edit the protected $fillable to add the new fields

    protected $fillable = [
        'firstname',
        'email',
        'password',
        'username',
        'lastname'
    ];
Enter fullscreen mode Exit fullscreen mode

Step 5: Modify the Registration view

Go to resources/views/auth/register.blade.php and modify to this

<x-guest-layout>
    <x-auth-card>
        <x-slot name="logo">
            <a href="/">
                <x-application-logo class="w-20 h-20 fill-current text-gray-500" />
            </a>
        </x-slot>

        <!-- Validation Errors -->
        <x-auth-validation-errors class="mb-4" :errors="$errors" />

        <form method="POST" action="{{ route('register') }}">
            @csrf

            <!-- Name -->
            <div>
                <x-label for="firstname" :value="__('First Name')" />

                <x-input id="firstname" class="block mt-1 w-full" type="text" name="firstname" required autofocus />
            </div>
            <!-- Name -->
            <div>
                <x-label for="lastname" :value="__('Last Name')" />

                <x-input id="lastname" class="block mt-1 w-full" type="text" name="lastname" required />
            </div>
            <!-- Name -->
            <div>
                <x-label for="username" :value="__('username')" />

                <x-input id="username" class="block mt-1 w-full" type="text" name="username" required />
            </div>

            <!-- Email Address -->
            <div class="mt-4">
                <x-label for="email" :value="__('Email')" />

                <x-input id="email" class="block mt-1 w-full" type="email" name="email"  />
            </div>

            <!-- Password -->
            <div class="mt-4">
                <x-label for="password" :value="__('Password')" />

                <x-input id="password" class="block mt-1 w-full" type="password" name="password" required autocomplete="new-password" />
            </div>

            <!-- Confirm Password -->
            <div class="mt-4">
                <x-label for="password_confirmation" :value="__('Confirm Password')" />

                <x-input id="password_confirmation" class="block mt-1 w-full" type="password" name="password_confirmation" required />
            </div>

            <div class="flex items-center justify-end mt-4">
                <x-button>
                    {{ __('Register') }}
                </x-button>
            </div>
        </form>
    </x-auth-card>
</x-guest-layout>
Enter fullscreen mode Exit fullscreen mode

Start our application with

php artisan serve

Click on Register, we are going to have this
register

Step 6: Modify the Login view

Go to resources/views/auth/login.blade.php and modify to this

<x-guest-layout>
    <x-auth-card>
        <x-slot name="logo">
            <a href="/">
                <x-application-logo class="w-20 h-20 fill-current text-gray-500" />
            </a>
        </x-slot>

        <!-- Session Status -->
        <x-auth-session-status class="mb-4" :status="session('status')" />

        <!-- Validation Errors -->
        <x-auth-validation-errors class="mb-4" :errors="$errors" />

        <form method="POST" action="{{ route('login') }}">
            @csrf

            <!-- Email Address -->
            <div>
                <x-label for="username" :value="__('Username')" />

                <x-input id="username" class="block mt-1 w-full" type="text" name="username" required autofocus />
            </div>

            <!-- Password -->
            <div class="mt-4">
                <x-label for="password" :value="__('Password')" />

                <x-input id="password" class="block mt-1 w-full" type="password" name="password" required autocomplete="current-password" />
            </div>

            <!-- Remember Me -->
            <div class="block mt-4">
                <label for="remember_me" class="flex items-center">
                    <input id="remember_me" type="checkbox" class="form-checkbox" name="remember">
                    <span class="ml-2 text-sm text-gray-600">{{ __('Remember me') }}</span>
                </label>
            </div>

            <div class="flex items-center justify-end mt-4">
                @if (Route::has('password.request'))
                <a class="underline text-sm text-gray-600 hover:text-gray-900" href="{{ route('password.request') }}">
                    {{ __('Forgot your password?') }}
                </a>
                @endif

                <x-button class="ml-3">
                    {{ __('Login') }}
                </x-button>
            </div>
        </form>
    </x-auth-card>
</x-guest-layout>
Enter fullscreen mode Exit fullscreen mode

This will change the login field from email to username

Step 7: Modify the Login Request Class

This is the class that replaces the LoginController class in the previous Laravel Authentication. Go to app/Requests/Auth/LoginRequest.php and change all the email string to username string, and also make sure the validating rules, you remove the email rule and replace it with username rule

<?php

namespace App\Http\Requests\Auth;

use Illuminate\Auth\Events\Lockout;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
use App\Events\LoginHistory;



class LoginRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'username' => 'required|string',
            'password' => 'required|string',
        ];
    }

    /**
     * Attempt to authenticate the request's credentials.
     *
     * @return void
     *
     * @throws \Illuminate\Validation\ValidationException
     */
    public function authenticate()
    {
        $this->ensureIsNotRateLimited();

        if (! Auth::attempt($this->only('username', 'password'), $this->filled('remember'))) {
            RateLimiter::hit($this->throttleKey());

            throw ValidationException::withMessages([
                'username' => __('auth.failed'),
            ]);
        }

        $user = Auth::user();

        event(new LoginHistory($user));

        RateLimiter::clear($this->throttleKey());
    }

    /**
     * Ensure the login request is not rate limited.
     *
     * @return void
     *
     * @throws \Illuminate\Validation\ValidationException
     */
    public function ensureIsNotRateLimited()
    {
        if (! RateLimiter::tooManyAttempts($this->throttleKey(), 5)) {
            return;
        }

        event(new Lockout($this));

        $seconds = RateLimiter::availableIn($this->throttleKey());

        throw ValidationException::withMessages([
            'username' => trans('auth.throttle', [
                'seconds' => $seconds,
                'minutes' => ceil($seconds / 60),
            ]),
        ]);
    }

    /**
     * Get the rate limiting throttle key for the request.
     *
     * @return string
     */
    public function throttleKey()
    {
        return Str::lower($this->input('username')).'|'.$this->ip();
    }
}
Enter fullscreen mode Exit fullscreen mode

Logout from the app and click on login
login page
dashboard after login

We can now login with username and password instead of email address. That is all
Follow me for more of my articles, you can leave comments, suggestions, and reactions.
I am open to any vacancy as a PHP backend engineer, my strength is in the Laravel framework

click the link to view my profile and follow me

Top comments (15)

Collapse
 
bicho44 profile image
Federico Reinoso

I know, maybe this is out of the scope of the tutorial, but, how you can add Roles to the register?
I just need to deny access to certain part of my site to certain role, (come can edit and some can only see)
It is possible?, or is better to go directly to Jetstream?
Thanks in advance.

Collapse
 
dreamhigh915 profile image
DreamHigh

Hi. king.
Now, I'm trying to use jQuery ajax method to send requests to the controller.
But, I've faced such an error.

Target [Laravel\Fortify\Contracts\RegisterViewResponse] is not instantiable.

Hope your kind help.

Collapse
 
kingsconsult profile image
Kingsconsult

Sorry, seeing this late, would be easier for me to debug if I see the way you are sending the request to the controller

Collapse
 
dreamhigh915 profile image
DreamHigh

Thank you. King.
I've solved it myself. :D
Thanks for your kindness reply again.

Collapse
 
marcelobianco profile image
Marcelo Bianco

Hi my friend
I have the following error: ErrorException
Undefined index:
my password field is called senha and it doesn’t pass this validation at all

public function validateCredentials(UserContract $user, array $credentials)

{

    $plain = $credentials['password'];



    return $this->hasher->check($plain, $user->getAuthPassword());

}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
rahulmanek profile image
rahulmanek

I am also facing same issue
Any solution??

Collapse
 
fahrudinyw profile image
Fahrudin Yuniwinanto

why suddenly there is login_history? tought in part 1 and 2 there is no tell about login_history, make me little bit confuse. please tell me clearly. thanks

Collapse
 
adefowowe profile image
Adefowowe Adebamowo • Edited

Hi Kingsley, really nice series! Taking the customisation further, how might one implement login with either email or mobile phone (in one field) and password. Thanks.

Collapse
 
njoura7 profile image
Njoura7

thank you for this article mate!

what do you mean by login_history please ?

Collapse
 
wanazhad24 profile image
wanazhad24

Hey wanna ask, in a situation where I'm not using a Users table for the login, where am I supposed to change the referenced table?

Collapse
 
thatal profile image
Sunil Thatal

you can change it on config/auth.php providers configuration.

Collapse
 
wanazhad24 profile image
wanazhad24 • Edited

Is this correct? Even after I changed that, it is saying that the credentials is invalid.

'providers' => [
'staffs' => [
'driver' => 'eloquent',
'model' => App\Models\Staff::class,
'table' => 'staffs'
],

Thread Thread
 
thatal profile image
Sunil Thatal • Edited

yes it is correct. you don't have to add table if you are using eloquent. Add query listener above your code to monitor query.
\DB::listen(function($query){
\Log::debug($query->sql);
\Log::debug($query->bindings);
});

Collapse
 
arinzehills profile image
ARINZE CHRIS HILLS

please mine does'nt have does controllers, please can you help me out

Collapse
 
kingsconsult profile image
Kingsconsult

Hope you run these commands

composer require laravel/breeze --dev
php artisan breeze:install