Refreshing OAuth Tokens with OkHttp Authenticator and Interceptors
Refreshing OAuth Tokens with OkHttp Authenticator and Interceptors
When working with APIs secured by OAuth, handling token expiration and refresh is a critical part of the networking layer. OkHttp provides two mechanisms for this: the Authenticator interface and Interceptor. The Authenticator is specifically designed for responding to 401 authentication challenges, while an Interceptor provides more flexible control over both request and response processing. Understanding when to use each approach and how they interact with the request lifecycle is essential for building a reliable authentication layer. By the end of this lesson, you will be able to:
- Explain how the OkHttp
Authenticatorresponds to 401 challenges automatically. - Implement an
Interceptorthat detects token expiration and refreshes the token inline. - Describe the key differences between
AuthenticatorandInterceptorfor token management. - Handle thread safety concerns when multiple requests trigger a token refresh simultaneously.
Using OkHttp Authenticator
The Authenticator interface is invoked automatically when a server responds with a 401 Unauthorized status code. It provides a hook to supply updated credentials and retry the request transparently.
class TokenAuthenticator(
private val tokenProvider: TokenProvider
) : Authenticator {
override fun authenticate(route: Route?, response: Response): Request? {
val newToken = tokenProvider.refreshToken() ?: return null
return response.request.newBuilder()
.header("Authorization", "Bearer $newToken")
.build()
}
}
Returning null from authenticate signals that the request should not be retried. Returning a new Request causes OkHttp to retry with the updated headers. The client is configured by passing the authenticator to the builder:
val okHttpClient = OkHttpClient.Builder()
.authenticator(TokenAuthenticator(tokenProvider))
.build()
OkHttp limits the number of retry attempts to prevent infinite loops when the server keeps returning 401.
Using OkHttp Interceptor
An Interceptor offers more control over the entire request and response pipeline. It can attach the token to every outgoing request and handle refresh logic when a 401 is detected.
class TokenInterceptor(
private val tokenProvider: TokenProvider
) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
var request = chain.request().newBuilder()
.header("Authorization", "Bearer ${tokenProvider.getToken()}")
.build()
val response = chain.proceed(request)
if (response.code == 401) {
synchronized(this) {
val newToken = tokenProvider.refreshToken() ?: return response
request = request.newBuilder()
.header("Authorization", "Bearer $newToken").build()
response.close()
return chain.proceed(request)
}
}
return response
}
}
This interview continues for subscribers
Subscribe to Dove Letter for full access to exclusive interviews about Android and Kotlin development.
Become a Sponsor