spomky-labs/oauth2-server-exception-manager
Converts League OAuth2 Server exceptions into proper HTTP responses for PHP applications. Provides customizable error rendering so your API returns consistent, standards-compliant OAuth2 error output instead of raw exceptions. Lightweight, PSR-friendly, and easy to integrate into any framework.
Architecture fit. spomky-labs/oauth2-server-exception-manager is not a Laravel package — it is a single-purpose PHP utility from the Spomky-Labs OAuth2 framework family. Its scope is narrow: it takes thrown OAuth2 exceptions and renders them as RFC 6749 §5.2 / RFC 6750-compliant error payloads (correct error/error_description/error_uri fields, HTTP status codes, and WWW-Authenticate headers for bearer-token failures). In a Laravel application this maps to a responsibility Laravel already owns: App\Exceptions\Handler (or bootstrap/app.php's withExceptions) plus a renderable exception contract. The library therefore fits either as (a) a renderer invoked from a custom exception handler, or (b) a small piece of logic we reimplement in ~50–100 lines. It is a poor fit if our OAuth2 server is Laravel Passport or league/oauth2-server, because the exception hierarchy is different — Passport throws League\OAuth2\Server\Exception\OAuthServerException, not the Spomky type this manager consumes.
Integration feasibility. The code surface is small (an interface plus a concrete manager and a handful of value objects), so the integration itself is low-effort — hours, not weeks. The friction is entirely in the dependency graph. The manager pulls in the Spomky OAuth2 server exception types, which in turn imply PSR-7/PSR-15 implementations. Laravel does not speak PSR-7 natively; we would need symfony/psr-http-message-bridge or a manual conversion from the returned PSR-7 response into an Illuminate\Http\JsonResponse. That adapter is trivial but permanent.
Technical risk. High, and dominated by vendor risk rather than code quality. Zero stars, zero dependents, and no visible release activity are strong abandonment signals; the parent spomky-labs/oauth2-server line was itself superseded by the OAuth2 Framework specification packages and the broader ecosystem's consolidation on league/oauth2-server. Concrete concerns:
psr/http-message, and laminas/* vs guzzlehttp/psr7 when installed alongside modern Laravel (10/11) and Passport.Key questions. (1) Which OAuth2 server are we actually operating — Passport, a Spomky-based Symfony service, or a third-party IdP? (2) Do external clients depend on RFC-exact error bodies and WWW-Authenticate semantics, or is machine-readable error shape a nice-to-have? (3) Is the OAuth2 server co-located in the Laravel app or a separate service? (4) Are we willing to own a fork, or is the behavior small enough to port? (5) What is the compliance driver — is this for a security review / pen-test remediation?
Stack fit. Confirm the server first, because it decides everything. If our token issuer is a standalone Symfony/Spomky service, this library belongs there, not in the Laravel app — Laravel should stay a resource server validating tokens via introspection or JWKS. If the Laravel app itself issues tokens, Passport is the idiomatic choice and this package is redundant: Passport already produces RFC-compliant OAuthServerException responses. The only legitimate adopt scenario is an existing Spomky-based issuer we are extending.
Migration path. Do not install it as a hard dependency in application code. Wrap it: define an internal OAuthErrorRenderer interface, implement it once with this library, and keep a hand-rolled fallback implementation behind the same interface. If the package later proves unmaintained or breaks on a PHP upgrade, we swap the binding with no call-site changes. This also makes the eventual fork a one-file change.
Compatibility. Pin and verify before committing: PHP constraint (expect 7.x/8.0-era code), psr/http-message major version, and whether it drags in a full PSR-7 implementation. Run composer why-not against the target Laravel version in a scratch branch as a day-one spike. Expect to either relax constraints in a fork or vendor the source into app/Support/OAuth.
Sequencing.
composer require in a throwaway branch, record conflicts.render() in the exception handler.invalid_request, invalid_client, invalid_grant, unauthorized_client, unsupported_grant_type, invalid_scope, plus bearer invalid_token/insufficient_scope.Maintenance. Effectively unmaintained upstream; adopting it means we own it. Budget for an annual compatibility review (PHP minor upgrades, PSR version bumps) and treat a fork as the likely steady state within 12 months. Contrast that with a native implementation whose maintenance cost is near zero because it has no dependencies beyond the framework.
Support. No community, no issue triage, no CVE process. Support is entirely internal — one engineer must be able to explain every branch of the mapper. This is acceptable only because the domain is small and well-specified by RFC 6749/6750; it would be unacceptable for anything larger.
Scaling. Negligible. The code runs on the error path only, does no I/O, and adds microseconds to failing requests. No horizontal-scaling, caching, or queueing implications. The real scaling concern is organizational: a dependency with zero dependents is a de facto internal library, and internal libraries need an owner.
Failure modes.
WWW-Authenticate, Cache-Control: no-store) silently, breaking client retry logic without erroring.composer update for the whole app; failure is loud at build time, which is at least safe.Ramp-up. Low technical learning curve — the code is small and readable in an afternoon. The real ramp is OAuth2 error semantics: engineers must know why invalid_client is 401 with a WWW-Authenticate challenge while invalid_grant is 400 without one. That knowledge is the durable asset, and it argues for capturing it in our own well-tested renderer rather than importing a black box that a future maintainer will have to reverse-engineer from a package with no documentation and no users.
How can I help you explore Laravel packages today?