F
Filament2mo ago
Fossil

2FA Middleware

I use Filament as the admin panel for my app. Whenever I login to my app, I get a 2FA screen after clicking login and the rest of the apps routes are not working before 2FA is completed. Now when I don't enter my 2FA, and try to open my Filament route instead I get the actual dashboard and everything is working. I can delete users etc. IE: Security hole. How can I apply my 2FA Middleware? Whenever I add \App\Http\Middleware\Google2FAMiddleware::class to the middleware() or authMiddleware() methods on my public function panel(Panel $panel): Panel in AdminPanelProvider.php it doesn't change anything.
14 Replies
Fossil
Fossil2mo ago
Anyone? 🙂
Desmond Njuguna
Desmond Njuguna2mo ago
Which starter kit are you using? Jetstream or Breeze?
toeknee
toeknee2mo ago
Ensure the middleware for your frontend routes are applied to your backend routes; https://filamentphp.com/docs/3.x/panels/configuration#applying-middleware
Fossil
Fossil2mo ago
No starter kit. Older project I have a 2FA middleware alias which is applied to my app routes. Any way to apply the same to Filament routes? When I add the FQDN to the middleware() function in my panel provider it doesnt do anything. Another thought: Is it possible to disable and bypass Filaments entire auth system and just rely on being logged on to the main app? That last part already works actually, just need to make FIlament inaccessable when the 2FA code hasnt been entered yet.
toeknee
toeknee2mo ago
Just add a redirect. Or register the standard login class you use .
Fossil
Fossil2mo ago
Any pointers? No clue where to look.
return $panel
->default()
->id('admin')
->path('dashboard')
->login()
return $panel
->default()
->id('admin')
->path('dashboard')
->login()
Part of my AdminPanelProvider. Do I remove the login method there? My login controller just uses the AuthenticatesUsers trait.
toeknee
toeknee2mo ago
->login() ->login(MyLoginClass::class)
Fossil
Fossil2mo ago
Ok. Meeting now, will try after and come back. Thanks! Hmm. Dont think I could make that work. It's expecting an invokable class. Yet my LoginController uses an index() and login() method.
toeknee
toeknee2mo ago
It expects a livewire class basically, so just add a redirect in the web routes to that url.
Fossil
Fossil2mo ago
Sorry for being a noob lol but add a redirect where to my /login url? AFAIK filament registers its own routes (/dashboard in my case) and idk if I can edit those.
toeknee
toeknee2mo ago
in your routes/web.php
Route::get('/{any}/login', function () {
return redirect('/login');
})->where('any', '.*');
Route::get('/{any}/login', function () {
return redirect('/login');
})->where('any', '.*');
with /login being your primary login route you want to use, /{any}/ will find any route which ends in /login and redirect to /login.
Fossil
Fossil5w ago
Ok cool, will try asap. Cheers! 😄 Ok that works perfectly. So simple, nice. Ah damn. Whenever I login with user/pass, I get shown the 2FA screen (diff URL). If I dont enter 2FA and instead open the dashboard (Filament) URL I am logged into Filament and can do anything. So need to make Filament aware of 2FA being logged in or not somehow
toeknee
toeknee5w ago
You need the 2fa middlewhere added to filament middleware 😉 For example my middleware for filament is:
->middleware([
EncryptCookies::class,
AddQueuedCookiesToResponse::class,
StartSession::class,
AuthenticateSession::class,
ShareErrorsFromSession::class,
VerifyCsrfToken::class,
SubstituteBindings::class,
DisableBladeIconComponents::class,
DispatchServingFilamentEvent::class,
RedirectTwoFactorEmail::class,
])
->middleware([
EncryptCookies::class,
AddQueuedCookiesToResponse::class,
StartSession::class,
AuthenticateSession::class,
ShareErrorsFromSession::class,
VerifyCsrfToken::class,
SubstituteBindings::class,
DisableBladeIconComponents::class,
DispatchServingFilamentEvent::class,
RedirectTwoFactorEmail::class,
])
Notice the last one? That middleware is:
<?php

namespace App\Http\Middleware;

use Closure;

class RedirectTwoFactorEmail
{
public function handle($request, Closure $next)
{
$response = $next($request);

// Check if the session indicates a 2FA verification is required

if (auth()->user() && ! auth()->user()->two_factor_excluded && session('requires_2fa_verification')) {
// Remove the flag to prevent redirect loops
$request->session()->forget('requires_2fa_verification');

// Redirect to the 2FA code entry page
return redirect()->route('two-factor-email.login');
}

return $response;
}
}
<?php

namespace App\Http\Middleware;

use Closure;

class RedirectTwoFactorEmail
{
public function handle($request, Closure $next)
{
$response = $next($request);

// Check if the session indicates a 2FA verification is required

if (auth()->user() && ! auth()->user()->two_factor_excluded && session('requires_2fa_verification')) {
// Remove the flag to prevent redirect loops
$request->session()->forget('requires_2fa_verification');

// Redirect to the 2FA code entry page
return redirect()->route('two-factor-email.login');
}

return $response;
}
}
Fossil
Fossil4w ago
I added it to both middleware and authmiddleware now and it seems to finally work in prod now too. Cheers!