restFull Api development in Cakephp

restFull Api development in Cakephp

Recently I started a new stage in a project which I have been working on for the last 6 months.

The new stage; Create the API.


Creating a restful API, meant to be used equally by our own iOs app and Android Apps, as well as the website or any external developer.

So complicated as complete it sounds.


Developing a complete restful API is something different from what I am used to with CakePhp.
The JSON responses are easy to create, the stateful responses and error codes are easy to throw thanks to CakePhp request handler and object, models and controllers work more or less the same way, and you can actually import a big part of all your existing functions from your pre-existing website.
The problem starts to appear when you realise that even rest APIs support cookies and are accepted, the ideal solution is not to rely on them. In fact, I realised about this problem when the iOS developer told me he was having weird issues with the sessions, obviously issues that I could not reproduce on my PAW client.

OMG! So the session was being lost and renewed on each request.

I did not know what was going on, but I knew it was not good. With tight deadlines and already behind schedule, changing something so basic as the session management for the users is like changing you airplane wings just before take off.

After some reading on stackoverflow and other troubleshooting pages, including the wikipedia page about the restful APIs specs I realised that the sessions should be linked to the $deviceId making the request, and if the device does not have an ID (like browsers), the session ID should be passed on each request, solution that I don't like at all.

Let me explain my self:    The standard solution for my problem in the PHP community is to disable cookie sessions and enable session id on URL, you do that by setting 2 php ini setting:

ini_set("session.use_cookies",0);
ini_set("session.use_trans_sid",1);

I dont like this because; If the sessionId is passed to the client on each request, and the client has to send it back 2 things may happen:
  • At some point/request it can be forgotten or not received in the query string   (https://url.com/?session_id=xxxxxxxxxxxxxxxxx).
  • More important, the id can be stolen or copied, which means, the session can be restarted somewhere else by a different person or device.
But you will think, Hey, I am a master PHP programmer and I am using https connections so I feel like god!
Well, come back to earth master, because https encrypts the body content of the request, but the headers and request URI can be seen, so your session Id in the query string would be visible for any MAN-IN-THE-MIDDLE attacks, which believe, are super easy to do, you only need to install wireshark (https://www.wireshark.org/).

So I disabled the session cookies with session.use_cookies = 0 but I kept session.use_trans_sid = 0 too.
At this point, your session will not rely on cookies and will not get the sessionId from the URL either, so you have to earn your wage.

Finally, at this point, thanks to the fact that I already was using Device-Id and APIkeys, I decided to do the following:
  • On login/signup store the sessionId with the device information.
  • On each following request get the device, check if the device is authorized and get the existing sessionId from the database.
  • Restart the existing session with the Id from the database using Cakephp's session component: $this->Session->id($recoveredId);
Now the sessions are back again working without cookies, it is nice but do not forget that we want to use this API for the website too!  
Complex JavaScript applications (like angularJs, backbone, Aurelia or React.js) that run in a single page to offer the best user experience, do not refresh the server session with each request to the API, they work as real stateful apps, but still need an initial login process that will initiate the sessionId on the database.

To solve this, you will realise that you have to do a regular login like Google or Facebook do, a login in a regular HTML/POST call that will authorized your JS app to access that account data.

Do not send the session ID

To solve this problem, you will return to the client a custom ID linked with the session that the JS app will have to send you on each request like the iOS app was doing with the deviceId.   You will use this ID to identify the session, user and device in a safe way.

You still need to be cautious: Anybody can steal this ID too, but since it is not the session, you can check it and throw an exception.
To do that, check the IP, user-agent, api key and user-id, if there is something different just deny the request and force a redirect to the initial login page.

This way, the real and valid user will continue using the API without noticing any problem, and the attacker, will only get Exceptions that you can log and track.


I hope this thoughts will help you developing your safe API web service, which basically are the engine of the famous web 2.0.

Share this post