Basic HTTP Authentication with the Slim PHP Framework REST API

When it comes to securing your REST API — authenticating and authorizing users — the situation is a bit interesting because the principle of an API being truly RESTful is that things remain stateless on the server side with each request. What that means is that the server isn’t really supposed to keep track of state in the form of sessions or anything else. To be truly RESTful all of the information that the web application needs to properly handle each request should be contained in the request itself.

If you wanted to, you could just cheat and handle everything using sessions. But according to the Internet, if you do this many kittens will die. So in the interest of at least trying to do things properly and saving the lives of millions of kittens, in the following bit we’re going to look at another one of the more common implementations for REST API authentication and authorization: Basic HTTP Authentication. We’ll be using the Slim Framework — a lightweight PHP REST API to demonstrate this, but the same principles apply if you’re using another framework or even another language.

To have user authentication within your app’s API and remain truly RESTful, it usually inevitably boils down to 2 choices: Basic HTTP Authentication and OAuth. OAuth was discussed previously in this article about using Google’s OAuth in order to access many different Google’s APIs. The developer docs at Twitter also have some good information on these two different forms of authentication.

OAuth is another great option for securing your REST API but it’s slightly more complex to both set up and code against compared to basic HTTP authentication, what we’ll be looking at shortly. Basic HTTP authentication is probably the quickest and easiest way to add some security to your REST API, but if you wanted to try to implement OAuth, you could definitely do that as well. It all just depends on your needs and requirements.

The Basics of Basic HTTP Authentication

So what exactly is basic HTTP authentication? As it turns out, just about any webpage could use HTTP authentication if it was desired (so long as the page was able to set HTTP headers). Did you ever visit a page and have the little password prompt come up (one that was system-level and not part of the website you were visiting)?

Basic HTTP Authentication

What is this? That indicates that a page is likely using HTTP authentication in asking you to provide a username and password. How is this being done? Take a look at the following PHP page below…

<?php 
if(!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW']) || $_SERVER['PHP_AUTH_USER'] !== 'demo' || $_SERVER['PHP_AUTH_PW'] !== 'demo') {

    header("WWW-Authenticate: Basic realm=\"Secure Page\"");
    header("HTTP\ 1.0 401 Unauthorized");
    echo 'No soup for you';
    exit;
}
?>
<!DOCTYPE html>
<html>
<head>
<title>Basic HTTP Authentication</title>
</head>
<body>

<h1>Secure Page</h1>

<p>This is a page with secure content...</p>

</body>
</html>

Because the WWW-Authenticate headers are included, the user will be prompted to provide a username and password (in this case both need to be ‘demo’) or else the user will not be allowed to see the content in the page. By doing this you can secure basically any web page or request route that you want. Any page or route secured by this method requires the username and password to be sent with each request. One thing to mention on that note, however, is that it goes without saying that you’d want to be sure to do this authentication over HTTPS in production using an SSL certificate. As is stated on the Wikipedia page for basic access authentication

The BA mechanism provides no confidentiality protection for the transmitted credentials. They are merely encoded with BASE64 in transit, but not encrypted or hashed in any way. Basic Authentication is, therefore, typically used over HTTPS.

You want to be sure that your communication is encrypted. Otherwise someone with a packet sniffer could potentially see your username and password credentials being transferred over the web. Actually if your website our web application has any sort of user login system you should be doing things over HTTPS (but not everyone does).

You may have noticed that there’s also mention of a “realm” in basic HTTP authentication. The realm is a case sensitive string used to describe groupings of pages that use a particular set of credentials. If you authenticate on one page with a certain set of credentials, you should be able to access other pages or routes within the same realm. In this way, you can have different levels and different types of authentication for different pages in different realms.

Basic HTTP Authentication with the Slim Framework

So let’s take a look at how we might be able to add some basic HTTP authentication to a REST API using the Slim Framework to protect our routes. Fortunately the Slim Framework provides middleware to allows us to easily incorporate this. You can find these middleware libraries in the Slim Extras repository here. What we’re interested in is the basic auth component. The code for this (minus the large introductory legal text) can be found below…

<?php

class HttpBasicAuth extends \Slim\Middleware
{
    /**
     * @var string
     */
    protected $realm;

    /**
     * @var string
     */
    protected $username;

    /**
     * @var string
     */
    protected $password;

    /**
     * Constructor
     *
     * @param   string  $username   The HTTP Authentication username
     * @param   string  $password   The HTTP Authentication password
     * @param   string  $realm      The HTTP Authentication realm
     */
    public function __construct($username, $password, $realm = 'Protected Area')
    {
        $this->username = $username;
        $this->password = $password;
        $this->realm = $realm;
    }

    /**
     * Call
     *
     * This method will check the HTTP request headers for previous authentication. If
     * the request has already authenticated, the next middleware is called. Otherwise,
     * a 401 Authentication Required response is returned to the client.
     */
    public function call()
    {
        $req = $this->app->request();
        $res = $this->app->response();
        $authUser = $req->headers('PHP_AUTH_USER');
        $authPass = $req->headers('PHP_AUTH_PW');
        if ($authUser && $authPass && $authUser === $this->username && $authPass === $this->password) {
            $this->next->call();
        } else {
            $res->status(401);
            $res->header('WWW-Authenticate', sprintf('Basic realm="%s"', $this->realm));
        }
    }
}

More information about Slim Framework Middleware can be found in the documentation. The public “call” method is essentially required any middleware in the Slim Framework. It’s the method that gets invoked when middle ware is instantiated.

Modifying the Middleware

Now, in my personal opinion, I don’t find it tremendously useful to have to pass credentials into the constructor if our API was going to have multiple users. So let’s modify this a bit and also do a bit of preparation for running a SQL query on

<?php

class HttpBasicAuth extends \Slim\Middleware
{
    /**
     * @var string
     */
    protected $realm;

    /**
     * Constructor
     *
     * @param   string  $realm      The HTTP Authentication realm
     */
    public function __construct($realm = 'Protected Area')
    {
        $this->realm = $realm;
    }

    /**
     * Deny Access
     *
     */	
    public function deny_access() {
        $res = $this->app->response();
        $res->status(401);
        $res->header('WWW-Authenticate', sprintf('Basic realm="%s"', $this->realm));        
    }

    /**
     * Authenticate 
     *
     * @param   string  $username   The HTTP Authentication username
     * @param   string  $password   The HTTP Authentication password	 
     *
     */
    public function authenticate($username, $password) {
        if(!ctype_alnum($username))
            return false;
        
        if(isset($username) && isset($password)) {
            $password = crypt($password);
            // Check database here with $username and $password
            return true;
        }
        else
            return false;
    }

    /**
     * Call
     *
     * This method will check the HTTP request headers for previous authentication. If
     * the request has already authenticated, the next middleware is called. Otherwise,
     * a 401 Authentication Required response is returned to the client.
     */
    public function call()
    {
        $req = $this->app->request();
        $res = $this->app->response();
        $authUser = $req->headers('PHP_AUTH_USER');
        $authPass = $req->headers('PHP_AUTH_PW');
		
        if ($this->authenticate($authUser, $authPass)) {
            $this->next->call();
        } else {
            $this->deny_access();
        }
    }
}

What we’ve done here is pull the logic that checks the users credentials into its own “authenticate” method. We’ve also created a deny_access method as well (though that might not be entirely necessary at the moment, it may be beneficial to have that present in the future as the auth code becomes more complex as we write it).

Now in this code it should be fairly obvious that it accepts any username and password combination (as long as there is something set). The only case of failure is that the username has to be alphanumeric (assuming that was a requirement for your system). We won’t go that deep into it, but it is here where we’d want to go a step further, connect to our database and validate the user’s credentials against what is stored in the database (or do whatever authentication implementation that you to wanted here). We’d obviously also want to be sure that we’d do the proper sanitation of user input before running our SQL queries. I’m not a black-belt security kung-fu master but I believe that it’s possible that requiring the username to be alphanumeric and creating a crypt hash of whatever the password input was (assuming that was the encryption method you were using to store passwords — and you are using encryption right? ;)) is pretty clean already. But we could also do the additional sanitization methods. In this past, this was using things like mysql_real_escape_string, but now other libraries are preferred. And in the future these in turn will be replaced with others.

Now we have to make sure that we remember to load the middleware. So in the index.php file in the root directory of our main Slim Framework API directory (the one where we instantiate slim and define routes) we just have to load up the middleware…

require 'Slim/Slim.php';
require 'Slim/Middleware.php';
require 'Slim/Middleware/HttpBasicAuth.php';

\Slim\Slim::registerAutoloader();

And after we do that we are going to want to create a new instance of our Basic HTTP Authentication class after we initialize the Slim Framework…

$app = new \Slim\Slim();
$app->add(new \HttpBasicAuth());

What this will do by default is protect all routes by requiring authentication. If we wanted to open up some routes to be publicly available we could perhaps change the code in our HttpBasicAuth class to automatically allow access certain routes, but that’s another discussion for another day.

WordPress Themes

Like this post? How about a share?

Stay Updated with the 9bit Studios Newsletter

6 Responses to Basic HTTP Authentication with the Slim PHP Framework REST API

  1. AH

    June 19, 2013 at 6:05 am  
    When you login at the web application, I guess the username and the password must be encrypted in the client side right? Or HTTPS is enough? Since using SESSION is not RESTful, I guess we should send back a identificator to the user so we can identify him on other pages and requests later right? I hope I could avoid the ugly authentification window with some jquery & ajax on the client side... Thanks for the article, very useful.

    • June 22, 2013 at 7:12 am  
      Hi AH -- From what I've read, HTTPS is enough, but I'm sure there are some security experts out there who would offer suggestions for somehow adding an additional layer of security. As for the second part, I think how you implement something like that really depends on what type of application you are building so there's probably no one exact answer. Username and password are going to be sent with each request so while you're authenticating that you could grab whatever additional user info you wanted from your DB and send it back. I think it's pretty open-ended as to what you do beyond basic auth. That would be another really interesting topic to explore: different methods of integrating Basic HTTP Auth user logins into applications (especially with regard to UI/UX).

  2. August 25, 2013 at 11:40 am  
    Thanks, very helpful. I will use this in combination with Backbone.js and https://github.com/fiznool/backbone.basicauth

    • January 9, 2014 at 5:41 am  
      how are you going to use with backboneJs
  3. Sean

    October 2, 2013 at 9:23 am  
    I am a newbie. So how does the web app know your logged in if you don't set sessions? You would have to send username and password for every single request? Wouldn't that open yourself up to a security breach?

    • October 2, 2013 at 11:10 am  
      Hi there Sean. Yes, that always is a concern with Basic Authentication. Like with anything on the web, your credentials are plain text over the wire. Without SSL, if someone on the same network was monitoring network traffic they could see it... but the situation is essentially the same with sessions as those can also be hijacked.

Leave a Reply