padosoft / laravel-iam-bridge-spatie-permission
Bridge di migrazione da spatie/laravel-permission a Laravel IAM: scan, manifest generation, shadow mode, decision diffing, cutover, rollback.
Package info
github.com/padosoft/laravel-iam-bridge-spatie-permission
pkg:composer/padosoft/laravel-iam-bridge-spatie-permission
Requires
- php: ^8.3
- padosoft/laravel-iam-client: ^1.0
- padosoft/laravel-iam-contracts: ^1.0
- padosoft/laravel-iam-server: ^1.0
- spatie/laravel-package-tools: ^1.16
- spatie/laravel-permission: ^6.0
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.18
- orchestra/testbench: ^10.0|^11.0
- pestphp/pest: ^3.0
- pestphp/pest-plugin-laravel: ^3.0
This package is auto-updated.
Last update: 2026-06-29 14:27:09 UTC
README
Laravel IAM — Spatie Permission Bridge
Migrate from spatie/laravel-permission to Laravel IAM without a big-bang cutover.
Scan your existing permissions, generate the IAM manifest, run both systems in shadow,
diff every decision, and switch over only when the diff is clean — with a rollback always one env var away.
Why this package
spatie/laravel-permission is a great in-app RBAC library — until you outgrow it. Multiple apps, a real
audit trail, ABAC/ReBAC conditions, governance and access reviews, an OAuth/OIDC provider: that's a
control plane, and that's Laravel IAM. But you can't
just flip authorization for a live application and hope. One wrong mapping and people are locked out of
production — or worse, let in.
This bridge makes the move boring and reversible. It treats migration as three observable phases:
- Inventory — read your Spatie roles/permissions (read-only, touches nothing) and turn them into an IAM manifest.
- Shadow — Spatie keeps deciding for real; IAM decides in parallel on every
Gatecheck and records only the mismatches. Nobody is ever blocked or let in by IAM during this phase. - Enforce — once the mismatch log is clean (or every divergence is explained), flip
IAM_SPATIE_MODEtoenforce. IAM becomes the authority; Spatie stays as a read-only cache. Roll back by flipping the env var back.
You cut over on evidence, not hope.
Features
iam:spatie:scan— read-only inventory ofspatie/laravel-permissionstraight from its tables (SpatieScanner). Emitsinventory.json+ areport.mdthat flags the smells: empty roles, orphan permissions, direct user grants, multiple guards.iam:spatie:manifest— generate alaravel-iam.manifest.v2from the inventory (ManifestGenerator), ready foriam:manifest:validate/iam:app:register.PermissionMapper— deterministic, idempotent slugging of Spatie names ("orders.refund","Manage Users") to IAM keys (^[a-z][a-z0-9_.-]*$); two names that collapse to the same key surface a semantic duplicate to review. Includes a startingriskheuristic for high-impact actions.ShadowGate— aGate::afteradapter that compares IAM vs Spatie on every ability and returnsnull, so it never changes the live outcome. It probes Spatie directly (hasPermissionTo) instead of trusting a possibly short-circuited gate result — so you never cut over on false-zero mismatches.RecordsMismatch/MismatchRecorder— a pluggable sink for divergences (structured log by default; swap it to push to a dashboard or review queue).- Reversible cutover —
shadow⇄enforceis a single env var. Read-only write-protection keeps Spatie consistent after cutover.
Use cases
- Prove decision parity to stakeholders before switching: run shadow in production traffic for a week, show a clean mismatch log, then cut over.
- Migrate app-by-app in a fleet: each application gets its own manifest and
IAM_SPATIE_APPprefix. - De-risk a compliance-driven move: keep the exact same enforcement behavior while you build confidence in the new control plane, with an instant rollback path.
Installation
composer require padosoft/laravel-iam-bridge-spatie-permission
php artisan vendor:publish --tag=iam-spatie-config
Requirements: PHP 8.3+, Laravel 13+, an existing spatie/laravel-permission install, and a
reachable Laravel IAM server (via padosoft/laravel-iam-client).
Quick start
The bridge ships in shadow mode by default (IAM_SPATIE_MODE=shadow) — installing it changes no
authorization behavior. Follow the runbook:
1. Inventory your current setup
php artisan iam:spatie:scan --output=storage/app/iam/spatie-inventory
# → inventory.json + report.md (roles, permissions, empty roles, direct grants, guards)
Open report.md and clean up the smells (inconsistent naming, semantic duplicates, critical permissions).
2. Generate the IAM manifest
php artisan iam:spatie:manifest --app=billing --name="Billing" \
--output=storage/app/iam/iam.manifest.json
The manifest is a proposal: review the inferred risk levels and roles, then validate it on the server:
php artisan iam:manifest:validate storage/app/iam/iam.manifest.json php artisan iam:app:register storage/app/iam/iam.manifest.json
3. Observe in shadow
With IAM_SPATIE_MODE=shadow, the ShadowGate is registered automatically. Every Gate check is mirrored
to IAM and divergences are logged as iam.shadow.mismatch:
// Your existing code — unchanged. Spatie still decides. Gate::authorize('orders.refund', $order); // In the background: IAM evaluates billing:orders.refund and logs only if it disagrees with Spatie.
Point the mismatch channel wherever your reviewers look:
IAM_SPATIE_APP=billing IAM_SPATIE_MISMATCH_CHANNEL=iam-shadow
4. Review mismatches & cut over
When the mismatch log is clean (or every entry is explained), flip the mode:
IAM_SPATIE_MODE=enforce
IAM is now the authority (enforcement comes from the client's Gate adapter); Spatie becomes a read-only
cache. Rollback is the same switch in reverse: set IAM_SPATIE_MODE=shadow and you are back to Spatie
deciding, instantly.
Ecosystem
| Package | Role |
|---|---|
| laravel-iam-contracts | Shared interfaces & DTOs — the dependency root |
| laravel-iam-server | The IAM server: identity, PDP (RBAC+ABAC+ReBAC), OAuth/OIDC, audit, governance, Admin API & panel |
| laravel-iam-client | Client for apps consuming Laravel IAM: OIDC login, JWT/JWKS, middleware, Gate adapter |
| laravel-iam-bridge-spatie-permission (this repo) | Zero-downtime migration off spatie/laravel-permission |
| laravel-iam-ai | Optional AI module: advisory-only governance (redaction + hallucination guard + audit) |
| laravel-iam-directory | Optional directory module: LDAP / Active Directory (LdapRecord); SCIM in v2 |
Documentation
A docmd doc-site lives in docs/: start at docs/index.md, then
Getting started, Concepts, the step-by-step
Migration runbook, and the Reference.
Security
Migration is fail-closed and non-destructive: the scanner is read-only, shadow mode never alters a live
decision, and decision diffing uses deny-overrides — when in doubt, deny. Permission and role slugs are
immutable (app_key:permission). If you discover a security issue, email security@padosoft.com
rather than opening a public issue.
