Offer «Entrar con Pireon» on the panel's login page
Some checks failed
Tests / lint (push) Has been cancelled
Tests / test (push) Has been cancelled
Tests / test-postgres (push) Has been cancelled
Tests / mcp (push) Has been cancelled

Under the e-mail and password form, a button takes the redirect flow
(Authorization Code + PKCE), so the password is only ever typed at the
identity server. The routes for it were already there; the page had no
way to reach them.

A Pireon client allows one grant type and the panel's is a password
client, so the redirect flow can use its own: PIREON_REDIRECT_CLIENT_ID
and PIREON_REDIRECT_CLIENT_SECRET (the main client when they are empty).
The button shows up once that client is set, or with
PIREON_REDIRECT_LOGIN=true. Each session renews its token with the
client that issued it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-16 12:46:07 +02:00
parent 3c119d425e
commit ec4f687ca8
12 changed files with 169 additions and 14 deletions

View File

@@ -10,6 +10,7 @@ use App\Services\Pireon\PireonClient;
use App\Services\Pireon\PireonException;
use App\Services\Pireon\TokenStore;
use DanHarrin\LivewireRateLimiting\Exceptions\TooManyRequestsException;
use Filament\Actions\Action;
use Filament\Auth\Http\Responses\Contracts\LoginResponse;
use Filament\Auth\Pages\Login;
use Filament\Facades\Filament;
@@ -27,6 +28,9 @@ use SensitiveParameter;
* usable password column — but the person signing in never sees that. They
* type their credentials here and land in the panel.
*
* «Entrar con Pireon», under the form, takes the redirect flow instead: the
* password is then typed at the identity server only.
*
* The cost of that convenience is stated plainly because it is real: this
* application now handles the password rather than never seeing it. It is sent
* straight to the identity server over the password grant and is never stored,
@@ -53,6 +57,25 @@ class PireonLogin extends Login
return __('pireon.sign_in_intro');
}
/**
* Under «Entrar», «Entrar con Pireon»: the redirect flow, for whoever would
* rather not type their password here (or signs in some other way there).
*/
protected function getFormActions(): array
{
$actions = parent::getFormActions();
if (config('pireon.redirect_login') && PireonClient::forRedirect()->isConfigured()) {
$actions[] = Action::make('pireon')
->label(__('pireon.continue_with_pireon'))
->url(route('auth.redirect'))
->color('gray')
->outlined();
}
return $actions;
}
/**
* Filament's own flow checks the credentials against the local user table.
* There are no local passwords here, so the whole of it is replaced: the
@@ -110,7 +133,7 @@ class PireonLogin extends Login
Auth::login($user, (bool) ($data['remember'] ?? false));
app(TokenStore::class)->put($token);
app(TokenStore::class)->put($token, viaRedirect: false);
if ($user->locale) {
session()->put(config('locales.session_key'), $user->locale);