I recently had the need to write a small url shortening application. I am aware that this problem has been solved quite a few times before, but what is being a developer if not reinventing the wheel just for the heck of it? Custom CMS anyone?
Knowing that this was going to be a tiny RESTful API and also knowing that Laravel 5.2 had API rate limiting built in, I was eager to give it a try. Taylor Otwell being Taylor Otwell shipped 5.2 with the rate limiting defaults set up out of the box and I had my application building out short url's in a matter of minutes. The problem for me came when I wanted to start associating those short urls with a user.
Typically my applications have a UI and authentication is done through a simple login page. Obviously for a simple RESTful API, having a login page isn't ideal. Instead, my hope was to have users append an api_token to the end of their query string and use that to authenticate their request.
I was happy to find that 5.2 also ships with a TokenGuard
class that allows you to do exactly that, but the documentation on getting it to work was a bit thin, so here you go.
The first think you need to do is to add an api_token
column to your users
table. If you are just starting your application you can likely get away with modifying the user migration that ships with Laravel to include your new column.
// add this to your users_table migration
$table->string('api_token', 60)->index();
Second, we need to make sure that any routes that will be using this particular method of Authentication are being protected by the auth:api
middleware.
Use the following route group as an example of what your route might look like.
Route::group(['prefix' => 'api/v1', 'middleware' => 'auth:api'], function () {
Route::post('/short', 'UrlMapperController@store');
});
Note: Typically when protecting routes from unauthenticated users, we use the auth
middleware, but by appending the :api
to the end of it we are telling Laravel that we want to use the driver for the api
guard which is set up in the config/auth.php
and is defaulted to the token
guard.
At this point, any routes wrapped with your auth:api
middleware are locked down to those that visit the URL with a valid api_token
in their request.
My goal however was not to simply protect a route, but to associate any new short urls created with the user that created them. In order to do this, we need to know whose api_token
was used during the request. Because this is a statelss API we can't rely upon cookies or sessions to tell us who our user is. Thankfully, Laravel makes it easy to work with that.
Not sure if this is any better than good old SessionId.
At least, SessionId is regenerated often (normally, on each log-in, if you have it implemented correctly), so even if someone stole it, it will be usable only for a short period of time.
Such database token, on the contrary, is not regenerated, and even if you encrypt it, it still is the same and being sent to the server and could be intercepted almost the same way as SessionID. Also, it does not offer any benefits - you still have to hit the database on each request. But in comparison, session could be implemented as a Redis cache, fast SSD storage - you name it.
If you really want to use true token mechanism, you have to implement it fully - to create a short term tickets (e.g. JWT) which contain claims about the caller identity, so you can grant access to the API service without hitting the database. All the other in-between solutions for sessionId<->token are redundant and not any better than using SessionId directly.