CORS Slim PHP Setup

Ok, another PHP post but this time it’s about setting up some middleware for a slim PHP application.

Let me set this up. We are building a simple REST API for use with a basic phone native app (both Android and iOS). Me being new to this, I wasn’t sure if the native app domain call is considered cross browser or not, plus there are some outside companies we are working with who MAY access the API as well. There are only 4 routes that are valid for this API.

I setup some middleware by extending the Slim Middleware class and adding them via the app like so:

$app->add(new \HttpsAuth());
$app->add(new \HttpBasicAuth());
$app->add(new \AccessControlOrigin());

Now, this is literally what my code looks like so don’t kill me too much. But basically you setup the middleware as an extended class and it’s got one job really, and that’s to implement call(). Anyways, you can see the three middleware I have setup so far and keep in mind that the middleware is setup so that any route has to go through them. The only option to call is the Route class from Slim. You can change the middleware to ignore certain routes, but if you are going anymore complicated, I would change up the way I would do middleware for certain routes rather than this route.

So anyway, you can guess what they do. The longest one is Basic Auth which means I am using HTTP Basic Authentication with a username and password to identify users. I won’t show you that code but suffice it to say, it’s the most complicated and easiest to fail.

The HttpsAuth is actually a basic check for SSL. Every request must be secure and this middleware ensures that.

if($this->app->environment['slim.url_scheme'] !== 'https'){

So here is where I ran into problems. I was having trouble with CORS (Cross Site requests). Here are some of the steps I used to clean it up and made sure it worked so you don’t get 401 errors. Or especially this lovely message:

XMLHttpRequest cannot load http://external.service/. No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘‘ is therefore not allowed access.

  • If you are using Basic Auth or Digest Auth and your Slim authentication middleware is always run like mine, ensure that the authentication ignores OPTIONS request. A CORS request will send a preflight request without actual authentication data, so this would fail everytime unless you handle it. Ex.if(!$this->app->request->isOptions()) {
  • Make sure the proper headers are set in your server response. This includes identifying the origin and returning it. You can do something in .htaccess or Apache configs but since I am using slim I preferred to do it there.$this->app->response->headers->set('Access-Control-Allow-Origin', $http_origin);
    $this->app->response->headers->set('Access-Control-Allow-Credentials', 'true');
    $this->app->response->headers->set('Access-Control-Allow-Methods','GET, OPTIONS');
  • Notice above that I also set Access-Control-Allow-Headers to Authorization. The browser is expecting this information back as well. I also limited myself to just GET and OPTIONS since I don’t have any routes using the other VERBS but if the API expands in the future, this is easily adaptable since the middleware is in one place (yay DRY principles).
  • Lastly, make sure to send the proper headers on the front end, ie. the request must go through SSL, remember to send a Basic Auth header, and if sending an XHR request, be sure to turn withCredentials to true. In jquery (which is our current front-end library of choice) it’s as simple as adding this in your ajax options xhrFields: {
    withCredentials: true

Ok, so it seems as though I write posts about the things that cause me the most headaches but since I had to piece together items from all over, I figured I would put it all together in one spot for someone else who may be going through the same thing.

Simple REST APIs are fun and easy to implement with Slim especially in our case since we are basically returning JSON data. You can use Slim to render data as well with templates, etc… but personally I think it defeats the purpose of an API. It should be the go between the back and front and handle those requests that way you can handle the front end however you would like. And hopefully, the cross browser gotcha won’t catch you like it caught me.