Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Server Library Laravel Package

oauth2-framework/server-library

OAuth2 Framework Server Library gives PHP applications the components needed to run an OAuth2 authorization server, including grant handling, token issuance, client authentication, and standards-compliant endpoint behavior for secure API access.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a framework-agnostic OAuth 2.0 authorization server (PSR-7/PSR-15 oriented), not a Laravel package — there is no service provider, no publishable config, no migrations, no facade. Budget a half-day of wiring before your first token.

Install and orient yourself:

composer require oauth2-framework/server-library

Read in this order: README.md → src/ top-level factories (look for AuthorizationServer / ResourceServer classes) → the GrantType/ directory → the Repository/ interfaces. The repository interfaces are the actual contract you implement; everything else is plumbing you assemble.

First use case — client_credentials. Skip authorization_code initially: no redirect handling, no consent screen, no PKCE. You can get a token out of POST /oauth/token in an hour and validate your wiring end-to-end.

// routes/api.php — deliberately NOT in the 'web' group
Route::post('/oauth/token', [TokenController::class, 'issue']);

// TokenController
public function issue(Request $request)
{
    $psrRequest = (new Psr17Factory())->createServerRequest(
        $request->method(), $request->fullUrl()
    )->withParsedBody($request->post())->withQueryParams($request->query());

    $psrResponse = $this->authorizationServer->respondToAccessTokenRequest(
        $psrRequest, new Response()
    );

    return response($psrResponse->getBody()->getContents(), $psrResponse->getStatusCode())
        ->withHeaders($psrResponse->getHeaders());
}

The core checklist: implement ClientRepository, AccessTokenRepository, ScopeRepository against Eloquent; generate an RSA keypair; register ClientCredentialsGrant; hit the endpoint with curl -u client_id:client_secret -d grant_type=client_credentials.

Implementation Patterns

Repository-as-adapter. Treat the package's repository interfaces as your seam. Implement them with Eloquent models (OauthClient, OauthAccessToken, OauthRefreshToken, OauthAuthCode, OauthScope) and keep all SQL in those classes. You'll write your own migrations — the package ships none. Bind the interfaces in a service provider so you can swap in fake implementations for tests.

Resource-server middleware. Wrap token validation in a Laravel middleware rather than validating per-controller:

class AuthenticateBearer
{
    public function handle($request, Closure $next)
    {
        $psrRequest = $this->toPsr($request);
        $result = $this->resourceServer->validateAuthenticatedRequest($psrRequest);
        $request->attributes->set('oauth', $result->getAttributes());
        return $next($request);
    }
}

Apply to your api group, then resolve Auth::user() from the token's sub claim inside a custom guard or a small resolveUser() helper.

Grant selection by client type. authorization_code + PKCE for SPAs and mobile; client_credentials for machine-to-machine; avoid password — it's deprecated in the spec and locks you into collecting user passwords. Register only the grants you actually expose; each one you add is attack surface.

Bridge once, not everywhere. The Laravel↔PSR-7 impedance mismatch is the biggest friction. Install symfony/psr-http-message-bridge + nyholm/psr7, write two conversion functions (toPsr / toLaravel), and put them in a single trait or base controller. Do not scatter conversions across controllers.

Config as a first-class concern. Keep TTLs, key paths, and enabled grants in config/oauth.php — the package won't provide this. Read them once in a service provider, not inside grant handlers.

Testing. Test at the HTTP boundary with $this->postJson('/oauth/token', ...) — you're asserting the assembled server, not the library. For unit tests, hand-roll in-memory repositories (three small classes) rather than fighting the container.

Gotchas and Tips

  • Maturity signal is the headline risk. Zero stars and zero dependents means no community burn-in: no Stack Overflow corpus, no battle-tested edge cases around clock skew, token replay, or malformed headers. Pin an exact version, read the source, and seriously evaluate league/oauth2-server (the de facto PHP OAuth2 server, with far more production mileage) before committing. If you proceed, isolate it behind your repository interfaces so swapping later is a contained change.

  • Exceptions won't render as OAuth JSON. The package will throw OAuth2-specific exceptions that Laravel turns into HTML 500s. Register renderable callbacks in bootstrap/app.php (or Handler::render) mapping them to {"error": "...", "error_description": "..."} with the correct HTTP status. Without this, clients can't distinguish invalid_client from a server crash.

  • Middleware group matters. Session and CSRF middleware will break token endpoints. Put them in a stateless group that still runs throttle — rate limiting /oauth/token is mandatory, not optional.

  • Authorization header stripping. Apache/CGI and some Nginx fastcgi setups drop the Authorization header. If bearer tokens validate locally but fail in production, check $_SERVER['HTTP_AUTHORIZATION'] and add SetEnvIf Authorization / fastcgi_param HTTP_AUTHORIZATION before debugging your code.

  • Key storage and rotation. The private signing key must live outside the docroot with 0600 perms and must never be committed. Plan rotation now: publish a JWKS-style endpoint keyed by kid so tokens don't all die at once. Losing the key invalidates every issued token.

  • Redirect URI exactness. Match schemes, hosts, ports, trailing slashes, and query strings byte-for-byte. Wildcard matching is how open redirects happen.

  • Refresh token rotation. On grant, revoke the presented refresh token and issue a new one. Check the repository interface actually exposes revocation — if not, add a revoked_at column and enforce it in your implementation.

  • Clock discipline. Store all expiry timestamps in UTC (Laravel's default Carbon timezone may differ from date_default_timezone_get()). Allow ~30s skew when validating iat/exp.

  • Debugging. Log the grant type, client id, and error code on every rejection — never the token or secret. The response body's error field is your primary signal; invalid_grant almost always means a mismatched redirect URI, expired code, or reused PKCE verifier.

  • Extension points. Custom grants extend the base grant class; custom responses implement the response-type interface. Scope narrowing belongs in ScopeRepository::finalizeScopes() — that's the hook for role-based scope restriction.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource