OAuth Middleware for Slim

OAuth can be anything you want it to be, the standards are lax and give you plenty of room for getting the right implementation for your system. However you proceed, though, you'll need to check an access token on every request - and in a Slim application, a middeware can help enormously since it hooks in to every request by design. I've recently implemented this and thought I would share.

Acquiring an Access Token

This is an RPC-esque API, and there's an action that looks very much like a user login method. In OAuth terms, this is the "client credentials flow". Since the consumer of this API is created by the same organisation as the API itself, there's a high degree of trust between the two. To make things very simple, the consumer asks the user for their credentials, and passes them to the API (note: the consumer does not store them, and will never use them again. The trusted consumer application is the ONLY time you give your password to any 3rd party). The API checks them, and sends back an access token which the consumer then uses on all future requests.

This is a basic login type of flow, similar to what you would build on any website, and the access token is just a generated hash of some kind. You could do pretty much anything here, generate something and then store it so you can tie it back to the correct user again later. For the record, my code looks like this:

    $token = bin2hex(openssl_random_pseudo_bytes(16));

The consumer then captures this token and adds it in the Authorisation header of all future requests, so that the header looks like this:

Authorisation: OAuth [token]

Checking the Token

Now we need to check the token on every request where we expect the user to be authenticated. You could do this with a check at the top of each appropriate controller action, but Slim has a mechanism that makes this even easier: its middleware provides hooks that can be used on every request.

Middleware is a self-contained class, here's mine:

namespace MyLib\Middleware;

class OAuth2Auth extends \Slim\Middleware
{
    protected $headers = array();

    protected $config;

    protected $mysql; // PDO

    public function __construct($headers, $config, $mysql) {
        $this->headers = $headers;
        $this->config = $config;
        $this->mysql = $mysql;
    }

    public function call() {
        // no auth header
        if(!isset($this->headers['Authorization'])) {
            $this->app->getLog()->error("No authorization header");
            $view = $this->app->view();
            $view->setData("data", array("message" => "Access credentials not supplied"));
            $view->render('error.php', 400);
        } else {
             try {
                $authHeader = $this->headers['Authorization'];
                $auth = new \Service\Mysql\AuthService($this->mysql, $this->config);
                $validated_user_id = $auth->verifyOAuth($authHeader);
                $this->app->user_id = $validated_user_id;
             } catch (\Exception $e) {
                $view = $this->app->view();
                $view->setData("data", array("message" => $e->getMessage()));
                $view->render('error.php', $e->getCode());
             }
           }

        // this line is required for the application to proceed
        $this->next->call();
    }
}

Hopefully this code is easy enough to follow, the constructor of this class accepts some dependencies including the incoming headers for this request. The call() method is then called when it's this middleware's turn ... and at the end of that method, we call the next middleware in the list. Within this main method, we check the incoming header against the database and save the user's information so that we can use it again if we want to use their identity when processing the detail of this request later. This application requires all requests to be authenticated, but if yours allows some unauthenticated access, you could just as easily not set the user details and continue - then check if those details are present as appropriate to each route.

Adding Middleware to Slim Framework

I found this a super-easy way to get the same code firing on every request without remembering anything :) It gets set up after I've instantiated the app (which is in $app) and connected to the database (the PDO object is stored in $mysql). Then in index.php I just add these lines:

// Add OAuth middleware
$headers = apache_request_headers();
$app->add(new \MyLib\Middleware\OAuth2Auth($headers, $config, $mysql));

Hopefully if you need to implement something similar, this gives you an idea of the kind of pattern you can follow. Additional tips, questions or comments are all welcome, just use the comment form below :)

8 thoughts on “OAuth Middleware for Slim

  1. Pingback: OAuth Middleware for Slim | Advanced PHP | Scoo...

  2. "OAuth can be anything you want it to be, the standards are lax and give you plenty of room for getting the right implementation for your system"

    And this is why people dislike working with OAuth, because they see a statement like that and go and implement insecure crap on the backend then cry because every implementer has created something different and we have hundreds of different libraries to work with specific providers.

    OAuth 2.0 is actually quite a well defined standard with explicit (and very readable) instructions on how implementations should function. As an OAuth advocate I strongly recommend and urge anyone reading this ignores the article featured here and looks and makes uses of an implementation that follows the standard to the letter - Brent Shaffer has created an excellent implementation (https://github.com/bshaffer/oauth2-server-php) and I have my own implementation as well (https://github.com/php-loep/oauth2-server).

    • Thanks Alex, I found your blog via your comment and it's fantastic. I too wanted a more true OAuth implementation. Thanks for sharing.

    • That's the service class that will actually do the loading and storing of user details, mine happen to be in MySQL for this application. Hope that helps.

  3. I am implementing REST API with slim and also using oauth-php library. I don't want to authenticate every request but I require some of the API Call secured using oAuth.

    What should I do?

  4. Pingback: Best Practices REST API from Scratch - Introduction

Leave a Reply

Please use [code] and [/code] around any source code you wish to share.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>