David Mosher

PHP League OAuth 2 Server in Laravel

At work I'm working on implementing an OAuth 2.0 server for use with some internal API's. I've been keeping a close eye on Alex Bilblie's OAuth 2 Server package that he maintains under the PHP League umbrella, and as such decided to use his package to do my implementation.

Most of the new stuff we're writing is utilizing PHP 7 and Laravel 5.2. I fired up a new repository, ran composer create-project laravel/laravel ./my-project and the first thing after that was to composer require league/oauth2-server, which gave me the 5.0 release.

I went about my way implementing the various storage repositories for access tokens and the like. Finally I got to the point where my application was providing tokens back to the user. Now I wanted to run a middleware to validate the token before returning a controller response.

This is where I hit my first minor road block.

Upon inspecting code for Laravel (mostly Symfony http-foundation stuff...) and the oauth package I found that the oauth package relied upon the PSR-7 request implementation. The problem I ran into with this is if you pass the PSR-7 request on to the next middleware in the stack, the world blows up.

Here is what I came up with for a middleware that appears to work. Fair warning: this code may make your eyes bleed, etc., etc.

<?php namespace Noip\SooperSecretProjectName\Http\Middleware;

use Closure;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;
use League\OAuth2\Server\ResourceServer;
use League\OAuth2\Server\Exception\OAuthServerException;

class OAuthResource
{
    private $psr_request;
    private $server;

    public function __construct(Request $psr_request)
    {
        $this->request = $request;
        // FIXME: Inject this by binding the server in AppServiceProvider
        $this->server = app('oauth.resource_server');
    }

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @param  string|null  $guard
     * @return mixed
     */
    public function handle($request, Closure $next, $guard = null)
    {
        try {
            $psr_request = $this->server->validateAuthenticatedRequest($this->psr_request);
        } catch (OAuthServerException $e) {
            // FIXME: Return a response formatted as such:
            // $e->generateHttpResponse($response);
            dd('OAuthServerException', $e);
        } catch (\Exception $e) {
            // FIXME: Return a response formatted as such:
            // $response->getBody()->write($exception->getMessage());
            // return $response->withStatus(500);
            dd($e);
        }

        // Change PSR-7 Request back into an Illuminate\Http\Request so lower
        // down the chain middlewares can handle it
        $factory = new \Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory;
        $symfony_request = $factory->createRequest($request);
        $request = \Request::createFromBase($symfony_request);

        // Update the request set in app so we have access to the
        // oauth attributes parameter bag in controllers and such
        \App::instance('request', $request);

        // Pass the request and response on to the next responder in the chain
        return $next($illuminate_request);
    }
}

And that, my friends, is what I did for almost all of my Friday at work, then a few hours at home in an attempt to move this project forward. All in a days work, right?