Nowadays, Token Based Authentication is widely used for API authentication. With most, every mobile application using an API, tokens are the most secure way to handle authentication for multiple users. But, we never thought, is it really the most secure way?
Well, if token based authentication guaranteed security for each and every request, then yes, it is.
But unfortunately, each request to the server is not fully secure with token-based authentication.
So, this blog is all about, how we can secure every single API request on token-based API authentication.
Before moving on this, let's have a look, how token-based API authentication works-
- User requests for access with Username/Password, basically do log in.
- API validates credentials and if successful then it generates a unique token (set of characters) against that user and returns to the client.
- Client stores that token and use for the further communication with the server. And no Username/Password needed for next time.
- API server only verifies the token in every next request and responds with data.
Problem
Now, for each request API need a valid token to process the request.
But, how you can ensure the API request with a valid token is coming from the authenticated user but not from a third person?
If somehow a third person captured your token from the network and then request for API by sending that token from their end, then the security will be broken down until the token is expired. Of course, it is hard to capture token from the network but possible.
Well, no one can track this type of faulty request. But we must invalidate the faulty request somehow.
Solution
The solution for the problem involves the following steps:
- The token used for the API access must not be the same for each request.
- The token must be invalidated after one-time use (but a user does not need to log in after each request). So that, if it got captured by any third person, though it will not be used for any further request because it is invalidated after one-time use.
- Use encrypted token instead of the plain token. For this, use a platform independent encryption-decryption process, so that the token can be encrypted at the client end and can be decrypted at the server end.
NOTE: The second point is most important. And after implementation of the above points, the APIs will be 99.999% secured. We cannot say its 100% secured. But so far it will be the most secure way of token-based authentication.
Implementation
Use AES encryption-decryption: this process needs a plain text and a salt for encryption-decryption.
At the client end, the process will be:
plain text = original token
salt = a secret key + current timestamp
encrypted token = encrypt (plain text, salt)
final token = Base64 (encrypted token)
(The final token and current timestamp used in the salt are sent to the server.)
At the server end, the process will be:
encrypted token = FromBase64 (received token)
salt = same secret key + received current timestamp
Original token = Decrypt (encrypted token, salt)
Authenticate Request:
Match original token in the database with additional condition: received current timestamp > saved current timestamp (in database)
Invalidate the Token after one-time use:
If the above authentication passed, do update 'current timestamp' saved in the database against that user by 'received current timestamp'.
Now, the token-based authentication will work like this-
- The user will log in with Username/Password.
- The server will validate credentials and generate a unique token and send to the client.
- Before sending the token, the server will store this token in a database and store current timestamp (unique for every millisecond) along with the token.
- At the client end, an encrypted token will be generated each time using AES encryption-decryption process in which plain text will be the token and, the salt will be 'secret key + current timestamp'. And final token will be Base64 converted string of encrypted token.
- The final token and current timestamp (used in the encryption) will be sent to the server.
- At the server end, final token and current timestamp are fetched. An intermediate token is fetched from the Base64 string final token. Now, this token is decrypted using 'secret key + current timestamp passed'.
- Then, the decrypted token is matched in the database and the current timestamp > the saved timestamp.
- If it is valid, the current timestamp is updated in the database.
- Basically, the timestamp saved in the database against the user is getting updated after each successful API respond. And for the next request, it must be greater than the previous one.
- Because of unique timestamp, the final token will be different in each request and will be invalidated after one-time use due to timestamp updated in the database after each successful response.
- This way, if a third person captured the final token from the network and try to do a request then it will be invalided by the server because, in the next request, the timestamp must be greater than previous. And if the third person tries to send current timestamp of a future one, then the decrypted token will not be matched at server end because the token was encrypted with a different timestamp.