jeffersongoncalves/filament-oidc
Add OpenID Connect (OIDC) authentication to Filament panels. This package integrates OIDC single sign-on with Filament’s login flow, making it easy to authenticate users through providers such as Keycloak, Auth0, Azure AD, and other OIDC-compliant identity services.
Install both packages — as of 3.1.0 the OIDC core lives in a separate package:
composer require jeffersongoncalves/filament-oidc jeffersongoncalves/laravel-oidc
Publish and migrate. The migration tag was renamed in 3.1.0:
php artisan vendor:publish --tag=oidc-migrations
php artisan vendor:publish --tag=oidc-config # config/oidc.php (was filament-oidc.php)
php artisan migrate
If you are upgrading from 3.0.0 and already published migrations under filament-oidc-migrations, don't re-publish — the table name and schema are unchanged and the existing migration still works.
Point the config at your IdP: issuer/discovery URL, client ID, client secret, redirect URI, and scopes (openid profile email minimum). Register the exact callback URL in the IdP before testing — most providers fail silently or with a generic error on a redirect URI mismatch.
Add the plugin to your panel provider:
public function panel(Panel $panel): Panel
{
return $panel
->plugin(FilamentOidcPlugin::make())
// ...
}
Wire the trait into the model that authenticates into the panel. Note the namespace change in 3.1.0:
use JeffersonGoncalves\LaravelOidc\Concerns\HasOidcIdentities;
class User extends Authenticatable
{
use HasOidcIdentities;
}
First useful use case: an internal admin panel where staff sign in with the company IdP instead of a local password. Get that working end-to-end (login, identity row created, logout) before touching claim mapping or auto-provisioning.
Link-on-first-login vs. invite-only. The common pattern is: match the incoming email claim to an existing users row, then persist an oidc_identities row keyed by issuer + subject. For anything beyond a trusted internal IdP, gate account creation behind an allowlist of domains or an existing-user check — otherwise anyone with an account at the IdP can provision themselves into the panel.
Guard/panel separation. Register the plugin only on the panels that should accept SSO. If you have a separate customer-facing panel with password auth, keep the plugin off it rather than trying to branch inside the login flow; a single panel with two competing login paths is where most confusion comes from.
Multiple IdPs / environments. Keep issuer and credentials in config/oidc.php fed by env vars per environment, so local and staging each point at their own IdP client. Don't reuse production client secrets locally — redirect URIs will not match and you'll chase phantom bugs.
Claim-driven authorization. Read roles/groups from the ID token or userinfo response and map them onto your existing role/permission model in a login listener or an afterLogin hook, rather than branching inside Filament resources. Keeping authorization in one place means panel policies stay testable.
Logout. Decide explicitly between local session logout and IdP single logout. Local-only is the default-safe choice; RP-initiated logout needs an end-session endpoint and a post-logout redirect registered on the IdP.
Testing. Feature-test the callback with a fake IdP response rather than hitting the network; assert that an identity row is created once and reused on the second login (the classic duplicate-identity bug). For local manual testing, a containerised IdP (Keycloak, Dex) with a seeded user beats mocking the browser flow.
JeffersonGoncalves\Filament\Oidc\Models\OidcIdentity → JeffersonGoncalves\LaravelOidc\Models\OidcIdentity, and ...\Filament\Oidc\Concerns\HasOidcIdentities → ...\LaravelOidc\Concerns\HasOidcIdentities. If you publish config fresh, you'll get oidc.php; if you keep the old filament-oidc.php around, code reading filament-oidc.identities_table breaks. Grep the whole codebase — app code, seeders, factories, tests, and any custom identity subclass.oidc_identities still holds your rows and that the trait's relation resolves to the same table.{issuer}/.well-known/openid-configuration; a stray trailing slash produces a 404 that surfaces as a vague "unable to discover" error. Copy the issuer verbatim from the IdP's well-known document.APP_URL and trusted-proxy config determine the generated URL; a mismatch here is the single most common cause of "it works locally but not in staging".SESSION_DOMAIN, SESSION_SECURE_COOKIE, and that your load balancer preserves the original scheme.nbf-in-the-future ID tokens get rejected; keep hosts NTP-synced, and don't set token lifetime assumptions in your own code — read exp if you cache anything.preferred_username instead of email, groups returned only from userinfo and not the ID token). Log the subject and issuer, never the tokens.filament-oidc 3.1.0 depends on laravel-oidc 3.x; constrain both in composer.json so a future major of the core package doesn't silently change identity behaviour under you.How can I help you explore Laravel packages today?