admin9/laravel-oidc-server
Laravel OIDC Server provides an OpenID Connect provider for Laravel apps, with discovery, JWKS, authorization code flow, and token endpoints. Add standards-based SSO and identity to your Laravel project with minimal configuration.
Architecture fit. Passport is an OAuth 2.0 authorization server built on league/oauth2-server; it has no first-class OpenID Connect layer. It issues JWT access tokens and stores them in oauth_access_tokens, but it does not ship an id_token, a discovery document, a JWKS endpoint (public keys are files in storage/), RFC 7662 introspection, or RP-initiated logout. This package's value proposition is closing exactly that gap without introducing a separate identity service. If our requirement is "make our existing Laravel identity provider consumable by standard OIDC relying parties" (SPAs, mobile, a second-party SaaS, Grafana/Jupyter/Sentry-style integrations), the architectural fit is good and the build-vs-buy calculus is favorable versus standing up Keycloak or Ory Hydra. If our requirement is enterprise IdP — SAML bridging, MFA orchestration, dynamic client registration, FAPI-grade flows — the fit is poor and this is the wrong layer.
Integration feasibility. Superficially low-effort: the package is a Passport extension, so client records, grants, scopes, and key material are reused. The real work is not installation but conformance. OIDC correctness lives in details Passport never had to care about: iss matching exactly (trailing-slash mismatches are the most common production break), nonce and at_hash/c_hash handling, azp and multi-audience rules, prompt/max_age/auth_time, rotating kids in JWKS, and PKCE. Whether the package achieves this by decorating Passport's response pipeline or by overriding AuthorizationController/TokenController determines everything downstream — the latter is a fork in all but name.
Technical risk. High, concentrated in three areas. (1) Upgrade coupling: Passport majors (11→12→13) and Laravel majors routinely reshuffle controller internals; an OIDC layer that subclasses them inherits that churn with no upstream guarantee. (2) Adoption signal: 6 stars, 0 dependents, single-maintainer optics means no observable production usage and no peer-reviewed failure modes — we would be an early adopter, effectively a co-maintainer. (3) Security surface: introspection and revocation endpoints are authenticated attack surface; a subtle bug in token lookup or client authentication is a token-disclosure class of defect. The future-dated release timestamp (2026-10-04) is worth clarifying with the maintainer — it may indicate a pre-release/tagged-ahead state rather than a shipped artifact.
Key questions.
composer.json constraints or tested in CI?kid rotation story with overlapping validity?Stack fit. Clean if the stack is Laravel 10/11/12 on PHP 8.2+ with Passport already installed and HTTPS terminated in front of the app. Two preconditions should be treated as gates: all OIDC traffic over TLS with a stable public issuer URL (not per-environment hostnames leaking into iss), and signing keys stored outside the repository with a documented rotation runbook.
Migration path. There is no data migration — the package reads existing Passport clients, scopes, and tokens. The migration is client-side: every relying party currently using the password grant or a bespoke token endpoint must move to authorization code + PKCE and validate id_tokens against our discovery document. Sequence that deliberately: inventory relying parties and their grant types first, because that list drives the timeline far more than the PHP work does.
Compatibility. Verify three things before committing: exact composer.json constraints against our pinned Passport/Laravel versions; whether the package's route registration respects our existing route prefixes and middleware groups (issuer paths must remain stable once published); and CORS behavior on /.well-known/openid-configuration, /jwks, and /userinfo, which browser-based clients will hit directly. Also confirm behavior behind a load balancer — iss and endpoint URLs must be derived from configuration, not Request::url(), or they will flap between nodes.
Sequencing. (1) Non-production spike: install, publish discovery/JWKS, drive one authorization-code + PKCE login from a test client, and diff the discovery document against the spec field by field. (2) Conformance pass: run the OpenID conformance suite or an equivalent contract test against the spike; treat any failure in nonce, at_hash, or iss as a stop-the-line item. (3) Pilot with a single low-blast-radius relying party — an internal dashboard, not a customer-facing app. (4) Harden: key rotation rehearsal, introspection load test, revocation propagation test. (5) Expand and only then document it as a platform capability. Budget the spike at 1–2 engineer-weeks and the full path at 4–8, with the honest possibility of concluding "fork and own it" or "buy" at gate 2.
Maintenance. This is the dominant cost and it is not the package's fault — it is the shape of the dependency. An OIDC layer pinned to Passport internals will lag every Laravel and Passport major, and with 0 dependents there is no community pressure to fix it quickly. Plan for a named owner, a fork in our namespace, and a standing budget of a few engineer-days per framework upgrade cycle. Pin the package to an exact version, not a caret range, and add a contract test suite that runs on every dependency bump — that suite, not the package's own tests, is our real safety net.
Support. No commercial support, no SLA, no observable issue-tracker throughput. Escalation path for a production auth outage is "our own engineer reads the source." That is acceptable for an internal-tooling IdP and unacceptable for a revenue-path login surface unless we accept the fork-and-own posture up front.
Scaling. Cheap where it matters: JWKS and discovery are static and should be cached aggressively at the edge; RS256 signing is negligible CPU. The scaling risk is introspection — if relying parties call it per request, each call becomes a token lookup against oauth_access_tokens, which turns a stateless JWT architecture into a database-bound one under load. Decide the contract explicitly: prefer local JWT validation at relying parties with short token lifetimes, and reserve introspection for revocation-sensitive callers, with rate limiting and a documented caching TTL on their side. Watch table growth and pruning of expired tokens.
Failure modes. Ranked by blast radius: (1) iss or endpoint URL drift after a deploy or proxy change — every relying party rejects every token, total login outage, and it is a configuration bug, not a code bug; (2) JWKS cache staleness at relying parties after key rotation without an overlap window — intermittent, maddening, environment-specific; (3) clock skew causing exp/iat/nbf rejections; (4) revoked-token propagation lag where relying parties validate locally and never call introspection; (5) logout that does not actually propagate — RP-initiated logout across a Laravel session cookie is genuinely hard, and "we have a logout endpoint" is not "sessions terminate everywhere," so scope that expectation with stakeholders early; (6) browser clients blocked by missing CORS on discovery/UserInfo.
Ramp-up. Modest but non-zero: the team needs working fluency in OIDC claim semantics and enough Passport internals to debug the override layer. Two engineers, a half-day on the spec's core sections plus a code walkthrough of the package's controllers, is realistic. The larger organizational ramp-up is with relying-party owners, who must each change their grant type and validation logic — socialize that as a platform migration with a deadline, not as a library install.
Overall. Worth a bounded spike, not a commitment. The gap it fills is real and the alternative (a dedicated IdP) carries its own operational weight, but the adoption signals here mean we should assume we are buying source code rather than a supported product. Recommendation: proceed to gate 2 with an explicit pre-agreed exit criterion — if the conformance run exposes id_token or discovery defects that require patching, decide then between forking under our ownership and moving to Keycloak/Hydra, rather than drifting into an accidental fork by default.
How can I help you explore Laravel packages today?