Computer monitor with lock and IP address

Adding IP Whitelisting to Your Filament PHP Admin Panel

TLDR;

Want to restrict access to your Filament admin panel to only specific IPs? Here's the coles notes:

  • Create a new middleware to check if the request IP is in your allowed list
  • Set up an allowed_ips database table to manage the whitelist
  • Add the middleware to your Filament AdminPanelProvider config
  • Done. Now only whitelisted IPs can access your Filament panel

This approach lets you manage allowed IPs from the database instead of hardcoding them in config files or the env settings.

Why IP Whitelisting?

Sometimes, just protecting your admin panel with a password doesn't feel like enough. You might want to limit access to your home IP address for small apps, prevent brute force attempts altogether, or simply add another layer of protection on top of authentication. This is where IP whitelisting comes in.

Step 1: Create the Middleware

We'll start with a custom middleware that checks if the request IP is in a database table. Here's what it looks like:

PHP
// app/Http/Middleware/IPWhitelist.php

public function handle(Request $request, Closure $next): Response
{
    $allowedIps = AllowedIP::all()->pluck('ip_address')->toArray();

    if (!in_array($request->ip(), $allowedIps)) {
        if ($request->expectsJson()) {
            return response()->json(['error' => 'The request is unauthorized'], 401);
        }
        abort(401, 'The request is unauthorized');
    }

    return $next($request);
}

Nothing fancy. It grabs all allowed IPs from the database, and checks if the incoming request matches.

Step 2: Create the AllowedIP Model and Migration

Let’s store allowed IPs in a proper Eloquent model.

PHP
// app/Models/AllowedIP.php

class AllowedIP extends Model
{
    protected $table = 'allowed_ips';

    protected $fillable = [
        'ip_address',
        'description',
    ];
}

And the corresponding migration:

PHP
// database/migrations/xxxx_xx_xx_create_allowed_ips_table.php

Schema::create('allowed_ips', function (Blueprint $table) {
    $table->id();
    $table->string('ip_address')->unique();
    $table->string('description')->nullable();
    $table->timestamps();
});

Step 3: Seed Some IPs

For local testing, let’s seed 127.0.0.1.

PHP
// database/seeders/AllowedIPSeeder.php

AllowedIP::firstOrCreate([
    'ip_address' => '127.0.0.1',
], [
    'description' => 'Localhost IP',
]);

And don’t forget to call it from your DatabaseSeeder.php:

PHP
$this->call(AllowedIPSeeder::class);

Step 4: Register the Middleware in Filament

The last piece is telling Filament to use this middleware for the admin panel. Inside your AdminPanelProvider you can add your new middleware to the top of the stack:

PHP
// app/Providers/Filament/AdminPanelProvider.php

use App\Http\Middleware\IPWhitelist;

// ...
->middleware([
    IPWhitelist::class, // 👈 Add this
    EncryptCookies::class,
    AddQueuedCookiesToResponse::class,
    StartSession::class,
])

And that's it! The IP whitelist will now be checked on each request to your admin dashboard.

Step 5: Testing It Works

First let's run our database migrations and seeders so that we have some data to work with.

BASH
php artisan migrate --seed

You should now be able to fire up your web browser and check if the admin login page is accessible. Note that if your local IP address is different than 127.0.0.1 , something like 192.168.0.x , then you can simply add this IP address to the whitelist instead. You can also clear the allowed_ips table to ensure that you receive a 401 Unauthorized response code as expected.

We should also write a few quick tests to make sure everything’s working as expected.

PHP
// tests/Feature/IPWhitelistTest.php

protected function setUp(): void
{
    parent::setUp();

    AllowedIp::create([
        'ip_address' => '123.123.123.123',
        'description' => 'Valid IP',
    ]);
}

public function test_admin_panel_denies_access_from_invalid_ip(): void
{
    collect([
        'filament.admin.auth.login',
        'filament.admin.pages.dashboard',
    ])->each(
        fn ($route) =>
        $this->withServerVariables([
            'REMOTE_ADDR' => '111.111.111.111',
        ])->get(route($route))->assertUnauthorized()
    );
}

public function test_admin_panel_allows_access_from_valid_ip(): void
{
    // Login page should return 200 OK
    $this->withServerVariables([
        'REMOTE_ADDR' => '123.123.123.123',
    ])->get(route('filament.admin.auth.login'))->assertStatus(Response::HTTP_OK);

    // Dashboard should redirect to login (302)
    $this->withServerVariables([
        'REMOTE_ADDR' => '123.123.123.123',
    ])->get(route('filament.admin.pages.dashboard'))
        ->assertStatus(Response::HTTP_FOUND)
        ->assertRedirectContains(route('filament.admin.auth.login'));
}

Step 6. (Bonus) Caching the Allowed IP Addresses

To improve performance, especially if your list of allowed IPs grows, it's a good idea to cache the results instead of querying the database on every request. You can cache the IP list for a short period (like 15 minutes) since running a query once per that timeframe isn't too taxing on the database. Just make sure to clear the cache anytime a new IP is added or removed from the whitelist.

PHP
// app/Http/Middleware/IPWhitelist.php

$allowedIps = Cache::remember('allowed_ips', now()->addMinutes(15), fn () => AllowedIP::all()->pluck('ip_address')->toArray());
PHP
// app/Observers/AllowedIPObserver.php

public function saved(AllowedIP $allowedIP): void
{
    Cache::forget('allowed_ips');
}

Wrap-Up

And that’s all you need to IP-lock your Filament admin panel.

The best part? You can manage allowed IPs through your own UI later on. Add a Filament resource to CRUD them in the admin panel itself. Just don’t forget to give yourself access first!

Pro Tip Sometimes it makes more sense to handle IP whitelisting outside your app using a WAF like AWS WAF. This is useful if you’re protecting multiple apps, want to block traffic before it even hits Laravel, or need to manage big or changing IP lists. Middleware works great for simple cases, but a WAF gives you more control at the network level.

Up Next

How to Add Dark Mode to Your Laravel Website (SSR) Using Tailwind 4.x . ' Featured Image'

How to Add Dark Mode to Your Laravel Website (SSR) Using Tailwind 4.x

In this post we'll see how simple it is to add a dark mode toggle to your Laravel website using Tailwind 4.x. Although there are a few different ways to accomplish this, this post focuses on...

August 13, 2025 • 3 min read
12 Simple Tips for Securing Your Web Apps . ' Featured Image'

12 Simple Tips for Securing Your Web Apps

In this post I share some simple tips you can use to improve the security of your web applications. Although many of these are best practices which apply to cloud-hosted web apps in general, I'll also share a few Laravel-specific code samples to...

August 1, 2025 • 7 min read