Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Filament Passport Laravel Package

webteractive/filament-passport

Manage Laravel Passport OAuth clients, access tokens, and authorization codes from Filament, with built-in consent views for authorization and device flow so Passport works out of the box.

View on GitHub
Deep Wiki
Context7

Getting Started

The package is a thin Filament plugin wrapper around Passport's own Eloquent models — there are no migrations, no new tables, no proprietary schema. That makes onboarding short but also means Passport must be fully installed and migrated first. The plugin assumes oauth_clients, oauth_access_tokens, and oauth_auth_codes already exist.

Minimal path:

  1. Install Passport itself (this is a hard prerequisite, not optional):

    php artisan install:api --passport
    

    Confirm the oauth_* tables exist and Passport::routes() / the migrations ran. Skipping this leaves you with a plugin that registers resources against missing models — the failure mode is a blank or erroring resource list, not a helpful exception.

  2. Require the plugin:

    composer require webteractive/filament-passport
    
  3. Register it on your panel in app/Providers/Filament/*PanelProvider.php:

    use Webteractive\FilamentPassport\FilamentPassportPlugin;
    
    public function panel(Panel $panel): Panel
    {
        return $panel
            // ...
            ->plugins([
                FilamentPassportPlugin::make(),
            ]);
    }
    
  4. Publish the config (do this before you deploy — you want it versioned, not regenerated ad hoc):

    php artisan vendor:publish --tag=filament-passport-config
    

Where to look first: the published config/filament-passport.php and the plugin class itself (FilamentPassportPlugin). Those two artifacts tell you exactly what is enabled, how navigation is grouped, and what the access-control precedence is. Read the plugin source before trusting the README — at 1 star and 0 dependents, the source is the documentation.

First use case: open the panel, navigate to the OAuth group, and create a client using the Authorization Code grant with a redirect URI. That single flow exercises the three things that matter: resource registration, the grant-profile form schema, and the consent view wiring. If consent rendering is broken, you will see it here — not in production.

Implementation Patterns

Scope resources per panel rather than globally. The config flags and the fluent API both work, but they operate at the plugin instance level. In a multi-panel app, register the plugin with only what each panel should expose:

// Admin panel: full surface
FilamentPassportPlugin::make()
    ->clients()
    ->accessTokens()
    ->authCodes();

// Support/ops panel: read + revoke only, no client creation
FilamentPassportPlugin::make()
    ->clients(false)
    ->accessTokens()
    ->authCodes(false);

Treat this as your primary lever. The plugin inherits Filament's default open access unless you install a gate or callback, and both of those are panel-wide — they do not differentiate between "can revoke a token" and "can create a client." If you need that granularity, you build it in a policy on the underlying Passport models, not in the plugin.

Gate access at the panel provider, not the resource. The documented precedence is Gate → canAccess() callback → default open. The default being open is the single most important operational fact about this package:

// In a service provider — preferred, because it centralizes the decision
Gate::define('viewFilamentPassport', fn ($user) => $user->hasRole('admin'));

// Or per-plugin, when the rule differs between panels
FilamentPassportPlugin::make()
    ->canAccess(fn () => auth()->user()->can('manage-oauth'));

Pick one and only one. If a viewFilamentPassport gate exists anywhere in the app, it wins — a canAccess() callback on the plugin will be silently ignored, which is a genuinely easy way to ship a misconfiguration.

Publish views deliberately and keep overrides thin. The consent views are the higher-value half of this package; Laravel Passport does not ship consent screens and every team hand-builds them. Publish once and commit:

php artisan vendor:publish --tag=filament-passport-views

Files land in resources/views/vendor/filament-passport/ and take precedence over the package's. Then keep your diffs to copy, branding, and scope display — do not rewrite the redirect/state handling. That logic mirrors Passport's authorization controller and a divergence is a security bug, not a styling bug.

Use the config views map to interoperate, not to fork. The cleanest integration point in the whole package is this:

'views' => [
    'enabled' => true,
    'authorization' => null, // defer to another package
    'device_authorization' => 'filament-passport::device.authorize',
    'device_user_code' => 'filament-passport::device.user-code',
],

Setting a key to null skips that single binding while leaving the rest intact. This is the documented path for coexisting with Laravel MCP, which needs its own authorization view:

// AppServiceProvider::boot()
Passport::authorizationView(fn ($parameters) => view('mcp.authorize', $parameters));

Use this pattern whenever you already have a consent screen for one grant but want the package's views for the others. Setting 'enabled' => false disables all three bindings and leaves you with the admin CRUD only — the right call if you want token management without letting the package touch your auth flow.

Separate "views only" from "CRUD only" in your head. They are independently controllable and they carry different risk. Views are user-facing HTML in the OAuth redirect path. CRUD is an admin surface over sensitive credentials. Teams often want one and not the other; the config supports it, so decide explicitly rather than accepting the default of both.

Pick grant profiles from the capability table, not from the form. The plugin's form schemas encode these constraints, but you should design around them:

Profile Confidential Redirect URIs Device Flow
Authorization Code configurable required optional
Authorization Code (PKCE) no required no
Device Authorization (v13 only) configurable no yes
Password configurable no no
Implicit no required no
Client Credentials yes no no

Device Authorization is the constraint that drives roadmap decisions — it requires Passport 13, and if you are on 12 you cannot use it through this package regardless of what the UI shows.

Gotchas and Tips

There are no policies, and the default is open. The package is an admin tool over OauthClient, OauthAccessToken, and OauthAuthCode. Anyone who reaches the resource can enumerate and revoke tokens. On a panel with multiple roles — or any panel a non-admin can reach — install the gate before you deploy. This is the first thing to verify in any audit, not the last.

Device flow silently depends on Passport 13. On Passport 12, the authorization-code and device-consent code paths are fine, but device flow is not available. There is no runtime guard you can rely on; if a device-flow client gets created on a v12 install, you find out when the flow fails. Pin Passport and check the major version in your deployment notes.

Nothing migrates on install. No migrations ship with this package, and that is by design — it reads Passport's tables. The consequence: if php artisan install:api --passport was skipped or partially run, the plugin fails in confusing ways rather than with a clear "Passport not installed" error. Verify oauth_clients exists before you debug the plugin.

Composer constraints are not in the README — read composer.json directly. The README states PHP 8.2+, Filament 4/5, Passport 12/13, but the actual laravel/framework, filament/filament, and laravel/passport constraints live only in the manifest. On a Laravel app that is mid-upgrade, this is the difference between a clean install and a solver conflict. Check it in a throwaway branch before touching your main composer.json.

View publishing is a one-way ratchet. Published views take precedence permanently. There is no "revert to package default" command — you delete the files. Upstream fixes to consent-view logic will not reach you once published. Decide explicitly: keep them unpublished and accept less branding control, or publish and take on tracking upstream manually. There is no middle ground.

The state and PKCE parameters must survive your customizations. If you customize the consent view, preserve exactly what Passport's authorization controller expects — state round-trip, PKCE code_challenge handling, and redirect-URI validation. The plugin's views do this correctly; your edits might not. Test with a real client end to end after any view change, and specifically test the error paths (denied consent, invalid redirect) — those are the paths most likely to leak.

Config cache will bite you during development. The views and resources maps are read from config. If you change them and see no effect, you are probably looking at a cached config. Run php artisan config:clear (or optimize:clear) before concluding the plugin is broken.

The navigation group is global, not per-panel. 'navigation' => ['group' => 'OAuth', 'sort' => null] comes from config, so multiple panels sharing a config all get the same group. If two panels need different placement, you are editing config per environment, not per panel — plan accordingly or accept the shared label.

Treat this as a fork candidate from day one. One maintainer, one star, zero dependents, and the most recent release is dated well into the future relative to typical project timelines — which is a signal about either automated releases or aspirational versioning, not about stability. The MIT license is the actual mitigation: pin the version in composer.json, read the plugin source and the consent views before merging the dependency, and keep your overrides thin enough that replacing this package with ~200 lines of your own Filament resources is a realistic escape hatch.

Testing guidance the README gives is for the package itself. composer test runs the vendor's suite, not yours. You still need your own UAT: authorization code end to end against a real client, PKCE, client credentials, and — on Passport 13 — device flow through the user-code entry form. Do all four on a staging branch before this lands on a production panel.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin