If you are building out a somewhat successfull app you will probably at some point want to provide API access to your application. Giving API access to private data requires you to think about how access credentials should be handled, and there are multiple options to go with here:
- Sessions based — You can reuse any access checks you have, but as it requires the client to maintain a cookie (most often) it makes using your API a pita.
- Passing username / password as GET/POST fields on each request — Dead simple in both ends, but as it is a security disaster it should not be considered.
- Request signing — Simple to use on the client after initial implementation as you can easier fire one-off requests
- OAuth (or similar) — A token based access system, good because its secure and there are a lot of libraries for it. Not so simple on the client as you must maintain the token however.
For the uses we’ve had I’ve often chosen #3, a request signing approach. This works by using the arguments (url, parameters) plus an API-key to generate a hash that is passed along the request. The arguments are visible in the request and those plus the shared secret key can be reused to generate a new hash on the server side that is compared against the passed signature. If the hashes match its a valid request.
The main upside this has is that eavesdropping to get the signature of one request does not allow an attacker to reuse it for another request, except to resend the exact same request, which probably isn’t too bad.
The first thing we need to set up is a pretty straight forward user model. Apart from the usual suspects you need to have an `apiKey` field to specifically use for API requests:
The next thing we need is a very simple protected controller resource that lists users:
I’ve not implemented any login handler so without the API this resource is now not possible to access, so lets build on the Auth class in Lithium to support signed request as well as password based auth:
Now we can finally run a request against the API and see if we pass authentication by signing our request. I’ve implemented a simple Command for this:
If you run this command using li3 users consume 1 you should get the print_r listing the single user from the database, while if you attempt to access the same url in your browser it should give a Not authed response.
All of the code is found on github as a working Lithum mini app: nervetattoo/li3-request-signing