bshaffer/oauth2-server-httpfoundation-bridge
Symfony HttpFoundation bridge for bshaffer/oauth2-server, enabling OAuth2 requests and responses to work seamlessly with Symfony/Laravel HttpFoundation objects. Provides adapters to integrate the OAuth2 server with HttpFoundation-based apps.
Install the Package:
composer require bshaffer/oauth2-server-httpfoundation-bridge
Ensure version matches oauth2-server-php (e.g., ^1.7 for Laravel 10).
Basic Integration:
In your OAuth2 controller (e.g., app/Http/Controllers/OAuth2Controller.php):
use OAuth2\HttpFoundationBridge\Request as BridgeRequest;
use OAuth2\HttpFoundationBridge\Response as BridgeResponse;
use OAuth2\Server;
public function token(Request $request) {
$oauthRequest = BridgeRequest::createFromGlobals();
$oauthResponse = new BridgeResponse();
$server = new Server($storage, $tokenStorage, $scopeStorage);
return $server->handleTokenRequest($oauthRequest, $oauthResponse);
}
Route Definition:
Route::post('/oauth/token', [OAuth2Controller::class, 'token']);
Token Endpoint: Replace manual parsing of grant_type, client_id, etc., with the bridge’s BridgeRequest:
// Before (manual parsing)
$grantType = $_POST['grant_type'] ?? null;
// After (bridge handles it)
$grantType = $oauthRequest->getGrantType();
Global Requests:
Use BridgeRequest::createFromGlobals() for CLI or PSR-7 environments (e.g., Laravel’s Request object).
$request = BridgeRequest::createFromGlobals();
$server->validateAuthorizationCodeGrantType($request);
Existing Request Objects:
Convert Laravel’s Illuminate\Http\Request to OAuth2-compatible:
$bridgeRequest = BridgeRequest::createFromRequest($request);
Request Stack (Laravel 5.5+): For middleware or service containers:
$bridgeRequest = BridgeRequest::createFromRequestStack();
JSON Responses:
The BridgeResponse extends Symfony\Component\HttpFoundation\JsonResponse, so it works seamlessly with Laravel’s JSON middleware:
$response = new BridgeResponse();
$server->handleTokenRequest($request, $response);
return $response; // Laravel’s JSON middleware auto-converts
Custom Responses:
Extend BridgeResponse for non-JSON formats (e.g., HTML for error pages):
class CustomResponse extends BridgeResponse {
public function setHttpCode($code) {
$this->setStatusCode($code);
}
}
Wrap OAuth2 logic in Laravel middleware for global handling:
// app/Http/Middleware/OAuth2Bridge.php
public function handle($request, Closure $next) {
$oauthRequest = BridgeRequest::createFromRequest($request);
$response = $next($request);
if ($response instanceof BridgeResponse) {
return $response;
}
return $response;
}
Register in app/Http/Kernel.php:
protected $middleware = [
\App\Http\Middleware\OAuth2Bridge::class,
];
Use HttpFoundation objects directly in tests:
public function testTokenRequest() {
$request = new Request([], [], [
'grant_type' => 'client_credentials',
'client_id' => 'test_client',
'client_secret' => 'secret',
]);
$bridgeRequest = BridgeRequest::createFromRequest($request);
$response = $this->server->handleTokenRequest($bridgeRequest, new BridgeResponse());
$this->assertEquals(200, $response->getStatusCode());
}
Laravel Service Container: Bind the bridge to the container for dependency injection:
$app->bind('oauth2.bridge.request', function () {
return BridgeRequest::createFromGlobals();
});
Validation:
Combine with Laravel’s validation (e.g., Validator facade) before OAuth2 processing:
$validator = Validator::make($request->all(), [
'grant_type' => 'required|in:authorization_code,client_credentials',
]);
if ($validator->fails()) {
return response()->json(['error' => 'invalid_request'], 400);
}
Error Handling: Catch OAuth2 exceptions and convert to Laravel responses:
try {
$server->handleTokenRequest($request, $response);
} catch (\OAuth2\ServerException $e) {
return response()->json([
'error' => $e->getMessage(),
'error_description' => $e->getErrorDescription(),
], $e->getHttpCode());
}
CORS: Use Laravel’s CORS middleware alongside OAuth2 to ensure preflight requests are handled:
Route::middleware(['cors'])->post('/oauth/token', ...);
Version Mismatches:
symfony/http-foundation. For Laravel 10 (Symfony 6.4), use ^1.7:
"bshaffer/oauth2-server-httpfoundation-bridge": "^1.7"
oauth2-server-php (e.g., ^1.7 for both).Request Order:
$_GET/$_POST before the bridge processes the request, OAuth2 parameters may be lost. Ensure the bridge middleware runs first in the stack.Response Types:
BridgeResponse always returns JSON. For non-JSON responses (e.g., HTML), create a custom class extending BridgeResponse and override setHttpCode()/setContent().PHP Warnings:
PHP Warning: Parameter 2 to OAuth2\HttpFoundationBridge\Request::__construct() has a default value followed by a required parameter
Fix: Upgrade PHP or pin to ^1.6 of the bridge.Global State:
createFromGlobals() relies on $_SERVER, $_GET, etc. In tests or non-web contexts, use createFromRequest() instead.CSRF Protection:
/oauth/token). Exclude the route:
Route::post('/oauth/token', ...)->middleware('throttle', 'bindings')->withoutMiddleware('csrf');
Request Inspection: Dump the bridge request to verify parameter parsing:
dd($oauthRequest->getRequestParameters());
Response Validation: Check the raw response content:
$response = $server->handleTokenRequest($request, $bridgeResponse);
dd($response->getContent());
Error Codes:
OAuth2 errors map to HTTP codes (e.g., 400 for invalid_request). Use Laravel’s abort() helper for consistency:
if ($oauthRequest->getError()) {
abort($response->getStatusCode(), $response->getContent());
}
Logging: Log OAuth2 events for auditing:
\Log::info('OAuth2 Token Request', [
'grant_type' => $oauthRequest->getGrantType(),
'client_id' => $oauthRequest->getClientId(),
]);
Custom Storage:
Extend oauth2-server-php’s storage classes (e.g., Client, AccessToken) and reuse them with the bridge.
Grant Types:
Add custom grant types by extending OAuth2\GrantType\AbstractGrant and register them with the server:
$server->addGrantType(new CustomGrant($storage));
Response Formatters:
Override BridgeResponse to support custom formats (e.g., XML):
class XmlResponse extends BridgeResponse {
public function setContent($content) {
$this->setContent(simplexml_load_string($content));
}
}
Middleware Chaining: Chain multiple OAuth2 middlewares for layered validation:
$middleware->push(\App\Http\Middleware\ValidateClient::class);
$middleware->push(\App\Http\Middleware\CheckScopes::class);
$_GET/$_POST on instantiation. For high-traHow can I help you explore Laravel packages today?