Almost all applications nowadays are using APIs to fetch and store data. These endpoints are (hopefully) secured and require authentication to access the user’s data. A lot of these authentication methods require a token to be send alongside the original HTTP request, most likely in the HTTP header.
The token is mostly used to indicate that a user has been logged in, which will result in the backend identifying the user, checking its permissions in the database, and if everything matches accessing and delivering the requested resources.
What happens if there is no user authenticated, but data is still supposed to be available to the application? Without any authentication method, the endpoints are completely open — and (in theory) other services may access the information as well by sniffing the application’s HTTP traffic or decompiling the app itself. To avoid having the information completely in the open, an application token can be used to identify the authenticity of the application.
This increases our available tokens to two, which means we have to select which one is supposed to be injected into the HTTP request headers, which requires logic.
Sometimes it’s a requirement to send an application-token for unauthorized requests, to make sure only users of the original application may access the API. This is supposed to make reverse engineering harder and thus protect the data. This requires some sort of management for the authentication tokens, either depending on endpoint (some endpoints require the app-token, some the user-token) or on a “highest authentication” layer (if user-token is available, send the user-token, otherwise the app-token).
This is an approach to simplify token-based authentication on a per-endpoint scale. It is based on OkHttp’s Interceptor interface, which allows (as the name suggests) intercepting and manipulating HTTP requests in a centralized way — which means by adding the interceptor into the OkHttpClient.
The purpose of this interceptor is to inject the appropriate and required header field with the user’s current authentication tokens seamlessly into the HTTP request. This is achieved by adding a placeholder header into the prepared HTTP request, which will be replaced with the actual value before being executed.
The benefits of this approach are that the actual token is not required in the API declaration scope, thus creating separation of concerns. Within the API declaration simply define the header placeholder for either the user’s token, the application’s token, or whichever you require.
The interceptor needs to be connected to anything that changes your authentication method (logging in, logging out, refreshing tokens, …). Your login procedure for example might have the following addition:
In this example the endpoints require two different authentication layers:
- Application Token in case the user is logged out to verify that the requesting application is legit
- User Token if the user is logged in to get access to the user’s scope
The implementation of the
TokenInterceptor looks as follows:
AuthenticationInterceptor is an abstract class that implements OkHttp’s Interceptor interface. It utilizes a temporary header field (
AUTHENTICATION_HEADER) in combination with a key-set. The AuthenticationInterceptor calls
getTokenByIdentifier with the found header value.
Before passing through the interceptor:
This would trigger
getTokenByIdentifier(identifier = "User Token")which is then supposed to return the corresponding token (in this case the user’s token). The returned value is then used to replace the temporary header with the real one.
After passing through the interceptor:
The only thing left to do is connecting the interceptor to your user authorization mechanism (login, logout). Using dependency injection and providing the interceptor implementation simplifies this task; you can either add variables or functions to set the tokens in the interceptor or you subscribe to an Observable to receive them — it’s up to you, as long as they are available whenever they are required and kept up-to-date.
If you are developing an Android application chances are high that you are also using Retrofit for your API calls. With Retrofit adding headers to endpoints is even more trivial, it boils down to adding an annotation. For this case, I have added constants to my projects which specify the required token and can simply be used within Retrofit interfaces:
The concatenation is required due to the expected format of headers
Key: Value. After defining these constants, an interface for Retrofit with specific authentication requirements looks as follows:
An example of this, including the abstract class of the TokenInterceptor can be found in my GitHub repository:
Contribute to authentication-interceptor development by creating an account on GitHub.
Feel free to share your thoughts on this approach or if you have been working in environments with multiple authentication scopes before share your experiences on this topic.