PHPackages                             fissible/vouch - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. fissible/vouch

ActiveLibrary

fissible/vouch
==============

Laravel authentication with password, OTP, MFA, and recorded session assurance.

v0.1.1(today)01↑2900%MITPHPPHP ^8.4CI failing

Since Aug 28Pushed todayCompare

[ Source](https://github.com/fissible/vouch)[ Packagist](https://packagist.org/packages/fissible/vouch)[ RSS](/packages/fissible-vouch/feed)WikiDiscussions main Synced today

READMEChangelog (1)Dependencies (18)Versions (4)Used By (0)

Vouch
=====

[](#vouch)

**Vouch** — authenticates your users to the degree you need. What they may do stays yours.

Vouch is Laravel authentication with password, OTP, MFA, and recorded session assurance behind one policy engine. It orchestrates authentication factors and step-up; it does not reimplement their cryptography or protocols.

Vouch is not an authorization package, token storage, or a UI. Your application or its authorization package decides who may act; Vouch records how strongly that person authenticated and can require a stronger session for that action. Token issuance and token assurance are planned for 2.4, and presentation remains the host application's responsibility. OIDC and federation are not planned.

Requirements and maturity
-------------------------

[](#requirements-and-maturity)

Vouch requires PHP ^8.4 and Laravel 13 components (`illuminate/*` ^13.0). It is pre-1.0 software: account lifecycle and assurance work ships in Phase 2.3, the token-issuance gate is planned for 2.4, and standard UI adapters are Phase 3 work. See [the roadmap](PROJECT.md) for those phases.

Its account-lifecycle services cover identifier verification, credential recovery, first-credential enrollment, and credential self-service. The host still supplies presentation and application policy.

Install and adopt
-----------------

[](#install-and-adopt)

Install the package:

```
composer require fissible/vouch
```

Publish the configuration and migrations, then configure the package before enabling login:

```
php artisan vendor:publish --tag=vouch-config
php artisan vendor:publish --tag=vouch-migrations
php artisan migrate
php artisan vouch:doctor
```

Before adding an assurance map or a direct assurance route, set `VOUCH_STEP_UP_URL` to the host's routeable step-up presentation. Vouch does not ship a step-up page. If an interactive request is refused and this value is unset, Vouch deliberately throws a `RuntimeException` (a 500 response) rather than redirecting a browser to its POST-only endpoint.

`vouch:doctor` checks adoption readiness as aggregate state; it never accepts an identifier. Before login is live, verify identifier control through `IdentifierVerifier`, bind real `OtpDelivery` and `DeliveryEconomics`implementations, and run a durable asynchronous queue worker for `vouch.otp.queue`. If CAPTCHA escalation is enabled, bind `CaptchaVerifier` as well. The full prerequisite staircase, queue operation, and maintenance commands are in [the operations guide](docs/operations.md).

Compose authorization with assurance
------------------------------------

[](#compose-authorization-with-assurance)

Vouch deliberately leaves authorization to the host. For a host using `spatie/laravel-permission`, the authorization middleware decides whether the user has `invoices.approve`; Vouch's ability map says that this same ability needs an `aal2` session. The route uses the host package's permission rule; the map is central, so the assurance requirement is not repeated on each route.

Laravel 11+ hosts register Spatie's middleware alias themselves, for example in `bootstrap/app.php`:

```
use Illuminate\Foundation\Configuration\Middleware;

->withMiddleware(function (Middleware $middleware): void {
    $middleware->alias([
        'permission' => \Spatie\Permission\Middleware\PermissionMiddleware::class,
    ]);
})
```

```
use App\Http\Controllers\ApproveInvoiceController;
use Illuminate\Support\Facades\Route;

Route::post('/invoices/{invoice}/approve', ApproveInvoiceController::class)
    ->middleware(['permission:invoices.approve']);
```

Spatie also ships a static helper that skips the alias entirely, which is worth knowing if you would rather not claim the generic name `permission` in your application's alias table:

```
use Spatie\Permission\Middleware\PermissionMiddleware;

Route::post('/invoices/{invoice}/approve', ApproveInvoiceController::class)
    ->middleware([PermissionMiddleware::using('invoices.approve')]);
```

Vouch reads either form: the ability names come from the middleware parameters on the matched route, and the alias is resolved through the router's own table.

```
// Published Vouch configuration
'assurance_requirements' => [
    'invoices.approve' => 'aal2',
],
```

The package's `vouch.ability` middleware reads the authorization declarations on the matched route and applies the strongest mapped requirement. It only refuses or sends a browser to the configured `vouch.step_up.presentation_url`; it never grants permission. This means you can use the same map with plain Laravel Gates, Spatie permission middleware, or another authorization system that exposes ability names on routes.

Enforcement boundary
--------------------

[](#enforcement-boundary)

Vouch adds `vouch.ability` to the `web` and `api` middleware groups only. A protected route in another or custom group must add `vouch.ability` explicitly, or it is not covered by route enforcement. Run `php artisan vouch:assurance-map`and inspect its `enforced_groups` field after configuring middleware, rather than assuming a host's group is protected.

For a direct requirement on one route or group that is not derived from an ability map, use the `vouch.assurance` alias, for example `->middleware('vouch.assurance:aal2')`. It has the same presentation-URL prerequisite as the map middleware.

The `Gate` hook is defense in depth, not the enforcement point. An earlier `Gate` hook can grant an ability and bypass a later hook, so only the route middleware can enforce the mapped assurance before that grant short-circuits the check. The measured package-specific paths and their limits are documented in the [authorization integration survey](docs/authorization-integration-survey.md).

For an authenticated request with no Vouch session, a mapped route returns a 403 response with `insufficient_assurance`; it does not evaluate a bearer token or fail open. That remains the boundary until 2.4 adds token assurance.

Strict maps
-----------

[](#strict-maps)

Set `vouch.assurance_strict` only after listing the host's intentional ability vocabulary in `vouch.declared_abilities`. Strict mode cannot use `Gate::abilities()` for that list: it is empty at boot for abilities defined only at runtime, and it does not enumerate policy methods or database-backed permissions. A host that defines an ability solely with `Gate::define` must still list it in `vouch.declared_abilities` when strict mode is enabled.

Host integration blind spots
----------------------------

[](#host-integration-blind-spots)

`php artisan vouch:assurance-map --json` reports `user_model_routes_to_gate`. Treat a false result as a coverage warning: a model using Bouncer's `Authorizable` trait can silently take over `can()` and stop that method reaching the Gate, without an error. The report can expose that model seam, but it cannot detect `Bouncer::runBeforePolicies()` at all. That switch moves Bouncer's grant into its before slot, where it can bypass a later deny-only hook; keep the route middleware as the enforcement boundary.

See [operations](docs/operations.md) for adoption and runtime operation, and the [authorization integration survey](docs/authorization-integration-survey.md)for the measured Spatie, Bouncer, and Gate behavior behind these limits.

###  Health Score

39

—

LowBetter than 84% of packages

Maintenance100

Actively maintained with recent releases

Popularity2

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity43

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

0d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/ef298fbffac2225e36ab3a6e089af020f76885bc65d5f6afda831c64939e1e4b?d=identicon)[fissible](/maintainers/fissible)

---

Top Contributors

[![fissible](https://avatars.githubusercontent.com/u/1410914?v=4)](https://github.com/fissible "fissible (481 commits)")

###  Code Quality

TestsPest

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/fissible-vouch/health.svg)

```
[![Health](https://phpackages.com/badges/fissible-vouch/health.svg)](https://phpackages.com/packages/fissible-vouch)
```

###  Alternatives

[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9922.4M148](/packages/roots-acorn)[laravel/ai

The official AI SDK for Laravel.

1.1k4.6M343](/packages/laravel-ai)[mike-bronner/laravel-model-caching

Automatic caching for Eloquent models.

2.4k161.4k2](/packages/mike-bronner-laravel-model-caching)[flarum/core

Delightfully simple forum software.

211.5M2.5k](/packages/flarum-core)[forjedio/inertia-table

Backend-driven dynamic tables for Laravel + Inertia.js

272.0k](/packages/forjedio-inertia-table)[aedart/athenaeum

Athenaeum is a mono repository; a collection of various PHP packages

265.2k](/packages/aedart-athenaeum)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
