Free·

How to auto-login in local environment, with a user selector

Choose your local user from a dropdown after running migrations and seeders

The problem

It's very, very annoying when we deal dozens of times interacting with our app in development, and we have to fill the login form. Not only we have to type the same thing over and over, there's also the muscle memory needed to remember the different users (with different roles, etc.).

What we explore today is a very convenient way of logging in an existing user after our migrations and seeders run..

The solution

Only in the local environment, we will override the default Filament login page, to add a dropdown with all the users available in our system. This way, we can just select the user we want to log in as, and click the login button.

Let's create a Filament Page class only. Instead of running the command, we will create the file manually, to avoid creating the view. Here's a shortcut to create the folder and file app/Filament/Pages/Auth/Login.php:

mkdir -p app/Filament/Pages/Auth
touch app/Filament/Pages/Auth/Login.php

We can now copy the contents of the file, that will override the default form.

It's recommended you leave the query filtering by some values that will not exist in production, for the case you end up having you production environment set as local, to not expose all your users and email addresses!
app/Filament/Pages/Auth/Login.php
<?php

namespace App\Filament\Pages\Auth;

use App\Models\User;
use Filament\Forms\Components\Select;
use Filament\Forms\Form;
use Filament\Pages\Auth\Login as BasePage;
use Filament\Http\Responses\Auth\Contracts\LoginResponse;

class Login extends BasePage
{
    public function mount(): void
    {
        parent::mount();
    }

    public function form(Form $form): Form
    {
        if (app()->environment('local')) {

            $users = User::query()
                ->whereLike('email', '%@example.com')
                ->pluck('name', 'email');

            $defaultUserEmail = User::query()
                ->whereLike('email', '%@example.com')
                ->first()?->email;

            $form->schema([
                Select::make('user')
                    ->required()
                    ->options($users)
                    ->default($defaultUserEmail),
            ]);

            return $form;
        }

        return parent::form($form);
    }

    public function authenticate(): ?LoginResponse
    {
        if (app()->environment('local')) {

            $authenticateAs = $this->form->getState()['user'] ?? null;

            auth()->login(
                User::query()
                    ->whereLike('email', '%@example.com')
                    ->where('email', $authenticateAs)->first()
            );

            return app(LoginResponse::class);
        }

        return parent::authenticate();
    }

}

We also need to tell Filament to use this new Login page.

app/Providers/Filament/AdminPanelProvider.php
<?php

namespace App\Providers\Filament;

use App\Filament\Pages\Auth\Login;
use Filament\Http\Middleware\Authenticate;
use Filament\Http\Middleware\AuthenticateSession;
use Filament\Http\Middleware\DisableBladeIconComponents;
use Filament\Http\Middleware\DispatchServingFilamentEvent;
use Filament\Pages;
use Filament\Panel;
use Filament\PanelProvider;
use Filament\Support\Colors\Color;
use Filament\Widgets;
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
use Illuminate\Cookie\Middleware\EncryptCookies;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;
use Illuminate\Routing\Middleware\SubstituteBindings;
use Illuminate\Session\Middleware\StartSession;
use Illuminate\View\Middleware\ShareErrorsFromSession;

class AdminPanelProvider extends PanelProvider
{
    public function panel(Panel $panel): Panel
    {
        return $panel
            ->default()
            ->id('admin')
            ->path('admin')
            ->login(Login::class)
            ->colors([
                'primary' => Color::Amber,
            ])
            ->viteTheme('resources/css/filament/admin/theme.css')
            ->discoverResources(in: app_path('Filament/Resources'), for: 'App\\Filament\\Resources')
            ->discoverPages(in: app_path('Filament/Pages'), for: 'App\\Filament\\Pages')
            ->pages([
                Pages\Dashboard::class,
            ])
            ->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\\Filament\\Widgets')
            ->widgets([
                Widgets\AccountWidget::class,
                Widgets\FilamentInfoWidget::class,
            ])
            ->middleware([
                EncryptCookies::class,
                AddQueuedCookiesToResponse::class,
                StartSession::class,
                AuthenticateSession::class,
                ShareErrorsFromSession::class,
                VerifyCsrfToken::class,
                SubstituteBindings::class,
                DisableBladeIconComponents::class,
                DispatchServingFilamentEvent::class,
            ])
            ->authMiddleware([
                Authenticate::class,
            ]);
    }
}

We'll be able to have our seeded users ready to be selected in the dropdown:

We're done. Enjoy!