ajgarlag/openid-connect-provider-bundle
A Symfony bundle that adds OpenID Connect Provider support on top of league/oauth2-server-bundle, providing standards-compliant discovery and RP-initiated logout endpoints with configurable routes and sensible defaults.
Revised for 0.3.0. Prior assessment was against 0.2.7.
The core finding is unchanged: this is a Symfony bundle, not a Laravel package. A Bundle class, a DependencyInjection extension, a config tree, PHP-route files loaded via config/routes/*.yaml, and hard runtime coupling to league/oauth2-server-bundle and Doctrine mapping passes. None of that surface exists in Laravel, and 0.3.0 did not move in that direction — the new "custom clients" capability is a Symfony DI tagged-service extension point, which is even more framework-bound than what came before.
0.3.0 requires league/oauth2-server-bundle:^2, a major-version jump in the one dependency that owns the actual OAuth2 state machine, client storage, and grant handling. The bundle is thin — that is its virtue — but thin means most of your upgrade risk lives one layer down.0.3.0 adds two items worth copying into any port: kid in the JWKS payload (the prerequisite for overlapping-key rotation) and a pluggable client-resolution abstraction. A Laravel team should treat this repo as a conformance checklist and reference design, not a dependency.| Risk | Severity | Change since 0.2.7 | Evidence |
|---|---|---|---|
| Bus factor = 1 | High | Unchanged | Every PR in 0.3.0 (#28, #30, #34, #39, #40) authored by @ajgarlag. Five releases of consistent solo authorship is now a pattern, not a data point. |
| Dependency major bump in a minor release | High | New | 0.3.0 adopts league/oauth2-server-bundle:^2. That is a breaking change to your transitive dependency graph delivered under a 0.x minor. Consumers must migrate the League layer and then take this bundle. |
| Narrowing support matrix | High | Worsened | 0.2.4 dropped Symfony 7.2/7.3 in a patch; 0.3.0 "completes Symfony 8.0 removal from workflows." Tested surface now appears to be Symfony 7.4 only. Verify before assuming 8.0 compatibility. |
| Pre-1.0, breaking changes permitted | High | Unchanged (structurally) | 0.2.0 renamed ClaimsResolveEvent → UserClaimsResolveEvent. 0.3.0's dependency bump is the same hazard by proxy. |
| No production evidence | High | Unchanged | 9 stars, 0 dependents. Still no named adopter. |
| Documentation still "TBD" | Medium-High | Unchanged | No docs PR in this release. The kid and custom-client features ship undocumented beyond the changelog line. |
| Key lifecycle | Medium-High → Medium | Improved | kid now appears in the JWKS payload (PR #30), which is the hard prerequisite for publish-both-keys rollover. The plumbing gap is closed; the policy/tooling gap (rotation schedule, overlap window, KMS custody) remains yours to build. |
| Client onboarding | Medium → Medium | Partially improved | Custom-client support (PR #28) makes it feasible to back clients with your own registry/repository instead of static Doctrine entities. It is not dynamic client registration — onboarding is still a human, out-of-band process. |
| No PKCE guidance | Medium-High | Unchanged | Still unmentioned; still mandatory-in-practice for public clients. Must be configured in the League layer. |
| Scope gaps | Medium | Unchanged | No dynamic client registration, no PAR, no DPoP/mTLS, no introspection/revocation surface described; Implicit Flow still present. |
| Conformance evidence | Medium-High | Unchanged | No OpenID Foundation Conformance Suite results in-repo. |
| Metadata anomaly | Low-Medium | Unchanged | Changelog still carries a release date inconsistent with its contents — verify supply chain before adoption. |
Net read: 0.3.0 is a substantive release, not a housekeeping bump. Two of the three highest-severity technical gaps from the prior assessment (key rotation plumbing, rigid client storage) were directly addressed. The maintainer is responsive and reading the same gap list a reviewer would. But it also introduced a fresh integration risk (League v2 migration) and tightened the framework window again — so the risk profile is flatter, not uniformly lower.
0.3.0 removed Symfony 8.0 from CI. Confirm 7.4-only before planning. If we are on 8.0, this bundle is now a non-starter without a fork.league/oauth2-server-bundle to v2 in lockstep? This is the new gating question. Scope the League v2 delta (breaking changes in grant types, client repository interfaces, token storage) before committing to 0.3.0.kid exists? The bundle publishes kid; it does not schedule rotation, publish overlapping keys, or retain retired keys. That runbook is ours.Recommendation matrix for a Laravel target — unchanged, with a note on why Option C got marginally better:
| Option | Fit | Effort | Verdict |
|---|---|---|---|
| A. Delegate to a dedicated IdP (Keycloak, Ory Hydra, Authentik, Zitadel) | Excellent | 2–3 wks integration | Still the default. 0.3.0's improvements close gaps that a mature IdP already closed years ago. |
B. Laravel-native OIDC provider on Passport / league/oauth2-server |
Good | 3–5 wks incl. conformance | Viable when policy forbids an external IdP. |
| C. Port this bundle's OIDC layer into Laravel | Poor-to-moderate | 6–10 wks | Slightly more attractive as a design source: kid-aware JWKS and a pluggable client resolver are both patterns worth lifting. Still bad as a code port. |
| D. Install as-is | None | — | Not possible on Laravel. |
For a Symfony target, Option D becomes viable and is now more viable functionally — but the entry cost rose, because 0.3.0 drags league/oauth2-server-bundle v2 into the upgrade. Budget 2 days of spike for the bundle itself plus 3–5 days for the League v2 migration if you are currently on v1.
If pursuing a port (Option B/C), the phased plan from the prior assessment holds; two phases need revision:
kid in every JWK from day one, even with a single key. Retrofitting kid after clients have cached a kid-less JWKS is an avoidable outage. Design the JWKS handler to serve an array of keys, not one.iss, sub, aud, exp, iat, auth_time, nonce, plus at_hash/c_hash. Set the JWT header kid to match the JWKS entry used to sign. nonce echoes only if present in the request (upstream fixed this in 0.2.5 — inherit the fix).UserClaimsResolving event/listener analogue to UserClaimsResolveEvent. Still the single best design idea in the repo.id_token_hint, post_logout_redirect_uri, state, and sid matching. Highest historical bug density (0.2.1 sid comparison, 0.2.5 error messages). Budget test time.0.3.0 on Symfony, upgrade league/oauth2-server-bundle to v2 first, in isolation, behind the existing bundle version if possible. Do not conflate the League v2 migration with an OIDC feature change — you will not be able to attribute regressions.0.3.0, not ^0.3. The maintainer has a demonstrated record of dropping framework support in patch releases and shipping dependency majors in minors.sid being correctly embedded from the ID-token step and on a session store consistent across auth and logout hosts.0.3.0 is the clearest evidence yet that this library is actively developed — five PRs, two of them addressing gaps a reviewer would flag. That is reassuring on responsiveness and unchanged on durability: still one maintainer, still pre-1.0, still no dependents to absorb the QA burden. Budget 2–4 days per release cycle for compatibility review, plus a larger one-off for the League v2 jump.kid now understood — you can implement key rotation properly from the start rather than inheriting an ambiguous story.0.3.0 shipped two user-facing capabilities (kid, custom clients) with no documentation beyond a changelog bullet. Onboarding cost is unchanged: an OIDC-spec-literate engineer reading source.kid published in JWKS, overlapping-key rotation is now implementable. The remaining gap is policy and custody: rotation schedule, overlap window ≥ one token lifetime, retention of retired keys for in-flight validation, and a KMS/HSM or encrypted versioned key store. This is now an engineering task you can schedule rather than an unresolved design question — that is a real de-risking.kid absent or mismatched (new) → RPs that cache JWKS by kid fail validation outright; some fail silently. Always emit kid; always match the JWT header to the JWKS entry; alert on signing-key/kid divergence.kid rotation behind a CDN → clients serve a stale JWKS and reject newly signed tokens. Set explicit cache headers and shorten TTL around rotation windows.sid mismatch on logout → session not terminated at the RP; a silent, security-relevant failure. Regression-test explicitly; upstream has had two bugs here.nonce not echoed / mis-echoed → replay surface or client-side rejection. Upstream fixed this in 0.2.5.exp/iat/auth_time → intermittent failures that read as flakiness. Allow ±60s and monitor.Recommendation stands: use this repository as a design reference and conformance checklist, not as a runtime dependency in a Laravel product — Laravel remains structurally impossible. For a Symfony product, 0.3.0 upgrades the package from "unproven and missing the key-rotation primitive" to "unproven but architecturally sound." The kid and custom-client additions remove two of the three reasons a TPM would have said no on technical grounds; the remaining objections are non-technical — one maintainer, no production evidence, no docs, and a support matrix that has narrowed three times in five releases, most recently to Symfony 7.4 only.
If the strategic goal is "we are an OIDC Provider," the default recommendation is still a dedicated IdP, with engineering budget spent on integration and conformance rather than on owning a nascent library. Reserve this bundle for the case where policy forbids an external IdP and the team is on Symfony 7.4 and can fund a fork-and-own decision — in which case 0.3.0 is a meaningfully better starting point than 0.2.7 was.
How can I help you explore Laravel packages today?