How do you implement OAuth2 token refresh with Retrofit Authenticator?
Distinguishing Authenticator from Interceptor for 401 retry and sync.
Implement authenticate() with a blocking refresh, new Request with new token, Mutex for parallel 401s.
WHAT THIS TESTS: Your understanding of OkHttp's request lifecycle and where Retrofit's Authenticator fits versus an Interceptor. Specifically, it checks whether you know that Authenticator is invoked only when the server returns a 401 Unauthorized response, and whether you can solve the thundering herd problem when multiple concurrent requests fail with 401 after token expiry.
A GOOD ANSWER COVERS: First, implement the Authenticator interface and override the authenticate method which receives the Route and the failed Response. Second, check the response code to confirm it is a 401 and inspect the request to avoid infinite retry loops, for example by checking if the request already carried the new token or by counting retry attempts. Third, perform a synchronous blocking token refresh call inside authenticate because the method signature requires you to return a Request or null immediately; you cannot use suspend functions or callbacks here. Fourth, return a new Request built from the failed response with the updated Authorization header containing the fresh access token so OkHttp automatically retries the original call exactly once. Fifth, guard the refresh logic with a Kotlin Mutex or a similar synchronization primitive so that if three requests hit 401 simultaneously only one network refresh call is made and the other two await the result, preventing a refresh storm.
COMMON WRONG ANSWERS: Using an Interceptor instead of Authenticator is the most common mistake because Interceptors run on every request and cannot cleanly distinguish between an initial request and a retry after 401. Another red flag is attempting to launch a coroutine or use async code inside authenticate, which violates the synchronous contract and will return null or crash. Failing to return null when the refresh itself fails is also critical; if you return a new request regardless you create an infinite retry loop that burns battery and hits rate limits. Some candidates also forget to update the local token storage before returning the new request, causing the retry to use the same expired token again.
LIKELY FOLLOW-UPS: How would you handle a 403 Forbidden differently from a 401, since Authenticator only triggers on 401s? What happens if the refresh token is also expired and the user must re-login? How do you unit test this flow without making real network calls? Would you use a Mutex or a Semaphore, and why? How does this design change if you have multiple authentication realms or base URLs?
ONE CONCRETE EXAMPLE: The AndroidTokenRefreshApp repository demonstrates this with two implementations. The TokenAuthenticatorMutex class wraps the refresh call in a Mutex.withLock block. When the DummyJSON API returns 401 on a protected endpoint, the Authenticator triggers, acquires the lock, performs one blocking refresh to the DummyJSON auth endpoint, stores the new access token, and returns a new Request with the updated Bearer header. The non-mutex variant shows multiple concurrent 401s triggering redundant refresh calls, which the Mutex variant eliminates.
Read the original → github.com
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.