postiefs/laravel-sso
postiefs/laravel-sso is a Laravel package for adding single sign-on to your app. It provides the building blocks to connect an SSO provider, streamline authentication, and keep login flows consistent across Laravel projects.
Architecture fit
This is a thin authentication adapter, not an identity system. It adds no tables, owns no roles, and delegates all user persistence to a UserResolver contract. That is the strongest architectural signal in the release: the package can be layered onto an existing users table, an existing RBAC setup (explicitly: spatie/laravel-permission), and existing policies without a schema change or backfill.
The flow is portal (Entra ID) → launch token → callback route → token verification → resolver → Laravel session with an absolute deadline derived from sexp. Sessions are portal-controlled and non-extendable.
Three middleware aliases (sso, sso.auth, sso.session) give three distinct enforcement points — initiate SSO, require an SSO session, enforce deadline/heartbeat. That maps cleanly onto route-group-level adoption and supports incremental rollout rather than a flag day.
The UserResolver contract is the only meaningful extension seam, and it is where the entire account-linking policy lives. Architecturally that is correct; operationally it means identity decisions are per-app and can diverge across the fleet unless someone owns a standard.
Integration feasibility
Low friction. composer require, sso:install, sso:check is about as cheap as Laravel onboarding gets, and shipping a diagnostic command with v1.0.0 is a genuine adoption accelerant — it turns "is my config right" into a command instead of a support ticket.
Zero migrations is a serious de-risker: no schema lock, no DBA review of data changes, no rollback plan, and security review is scoped to config plus secrets.
LaunchToken as a test helper and the SsoUserCreated / SsoLoggedIn / SsoSessionEnded events mean teams can write feature tests and wire audit logging without forking the package.
The one real front-end commitment is @ssoSessionGuard. It's trivial in Blade; it is an open question for Inertia/Livewire/SPA front-ends that don't render server-side Blade on every page.
Hard constraint: PHP 8.2+ and Laravel 11/12/13. Laravel 11 as the floor excludes Laravel 10 apps — the most likely blocker across an existing portfolio.
Technical risk
check_interval plus outage duration. Needs a documented sign-off and, ideally, a fail-closed option for privileged surfaces..env) are unaddressed in these notes and are the top pre-production verification item.Key questions
check_interval configurable per app / route group, and can we opt into fail-closed?sexp and the ended route?@ssoSessionGuard isn't rendered per page?Stack fit
Good fit for conventional Laravel monoliths on Laravel 11+ with Blade-rendered authenticated areas. The package sits beside existing auth rather than replacing it, so apps can keep local login for service accounts, break-glass admins, or machine access while SSO covers human users. Authorization stays in the app, which is where most teams already want it. Poor fit where the app is Laravel 10, where the front-end is SPA-first with no server-rendered shell, or where a hard requirement exists for fail-closed session validation.
Migration path
The absence of migrations makes the migration path unusually cheap in both directions:
sso middleware to a single route group; leave everything else on existing auth.UserResolver at existing users, or supply a custom resolver if account linking must be stricter than email match.Rollback is composer remove plus middleware removal — no schema to unwind, no data to reconcile. That is a legitimate selling point to risk committees and should be stated explicitly in the rollout plan.
Compatibility
composer.json.sso composes with them rather than replacing the default guard.Sequencing
sso:check in CI and a runbook entry.SsoSessionEnded and the check-failure path into existing logging/alerting.Maintenance
Very low surface area: no schema, no background jobs described, no scheduled tasks beyond sso:check as a manual or CI diagnostic. The package's real maintenance cost is configuration drift across apps — diverging resolver logic, divergent check_interval values, and diverging secret handling. Assign one owner for the shared policy and one for each app's resolver.
Support
Introduces a two-tier support boundary that must be explicit in the runbook: the portal/Entra ID team owns token issuance and availability; each app team owns resolver config and route wiring. sso:check should be tier-1's first diagnostic. Because v1.0.0 ships only a docs folder — no stated support SLA, changelog policy, or issue tracker commitment — the TPM should get a vendor support expectation in writing before this becomes load-bearing.
Scaling
Two cost centers. First, heartbeat and /auth/check-access traffic: at 10k concurrent users with check_interval = 300s, that's roughly 33 requests/second sustained against the portal, plus the same order of magnitude against your own endpoints. Shortening the interval for fresher revocation scales linearly and should be treated as a capacity decision, not a security knob to tune per app. Second, the single-use token store: it needs to be shared, fast, and durable enough that a flush doesn't open a replay window. Both need load testing at realistic concurrency before fleet rollout.
Failure modes
| Failure | Behavior | Blast radius |
|---|---|---|
| Portal unavailable | Existing sessions persist (fail-open); new logins fail | All new sign-ins blocked; existing users unaffected |
| Secret rotation / mismatch | Token verification fails | 100% login failure from a single config error |
| Cache/state store flush | Single-use guarantee may lapse | Replay window; silent |
| Email changed in Entra ID | New local user created by default resolver | Silent duplicate accounts, orphaned permissions |
| Callback URL misconfigured | Stray token logged and forwarded | User sign-in loop; token-handling question |
| Clock skew | exp validation failures |
Intermittent, hard to diagnose |
sexp reached mid-form |
Hard logout, no extension | Data loss on long forms |
The asymmetry in the first row matters for the runbook: a portal outage looks like "everything is fine" to logged-in users and "nothing works" to anyone arriving fresh.
Ramp-up
For a single app on a supported Laravel version: roughly 1–2 engineer-days including resolver, tests via LaunchToken, and sso:check in CI. Add time for secret management integration, session-ended UX, and observability wiring — those are app-specific and will dominate the estimate on the first app. The second and subsequent apps should be well under a day if the linking policy is already standardized.
How can I help you explore Laravel packages today?