shipfastlabs/grant
Grant is a lightweight Laravel package from ShipFastLabs for adding credits to your app. It provides a simple, expressive API to grant, spend, and track user credits, with seamless Eloquent integration and minimal setup.
shipfastlabs/grant is a pre-1.0 authorization package, so treat the first hour as an API discovery exercise rather than a copy-paste install.
composer require shipfastlabs/grant
php artisan vendor:publish --tag="grant-config"
php artisan vendor:publish --tag="grant-migrations"
php artisan migrate
config/grant.php first — v0.0.1 adds config validation, so this file is now actively parsed and validated at boot. Anything you leave as env()-driven is checked early; a bad value fails loudly on artisan boot rather than silently at runtime.User (or any authenticatable) model, and confirm whether permissions are resolved against a cache store or the database.Gate::allows() check in a controller. Verify with php artisan tinker before wiring it into policies.Where to look first when something misbehaves: the published config, then the package's migration (it defines the pivot/assignment tables and tells you whether writes are model-backed), then the service provider's Gate registrations.
Gate integration over custom checks. The package registers abilities on Laravel's Gate. Prefer $this->authorize('permission-name') in controllers and Gate::allows() in policies over calling package APIs directly — it keeps you swappable and makes Gate::fake()/Gate::before() work in tests.
Model-backed writes. Assignments are persisted through Eloquent models rather than raw cache mutations. Do role/permission changes inside transactions alongside the domain change they belong to (e.g. upgrading a plan and granting the entitlement in one DB::transaction), so a rollback doesn't leave a stale grant behind.
Queue workers and long-running processes. v0.0.1 fixes a stale Gate memo in workers. The pattern that stays safe: any job that mutates a user's roles/permissions should clear the resolved-ability cache before the next authorization check in that same worker, and jobs that assume a permission should re-check rather than capture the result at dispatch time. For Octane, do the same in a request-terminating or middleware hook if your config caches per-request.
Middleware for coarse gates, policies for fine ones. Use route middleware for "can this user reach this section at all", and policies for per-record checks. Mixing them (policy checks inside middleware) tends to double-resolve and mask which layer denied the request.
Testing. Because abilities live on Gate, standard Laravel tooling applies: Gate::fake() for unit tests, $this->actingAs($user) plus assertForbidden for feature tests. For the package's own tables, keep a factory-based seeder so tests don't depend on production role names.
"shipfastlabs/grant": "0.0.1") and read the diff before bumping; assume minor releases may change behavior until 1.0.config/grant.php against any env vars added or renamed.file or array store in tests versus redis in production can produce "works locally, denied in prod" reports. Assert the store explicitly in your test bootstrap.--parallel and publish the package's config or migrations in a test bootstrap, do the same — publish into a per-process temp path or keep the publish step out of the test suite entirely.Gate::after callback is enough) during rollout — permission packages fail closed, and a missing seed row looks identical to a wrong policy.How can I help you explore Laravel packages today?