padosoft/laravel-iam-server

Server Laravel IAM: identity, organizations, Application Registry + manifest, PDP (RBAC+ABAC+ReBAC), OAuth (league/oauth2-server) + OIDC layer, audit tamper-evident, governance/IGA, Admin API + panel.

Maintainers

Package info

github.com/padosoft/laravel-iam-server

pkg:composer/padosoft/laravel-iam-server

Transparency log

Statistics

Installs: 360

Dependents: 4

Suggesters: 0

Stars: 1

Open Issues: 0

v1.21.0 2026-07-09 18:33 UTC

README

Laravel IAM

Laravel IAM — Server

A self-hostable Identity & Authorization control plane for Laravel.
An OAuth2 / OIDC identity provider, a RBAC + ABAC + ReBAC policy decision point, tamper-evident audit, IGA governance and an admin panel — in one composer package you own.

Tests Latest Version on Packagist Total Downloads PHP Version License

📖 Read the documentation →
Guides · concepts · architecture · Admin API & PHP reference

Why this package

Most teams end up with authorization scattered across every app: a spatie/permission table here, a pile of Gate::define() closures there, hand-rolled OAuth somewhere else, and no idea who can do what or who decided it. Renting an IdP (Auth0, Okta, Entra) fixes login but leaves authorization — and your audit trail — off in someone else's cloud, metered per MAU.

laravel-iam-server is the control plane you host yourself. It is at once:

  • an identity provider — OAuth2 (league/oauth2-server) + an OIDC layer, with sessions you can revoke;
  • a policy decision point (PDP) — one deterministic engine that answers "can subject X do permission Y on resource Z?" with RBAC + ABAC + ReBAC, deny-overrides, fail-closed, and a citable explanation;
  • a tamper-evident audit log — every mutation hash-chained and verifiable, exportable to your SIEM;
  • an identity governance (IGA) suite — access reviews, access requests/approvals, least-privilege recommendations, SoD;
  • an admin panel — a React console driven entirely through the Admin API (no UI ever touches the DB).

Apps stop owning authorization logic. They declare their permissions/roles/scopes in a manifest, and ask the PDP. You get one place to see and prove every access decision.

Features

  • Deterministic PDPNativeSqlEngine evaluates RBAC + ABAC (attribute conditions) + ReBAC (relationship lookups: listSubjects / listResources) in one pass, deny-overrides, fail-closed. Every Decision carries a decision_id, the matched policies and a human-readable explanation you can cite in audit.
  • Application Registry + manifests — apps submit a manifest of their permissions/roles/scopes/conditions; it is validated, diffed, approved, applied and rollback-able. The core hardcodes nothing.
  • Full OAuth2 + OIDC IdP — authorization-code/PKCE, client-credentials, refresh (encrypted), JWKS, an OIDC layer on an MIT base (never AGPL). Bring your own login backend (Fortify, Socialite, passkeys).
  • Application credential lifecycle — IAM issues the client_secret at manifest apply (one-time, hashed), with zero-downtime rotation (grace window), scheduled expiry + alerts, opt-in auto-rotation with app self-fetch, and revocation. Full guide: Application credentials & lifecycle.
  • private_key_jwt — asymmetric client auth, NO shared secret (RFC 7523 / OIDC §9). A client registers only its public key (JWKS) and proves itself by signing a short-lived, audience-bound, single-use (jti) ES256 assertion — nothing secret ever leaves the client, nothing to rotate or leak. Full guide: private_key_jwt.
  • Tamper-evident audit — hash-chained events (AuditChainAppender / AuditChainVerifier), SIEM export, webhooks/outbox, and GDPR crypto-shredding / legal-hold for PII.
  • Identity governance (IGA) — access-review campaigns, access-request approval flows, least-privilege recommendations, separation-of-duties, anomaly signals — each gated per layer/app/role/user via a feature scope.
  • Assurance / step-up — NIST 800-63B assurance levels; the PDP can require step-up (AAL2) for critical actions.
  • Admin API + panel — every admin route is documented in resources/openapi.yaml (enforced by a test), protected by the iam.can permission middleware, with idempotency keys on writes. The surface is complete: groups (with native ReBAC nesting), federated providers, directory sources, policy wizard, webhooks (with DLQ replay), metrics, and multi-step approver chains for access requests.
  • Observability — health/readiness endpoints and a pluggable tracer (NullTracer / LogTracer).

Use cases

  • Be your organization's IdP. Run OAuth2/OIDC login for all your apps, on infrastructure you control.
  • Centralize authorization. Many apps, one PDP: each asks check() instead of re-implementing roles.
  • Pass an audit. Hash-chained, verifiable history + access reviews and SoD give you the evidence compliance asks for.
  • Escape scattered gates. Migrate apps off ad-hoc Gate/spatie permissions onto declared manifests (see the migration bridge).

Web Admin Panel

A React + Vite + Tailwind console, driven only through the Admin API.

Dashboard (dark)

Dashboard — posture at a glance.

Applications & manifests Audit trail
Applications Audit
Roles & permissions Access reviews
Roles and permissions Access reviews
Policy playground Anomalies
Policy playground Anomalies

The full set of screens (users, sessions & tokens, organizations, events & webhooks, settings…) lives in art/screenshots/.

Installation

composer require padosoft/laravel-iam-server

Requirements: PHP 8.3+, Laravel 13. A database (MySQL/PostgreSQL/SQLite).

Publish config and run migrations:

php artisan vendor:publish --tag="laravel-iam-server-config"
php artisan migrate

The service provider auto-registers the Admin API, OAuth and OIDC routes, and the iam.can / iam.admin_auth / iam.idempotency middleware.

Quick start

1. Register an application and its manifest

Each consuming app declares what it needs. A manifest lists permissions/roles (slugs are immutable app_key:permission):

{
  "app_key": "warehouse",
  "permissions": [
    { "key": "warehouse:stock.read",   "label": "Read stock" },
    { "key": "warehouse:stock.adjust", "label": "Adjust stock",
      "condition": { "attr": "amount", "op": "<=", "value": 1000 } }
  ],
  "roles": [
    { "key": "warehouse:operator", "permissions": ["warehouse:stock.read", "warehouse:stock.adjust"] }
  ]
}

Submit it through the Admin API (POST /manifests), then approve and apply it — the registry validates and diffs before anything changes.

2. Ask the PDP

The decision point is the only authority on allow/deny. Build a DecisionQuery and call the engine:

use Padosoft\Iam\Domain\Authorization\Pdp\NativeSqlEngine;
use Padosoft\Iam\Domain\Authorization\Pdp\DecisionQuery;
use Padosoft\Iam\Contracts\Support\SubjectRef;

$decision = app(NativeSqlEngine::class)->decide(new DecisionQuery(
    subject: new SubjectRef('user', '42'),
    permission: 'warehouse:stock.adjust',
    organizationId: 'org_123',
    context: ['amount' => 500],   // evaluated by the ABAC condition above
    explain: true,
));

$decision->allowed;        // bool — deny-overrides, fail-closed
$decision->decisionId;     // citable in your audit log
$decision->explanation;    // why it decided this way
$decision->requiresStepUp; // true ⇒ ask the user for AAL2 first

3. Or over HTTP

curl -X POST https://iam.example.com/api/iam/v1/decisions/check \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"subject":"user:42","permission":"warehouse:stock.adjust","context":{"amount":500}}'

In your consuming apps you normally don't call the PDP directly — you install padosoft/laravel-iam-client and protect routes with its iam.can middleware / Gate adapter, which caches decisions and verifies JWTs.

Ecosystem

Package Role
laravel-iam-contracts Shared interfaces & DTOs — the dependency root
laravel-iam-server (this repo) The control plane: identity, PDP, OAuth/OIDC, audit, governance, Admin API & panel
laravel-iam-client PHP/Laravel client: OIDC login, JWT/JWKS, iam.can middleware, Gate adapter — 3 auth modes (static token · self-managed client_credentials + self-fetch · private_key_jwt)
laravel-iam-node Node/TypeScript SDK: decision checks + token verify; same 3 auth modes
laravel-iam-rust Rust SDK (async + blocking): decision checks + token verify; same 3 auth modes
laravel-iam-react-native React Native client + hooks (public client: PKCE, no shared secret)
laravel-iam-ai Optional AI module: advisory-only governance (redaction + hallucination guard + audit)
laravel-iam-directory Optional directory module: LDAP / Active Directory; SCIM in v2
laravel-iam-bridge-spatie-permission Migration bridge from spatie/laravel-permission: scan, shadow mode, decision diffing, cutover

Documentation

📖 Full documentation: doc.laravel-iam-server.padosoft.com — a searchable docmd site with 38+ pages: quickstart, concepts (RBAC/ABAC/ReBAC, deny-overrides, fail-closed, AAL, tamper-evident audit, multi-tenancy), architecture & ADRs, best practices, operations, and a complete Admin API and PHP API reference.

The full HTTP contract is in resources/openapi.yaml.

Security

Laravel IAM is fail-closed by design: default-deny, deny-overrides, and any error resolves to deny. Every mutation is hash-chained and verifiable (audit/verify-chain); cross-tenant access returns 404, not 403; secrets use envelope encryption and PII is crypto-shreddable. OAuth is league/oauth2-server and the OIDC layer is MIT (never AGPL). Please report security issues to security@padosoft.com rather than opening a public issue.

License

MIT © Padosoft. See LICENSE.