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

Laravel Warrant Laravel Package

patrickhanna/laravel-warrant

Laravel Warrant is a lightweight authorization package for issuing and validating signed, expiring warrants that grant access to specific actions or resources. It keeps permission checks explicit and secure, making capability-style access easy to integrate into Laravel apps.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and publish the package assets:

composer require patrickhanna/laravel-warrant
php artisan vendor:publish --provider="Warrant\WarrantServiceProvider"
php artisan migrate

Add the ability trait to the models that should hold permissions (typically User, plus whatever you scope against — Team, Project, Post):

use Warrant\Concerns\HasWarrantAbilities;

class User extends Authenticatable
{
    use HasWarrantAbilities;
}

Where to look first: the published config/warrant.php (table names, morph map, cache settings) and the package migrations. Since the package is small and low-adoption, read src/ before trusting any blog post — the source is a 10-minute read and is the real documentation.

First use case: replace a hardcoded gate with a database-defined ability. Instead of:

Gate::define('post.publish', fn (User $user) => $user->is_admin);

seed an ability and check it the same way you already check gates:

Warrant::createAbility('post.publish');

// later, anywhere
if ($user->can('post.publish')) { ... }

The win is that the ability list, and who holds it, becomes data you can change per environment (or per tenant) without a deploy.

Implementation Patterns

Define abilities in a seeder, not in code. Keep ability names in one place and make the seeder idempotent (firstOrCreate on the slug) so it's safe to re-run:

foreach (['post.view', 'post.create', 'post.update', 'post.publish', 'post.delete'] as $name) {
    Warrant::createAbility($name);
}

Roles as bundles, abilities as the unit of check. Assign abilities to roles, roles to users, and always authorize against the ability — never the role — in application code. That way adding a role later doesn't require touching controllers.

$editor = Warrant::createRole('editor');
$editor->attachAbilities(['post.create', 'post.update']);

$user->assignRole('editor');

Instance-scoped checks are the reason to use this package. The valuable pattern is granting an ability on a specific record rather than globally:

$user->allow('post.update', $post);
$user->can('post.update', $post);   // true
$user->can('post.update', $otherPost); // false

This maps cleanly onto team/multi-tenant setups: give the user post.update scoped to $team, and let the policy translate a request for a Post into a check against $post->team.

Bridging into existing Policies. Your policies still do the domain reasoning; Warrant answers "is this person permitted in principle." A typical policy method:

public function update(User $user, Post $post): bool
{
    return $user->can('post.update', $post->team)
        && ! $post->is_locked;
}

Keep authorize() and Gate in your controllers — the package should be an implementation detail of Gate::allows, not a parallel authorization path.

Route middleware and Blade for the coarse checks, policies for the fine ones:

Route::post('/posts/{post}/publish', PublishController::class)
    ->middleware('can:post.publish,post');

Testing. Seed the abilities you need inside the test rather than loading the production seeder, and assert both the positive and negative case — permission systems fail open more often than they fail loudly:

$user->allow('post.update', $post);
$this->actingAs($user)->put("/posts/{$post->id}")->assertOk();

Gotchas and Tips

  • A failed ability check returns false, not an exception. A typo in 'post.publish' is indistinguishable from "not permitted." Centralize ability names as constants or an enum and reference those everywhere.
  • Cache invalidation bites after seeding. If the config enables ability caching (check config/warrant.php), re-running seeders or editing rows directly in the DB will look like a no-op. Clear the cache after any out-of-band change, and in tests, flush between cases.
  • N+1 on index pages. Rendering a list with a per-row $user->can('post.update', $post) check will fire a query per row unless assignments are eager loaded or the check falls back to a cached role map. Load the user's roles/abilities once per request.
  • Unsaved or unkeyed models. Instance-scoped checks on a model without a primary key can't resolve to a scoped row — make sure you're checking against a persisted model, or fall back to a global check plus a policy condition.
  • Polymorphic scoping and morph maps. If your scoped entities are stored polymorphically, configure Relation::enforceMorphMap() before seeding any Warrant rows. Changing morph aliases later orphans existing assignments.
  • Super-admin fallback. Add a Gate::before that grants everything to your admin role, rather than granting every ability individually — it keeps the ability table honest about what normal users can do.
  • Pin the version. With 14 stars and dependents: 0 there's effectively no community knowledge base; expect to read the source to answer your own questions. Treat the package as a small piece of vendored infrastructure: pin an exact version in composer.json, and cover your authorization matrix with tests so a future Laravel upgrade that breaks the package shows up as a red test rather than a production hole.
  • Migration ordering. The package migrations must run before any seeder that inserts abilities; check the timestamp prefix if the package tables aren't there yet on a fresh install.
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.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums