REST API's are meant to be stateless. What that means is that each request from a client should include all the information needed to process the request.In other words, if you are writing a REST API in PHP then you should not be using $_SESSION to store data about the client's session. But then how do we remember if a client is logged in or anything else about their state?The only possibility is that the client must be tasked with keeping track of the state.How could this ever be done securely? The client can't be trusted!
Enter JSON web tokens. A JSON web token is a bit of JSON, perhaps something that looks like this:
{
"user":
"alice",
"email":
"test@nospam.com"
}
Of course, we can't just give this to a client and have them give it back to us without some sort of assurance that it hasn't been tampered with. After all, what if they edit the token as follows:
{
"user":
"administrator",
"email":
"test@nospam.com"
}
The solution to this is that JSON web tokens are signed by the server. If the client tampers with the data then the token's signature will no longer match and an error can be raised.
The JWT PHP class makes this easy to do. For example, to create a token after the client successfully logs in, the following code could be used:
$token =
array();
$token[
'id'] =
$id;
echo JWT::encode(
$token,
'secret_server_key');
And then on later API calls the token can be retrieved and verified by this code:
If the token has been tampered with then $token will be empty there will not be an id available. The JWT class makes sure that invalid data is never made available. If the token is tampered with, it will be unusable. Pretty simple stuff!
What are the benefits of using a token-based approach?
Cross-domain / CORS: cookies + CORS don't play well across different domains. A token-based approach allows you to make AJAX calls to any server, on any domain because you use an HTTP header to transmit the user information.
Stateless (a.k.a. Server side scalability): there is no need to keep a session store, the token is a self-contanined entity that conveys all the user information. The rest of the state lives in cookies or local storage on the client side.
CDN: you can serve all the assets of your app from a CDN (e.g. javascript, HTML, images, etc.), and your server side is just the API.
Decoupling: you are not tied to a particular authentication scheme. The token might be generated anywhere, hence your API can be called from anywhere with a single way of authenticating those calls.
Mobile ready: when you start working on a native platform (iOS, Android, Windows 8, etc.) cookies are not ideal when consuming a secure API (you have to deal with cookie containers). Adopting a token-based approach simplifies this a lot.
CSRF: since you are not relying on cookies, you don't need to protect against cross site requests (e.g. it would not be possible to <iframe>your site, generate a POST request and re-use the existing authentication cookie because there will be none).
Performance: we are not presenting any hard perf benchmarks here, but a network roundtrip (e.g. finding a session on database) is likely to take more time than calculating an HMACSHA256 to validate a token and parsing its contents.
Login page is not an special case: If you are using Protractor to write your functional tests, you don't need to handle any special case for login.
Standard-based: your API could accepts a standard JSON Web Token(JWT). This is a standard and there are multiple backend libraries (.NET,Ruby, Java, Python, PHP) and companies backing their infrastructure (e.g. Firebase, Google, Microsoft). As an example, Firebase allows their customers to use any authentication mechanism, as long as you generate a JWT with certain pre-defined properties, and signed with the shared secret to call their API.
Sessions: We need to store our sessions somewhere. By default they are just stored on server’s memory and having thousand of them doesn’t help. Redis does help but without sessions there are no problems then :P
Mobile: Native mobile apps seems to have problems working with cookies so if we need to query a remote API, maybe session auth is not the best solution.
CSRF: If we go down the cookies way, you really need to do CSRF to avoid cross site requests. That is something we can forget when using JWT as you will see.
CORS: Have you fight with CORS and cookies? I hope it went right because when it doesn’t, we have a problem.