Quickstart
This page takes you from composer require to a working, centrally-decided route. For the why behind each
step, follow the links into Core concepts and the guides.
1. Install
composer require padosoft/laravel-iam-client
php artisan vendor:publish --tag=laravel-iam-client-config
The service provider (IamClientServiceProvider) auto-registers on boot. It:
- builds the right
Deciderfromiam-client.modeand wraps it in the cache; - registers the
iam.canandiam.authmiddleware aliases — only if those names aren’t already taken; - registers the Gate adapter when
gate.enabledistrue.
2. Choose a transport
IAM_CLIENT_MODE=http
IAM_CLIENT_BASE_URL=https://iam.example.com/api/iam/v1
IAM_CLIENT_TOKEN=your-service-bearer-token
IAM_CLIENT_APP=billing
IAM_CLIENT_ORG=org_acme
The client POSTs each query to {IAM_CLIENT_BASE_URL}/decisions/check with a Bearer token.
IAM_CLIENT_MODE=local
IAM_CLIENT_APP=billing
IAM_CLIENT_ORG=org_acme
In local mode the client resolves the server’s AuthorizationEngine from the container and calls the PDP
in-process — no network round-trip.
IAM_CLIENT_APP and IAM_CLIENT_ORG become the default application and organization on every query, so
you don’t repeat them at each call site. See Configuration.
3. Protect a route
- Add the middleware
use Illuminate\Support\Facades\Route; // Permission only Route::get('/reports', [ReportController::class, 'index']) ->middleware(['auth', 'iam.can:reports:view']); // Permission bound to a route resource (ReBAC): "can edit THIS invoice" Route::put('/invoices/{invoice}', [InvoiceController::class, 'update']) ->middleware(['auth', 'iam.can:billing:invoices.update,invoice']); - Let the central PDP decide
iam.authreturns 401 when there’s no resolvable subject;iam.canreturns 403 when IAM denies —
or when a step-up is required but not yet satisfied. The,invoicesegment binds the decision to the
route’s{invoice}(including through route-model binding). - Keep your Laravel code
In a controller,$this->authorize('billing:invoices.update', $invoice)and@can('reports:view')in a
Blade view now consult IAM automatically — through the Gate adapter, no rewrite.
4. Ask IAM directly
use Padosoft\Iam\Client\Facades\Iam;
// ABAC: pass context facts; IAM evaluates the policy
if (Iam::can($user, 'warehouse:stock.adjust', ['amount' => 300, 'resource' => 'wh_milan'])) {
// approved
}
// Need the full decision (step-up, explanation)?
$decision = Iam::check($user, 'billing:invoices.delete', ['explain' => true]);
$decision->granted(); // permit AND no pending step-up ← gate on this
$decision->requiresStepUp; // true → ask the user to re-authenticate at a higher AAL
$decision->explanation; // why (when explain=true)
5. Verify
php artisan tinker
>>> $u = \App\Models\User::first();
>>> \Padosoft\Iam\Client\Facades\Iam::can($u, 'reports:view'); // true / false
>>> \Padosoft\Iam\Client\Facades\Iam::check($u, 'billing:invoices.delete', ['explain' => true])->explanation;
If the IAM server is unreachable, every decision is deny — by design. There is no fail-open switch.
Plan your deployment (caching, local mode, server HA) accordingly. See
Fail-closed authorization.