Step 08 · Verify everything works
Goal: confirm the whole thing is healthy with a short checklist you can re-run any time, then point you at
the deep guides and the production topology.
Step 8 of 8. The finish line — a green checklist that proves the control plane is up, deciding, and auditable.
The final checklist
- The schema is migrated
Expectphp artisan tinker --execute="echo Schema::hasTable('iam_grants') ? 'iam_grants ✅' : 'MISSING ❌';"iam_grants ✅. - The commands are registered
Expect thephp artisan list iamiam:*family (manifests, audit, reviews, least-privilege…). - Health & readiness respond (unauthenticated, with
php artisan serverunning)Expect an OK / ready response — no auth needed on these two.curl http://localhost:8000/api/iam/v1/health curl http://localhost:8000/api/iam/v1/ready - The audit chain is intact
Every mutation you made (manifest apply, grants) was hash-chained; this walks the chain and reports anyphp artisan iam:audit:verify
break. Expect a clean verification. - The IdP is live
Expect the discovery JSON with your issuer.curl http://localhost:8000/.well-known/openid-configuration - The PDP still decides correctly
php artisan tinker>>> $pdp = app(\Padosoft\Iam\Contracts\Authorization\AuthorizationEngine::class); >>> $pdp->check(['subject'=>['type'=>'user','id'=>'1'],'permission'=>'warehouse:stock.adjust'])['allowed']; => true // Alice >>> $pdp->check(['subject'=>['type'=>'user','id'=>'2'],'permission'=>'warehouse:stock.adjust'])['allowed']; => false // Bob (unless you granted him in step 06)
If those six checks pass, you have a self-hosted Identity & Authorization control plane: installed, migrated,
configured, populated via a governed manifest, assigned with grants, enforced at a route, and auditable —
end to end, on your own machine.
Optional — a live introspection page
Want the whole picture on one screen (installed packages, iam:* commands, migrated iam_* tables, and live
ALLOW/DENY like the official demo)? The demo ships a
controller that renders exactly this at /iam. Its source is a great template — it lists commands with
collect(Artisan::all())->keys()->filter(fn ($n) => str_starts_with($n, 'iam:')) and runs real
AuthorizationEngine::check() scenarios. Copy its IamDemoController if you want a dashboard.
What you built
Go to production — split server and client
This tutorial ran server and client in one app for learning. For real deployments:
Host laravel-iam-server as your IdP/PDP. Set explicit secrets (IAM_OAUTH_ENCRYPTION_KEY,
IAM_ADMIN_AUDIENCE), a real issuer, and back crypto with a KMS. See
Deployment and Configuration.
In every consuming app install laravel-iam-client in http mode
(IAM_CLIENT_MODE=http, IAM_CLIENT_BASE_URL=https://iam.example.com/api/iam/v1). The iam.can /
iam.auth aliases work directly there (no server in the app, so no alias collision).
Pin the token audience, keep idempotency on writes, and rate-limit. See
Securing the Admin API.
Schedule iam:audit:verify, iam:audit:checkpoint and iam:least-privilege:scan; wire observability.
See CLI reference and Observability.
Where to go next
- Core concepts — the mental model, if you skipped the theory.
- Authorization models — RBAC + ABAC + ReBAC, formally.
- ReBAC relationships — per-resource, relationship-based access.
- Access reviews & Access requests — the
governance suite. - Admin API reference — the full HTTP surface behind everything you did.
These six checks are your smoke test. Run them after upgrades or config changes to confirm the control plane
is still healthy.
Congratulations — you went from zero to a working, tested IAM. 🎉
Ready to host it? Turn this local setup into a real server your apps can use: