chadicus/slim-oauth2-http
Lightweight bridge integrating bshaffer/oauth2-server-php with Slim. It implements the OAuth2 HTTP request and response interfaces on top of PSR-7 messages, letting token and authorization endpoints use Slim's request and response objects directly.
This is a glue package, not an OAuth2 server. It contains two adapter classes that translate between Slim/PSR-7 messages and the bshaffer/oauth2-server-php request/response interfaces:
Chadicus\Slim\OAuth2\Http\Request — wraps a Psr\Http\Message\ServerRequestInterface and implements OAuth2\RequestInterface (query(), request(), headers(), server(), and the getAll* variants).Chadicus\Slim\OAuth2\Http\Response — wraps a PSR-7 response, implements OAuth2\ResponseInterface (setError, setRedirect, setResponseCode, setParameters, …), and exposes getResponse() to emit a real PSR-7 response once the OAuth2 server has finished writing to it.Read those two files first; they are the whole package. Everything else (chadicus/slim-oauth2, chadicus/slim-oauth2-routes) is built on top of them.
composer require chadicus/slim-oauth2-http bshaffer/oauth2-server-php
OAuth2\Server with your storage (PDO, MongoDB, or the in-memory OAuth2\Storage\Memory for tests), then wrap it in a token route:use Chadicus\Slim\OAuth2\Http\Request as OAuth2Request;
use Chadicus\Slim\OAuth2\Http\Response as OAuth2Response;
$app->post('/token', function ($request, $response) use ($server) {
$oauth2Response = new OAuth2Response($response);
$server->handleTokenRequest(new OAuth2Request($request), $oauth2Response);
return $oauth2Response->getResponse();
});
That is the canonical first use case: POST /token with grant_type=client_credentials (or password, refresh_token, authorization_code) returns a JSON access token. If you only ever do one thing with this package, this is it.
The three-endpoint pattern. A typical integration wires three handlers, all using the same two wrappers:
handleTokenRequest(), returns JSON.handleAuthorizeRequest($oauth2Request, $oauth2Response, $isAuthorized). The third argument is your "is this user logged in and consenting?" boolean; when false the server emits a 302 to a login URI, so you must return getResponse() untouched.verifyResourceRequest() on any protected route:$app->get('/me', function ($request, $response) use ($server) {
$oauth2Response = new OAuth2Response($response);
if (!$server->verifyResourceRequest(new OAuth2Request($request), $oauth2Response)) {
return $oauth2Response->getResponse();
}
return $response->withJson(['sub' => $server->getResourceController()->getAccessToken()['user_id']]);
});
Keep adapters at the edge. Construct OAuth2Request/OAuth2Response inside the route/controller and never let them leak into your domain service. They are value-less wrappers around PSR-7 messages; passing them around couples your application code to bshaffer/oauth2-server-php.
Container factories. Register small factories so handlers stay thin:
$container->set(OAuth2Request::class, fn($c) => new OAuth2Request($c->get('request')));
$container->set(OAuth2Response::class, fn($c) => new OAuth2Response($c->get('response')));
(Or bind a single TokenController and let it build them per call — safer with Slim 4's per-request container scoping.)
Manual inspection. Because Request implements the OAuth2 interface, you can read grant type, scopes, client credentials, and the Authorization: Basic … header directly when you need custom logic before delegating:
$oauth2Request = new OAuth2Request($request);
if ($oauth2Request->request('grant_type') === 'password' && !$captchaPassed) {
// short-circuit with your own 400
}
Testing. You can unit-test every handler without Slim: build a nyholm/psr7 ServerRequest with form params, pass it in, assert the getResponse()->getBody() JSON and status code. Pair with OAuth2\Storage\Memory for a zero-dependency token issuer.
Middleware vs. handler. There is no middleware here. If you want blanket protection, write a Slim middleware that runs verifyResourceRequest() and returns getResponse() on failure; the bridge classes work identically inside middleware.
Request::request() reads getParsedBody(). In Slim 4, add BodyParsingMiddleware before your routes or grant_type/client_id come back null. In Slim 3, rely on Slim\Http\Request::getParsedBody() being populated by the framework; form-encoded and JSON bodies behave differently there.Authorization: Basic … is frequently stripped by Apache/FastCGI/nginx unless you forward it (SetEnvIf Authorization, fastcgi_param HTTP_AUTHORIZATION). Symptom: invalid_client even though the credentials are correct. Fall back to client_id/client_secret in the POST body while debugging.getResponse() returns a new PSR-7 response; the $response passed into your closure is unchanged. Always return $oauth2Response->getResponse(); — mutating and returning $response silently loses the token body.handleAuthorizeRequest fails authorization, setRedirect sets a 302 + Location. getResponse() handles this, but if you hand-roll a response around getParameters() you will break the redirect flow. Don't JSON-encode unconditionally.Cache-Control: no-store and Pragma: no-cache for token responses per RFC 6749. Overriding them (or a global middleware rewriting Content-Type) is a common source of "works locally, fails conformance" bugs.OAuth2\RequestInterface / OAuth2\ResponseInterface are not PSR-7's RequestInterface / ResponseInterface. Alias imports (as OAuth2Request) or you will chase type errors for an afternoon.implode(' ', $scopes) before passing them in.final, you cannot subclass them; implement OAuth2\RequestInterface yourself if you need different parameter mapping. Most customisation happens in the storage layer, not here.bshaffer/oauth2-server-php is in maintenance mode. If this is a new build, evaluate league/oauth2-server with a modern PSR-7 bridge — but if you're already on the Chadicus stack, this package does its one job correctly and stable (last release 2023).OAuth2\RequestInterface signature; upgrading bshaffer/oauth2-server-php across majors without bumping this package will produce confusing fatal errors.How can I help you explore Laravel packages today?