genealabs/nova-passport-manager
A Laravel Nova tool for managing Laravel Passport OAuth clients and access tokens. Create, edit, and revoke clients and personal access tokens directly from your Nova dashboard, without leaving the admin panel.
This is a Laravel Nova tool, so the prerequisite chain is non-negotiable: Laravel + Nova (paid license) + Passport, all already installed and migrated. If any one of those isn't in place, stop here — you cannot justify buying a Nova license for one admin screen.
Install and register:
composer require genealabs/nova-passport-manager
// app/Providers/NovaServiceProvider.php
public function tools()
{
return [
new \GeneaLabs\NovaPassportManager\NovaPassportManager,
];
}
Then clear caches (php artisan optimize:clear) and check the Nova sidebar. Since this is a Nova tool (not a resource package), assets ship pre-built in dist/ — you generally should not need to run npm install unless you're forking.
Where to look first, in order:
composer.json — the actual laravel/nova, laravel/passport, and PHP constraints. This is the single most important file, because release 0.9.0 (2024-04-24) adding Laravel 11 is the only compatibility evidence you have. Nova 4 vs 5 and current Passport majors are unproven.Passport::useClientModel() or hard-codes Laravel\Passport\Client.resources/js — this is where client secrets and token listings are rendered, and therefore where the security questions live.First use case to try: create a client credentials grant client for a server-to-server partner integration. It exercises the whole path — create, read the secret, hand it to the partner — with a small blast radius and an easy rollback (delete the client). Do this on a non-production environment against your real Passport schema before anything else.
Gate the tool registration, don't just gate the screens. Nova tools are visible to every Nova user by default. Register conditionally:
public function tools()
{
return array_filter([
Gate::check('manage-oauth-clients')
? new \GeneaLabs\NovaPassportManager\NovaPassportManager
: null,
]);
}
Do this in addition to any policies, not instead of. Treat "the package ships adequate authorization" as false until you've read the code and proven otherwise.
Consume it as a fork, not an upstream dependency. The package is archived with a single maintainer and zero dependents. Pull the source into app/Nova/Tools/ (or a private package namespace), pin it, commit the lockfile, and own the maintenance explicitly. The practical workflow:
composer require genealabs/nova-passport-manager
# copy src/ into app/Nova/Tools/PassportManager/
# remove the composer dependency
# register your copy in NovaServiceProvider
Use it as a reference implementation for a bespoke resource. This is often the highest-value use. The tool's surface is small — likely a handful of files — which is itself the scoping signal. Read it, then write one or two Nova resources over Passport::clientModel() and Passport::tokenModel() with your own policies, audit logging, and secret-rotation UX. If the only real need is "ops can issue, inspect, and revoke clients and PATs," that's a contained build, not a platform initiative.
Wrap every mutation in a domain service, not a raw Nova action. Even if the UI ships its own delete buttons, route revocation and client deletion through your own service class so you can add audit logging in one place:
class RevokeOAuthClient
{
public function __invoke(Client $client): void
{
DB::transaction(function () use ($client) {
$client->tokens()->update(['revoked' => true]);
$client->authCodes()->delete();
$client->refreshTokens()->delete();
$client->delete();
activity()->performedOn($client)->log('oauth client revoked');
});
}
}
Verify the package's own revocation does the equivalent server-side before you rely on the button.
Write the runbook alongside the tool. The operational case is that support can revoke a leaked token without a DBA writing SQL against oauth_clients and without an engineer dropping to php artisan passport:client on a production shell. Document: who can access the screen, how to rotate a secret, how to notifying a downstream partner of a new credential before the old one retires, and what to check if revocation "doesn't seem to work."
Test issuance and revocation explicitly. Not a manual click-through — actual tests:
it('revokes issued tokens when a client is deleted', function () {
$client = Passport::client()->forceFill([...])->save();
$token = $client->tokens()->create([...]);
(new RevokeOAuthClient)($client);
expect($token->fresh()->revoked)->toBeTrue();
});
Passport::hashClientSecrets() breaks the create-then-copy flow. If hashing is enabled, secrets are stored hashed and cannot be re-displayed. A UI that assumes a retrievable secret will either render nothing useful or — worse — let an operator believe a rotation succeeded when the new secret is unrecoverable. Decide this before rollout: either keep hashing off (acceptable only if DB access is tightly controlled) or build the UX around show-once-and-copy-at-creation.
Secrets in browser history and clipboard. Whatever renders a secret in the DOM is a credential exposure surface. Show once, in a modal, with no route-addressable state. Avoid putting the secret in a query string or a component prop that survives a page refresh.
Unbounded token lists will hurt. oauth_access_tokens grows fast and unboundedly, and it lives in the same database serving production API traffic. Reject any screen that loads a full token list. Confirm pagination, search, and filter actually push down to SQL, and test against realistic row counts — not your dev seed data.
Custom Passport models silently break things. Confirm the tool resolves clients via Passport::useClientModel() / Passport::useTokenModel() rather than hard-coded Laravel\Passport\Client. A grep for fully-qualified Passport class names is a two-minute check that saves a confusing bug hunt.
No audit trail ships with it. Every mutation is unattributed. For incident review after a leaked token is revoked, that's a real gap — add logging in your wrapped service layer, since you're forking anyway.
Nova major-version upgrades are the maintenance cliff. The single Laravel 11 compatibility line in 0.9.0 is the ceiling of evidence. Before adopting, run a hard-timeboxed spike (3–5 days) covering: Composer constraint resolution against your pins, service provider + tool registration, sidebar rendering, and query behavior against your actual Passport schema. Do not infer compatibility from the release date.
The item should close if Passport isn't your OAuth server. If first-party SPA/mobile tokens are handled by Sanctum, this problem class doesn't exist. An admin UI for auth you don't run is pure backlog debt.
Budget the fork as a recurring line item. Nova and Laravel major upgrades, Passport schema/API drift, and security patches all land on you, with no upstream to escalate to. If you can't fund that, decline — an unmaintained dependency on the code path that reads client secrets is exactly where that's least acceptable.
How can I help you explore Laravel packages today?