Implementing a Global Authentication Interceptor
Refresh your server access token with an OkHttp interceptor
In this article, you’re going to learn how to implement a global authentication interceptor. The job of this interceptor is to refresh the access token when you got an unauthorized response.
Updating your server to SSL doesn’t necessarily mean you’re safe out in the wild. Your server needs confirmation that you’re communicating with the user without any hacker interception (mostly stated as the man in the middle attack).
Quick Note: Use a certificate pinning feature to avoid man in the middle attacks in most cases. You can learn what certificate pinning is and how to implement it in Android from this article.
Although we have certificate pinning, it’s better to have some sort of user verification. There are different approaches to verify that you’re communicating with the actual user, one of which is token verification. It might be either standard JWT token or your custom logic.
If we see this token verification at a high-level, it’ll be something like this: First, you’ll perform a regular service call if the response status code is 401, which means unauthorized, it might be a hacker interception, or the actual token is expired. In which case, we have to request a new access token. If the token is generated, then we’ve to reinitialize the original request flow. If not, we should log out the user, assuming the connection is compromised.
Enough with the theoretical part, let's start with what an interceptor is. An interceptor is a powerful mechanism that can monitor, rewrite, and retry service calls. Here's a simple interceptor that logs the outgoing requests and the incoming responses.
addInterceptor is the function through which we can add an interceptor to the request builder, OkHttp builder. Then we created a new instance of an interceptor in which we obtain the
interceptor.chain as input.
From this chain, we can get the
request object, which contains in-detailed information about the
request body, headers, and more. Once the request completes, we can access the response.
proceed function with the
request object invoked on the
chain instance, the actual execution will start. The output of the
proceed function is the response from the server, including additional information like status code and other stuff.
Now that we understand how to create an interceptor and how it works, let’s start building the authentication interceptor.
This interceptor’s goal is to invoke a refresh of the access token functionality when the origin request emits unauthorized access. After successfully retrieving the refreshed token, we need to instantiate the request. Have a look:
In the first step, we created the original
request object to reinitialize it if we get unauthorized access. In the next step, we invoked the
proceed function on the chain with the request object.
By this time, the request is started executing. Once the request is completed, we will get the response, and the very first thing we need to do is to verify the request is successful by comparing the status code. If the status code is 200 in the response, then the request is successfully executed.
If the request is a success, then we have to return the response directly. If not, we need to check the error type using the status code. If the status code is 401, then it is unauthorized access; likewise, if you wish to handle other errors, we need to implement it in the
If the origin request response is unauthorized, then we need to create a new request to invoke the
getAccessToken service call. Once we obtain the response first, we need to save the latest access token in preference for future use.
After that, we need to update the latest token in the original request object and then re-initiate the request.
That’s all. Now, your app has a global authentication interceptor. To make the code a bit more optimized, we can create a new class that extends the interceptor and includes the logic related to authentication here. In this way, we can isolate the interceptor’s functionality, so the code looks more organized. Have a look:
To add the interceptor, we need to create an instance of
ErrorHandlingInteceptor, as shown below:
val client = OkHttpClient.Builder()