Refreshing OAuth token using Retrofit without modifying all calls
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
The clean way to refresh OAuth tokens in Retrofit is to centralize the logic in OkHttp rather than touching every API call. In practice, that means one interceptor for attaching the current access token and one authenticator for reacting to 401 responses by refreshing and retrying the failed request.
Separate request decoration from refresh logic
These two jobs should not be mixed:
- add the current token to outgoing requests
- refresh the token when the server rejects it
The first belongs in an interceptor. The second belongs in an authenticator.
Add the token with an interceptor
The interceptor reads the current access token from a repository and attaches it to every request.
This keeps your Retrofit service interfaces free of repetitive token boilerplate.
Refresh with an Authenticator
When the server returns 401, OkHttp can invoke an Authenticator. That is the right place to refresh and retry.
The synchronized block prevents several concurrent 401 responses from all refreshing at once.
Wire it into Retrofit once
The client setup is where the whole design comes together:
Now the token handling is centralized and existing API interfaces usually need no changes.
Keep the refresh endpoint separate
A practical detail is that the refresh call itself should not recurse through the same failed auth flow. Many teams solve this by:
- using a dedicated Retrofit instance for auth refresh
- excluding the refresh request from the normal auth header logic
If you use the exact same stack carelessly, a failed refresh can loop into more refresh attempts.
Handle logout and terminal failure explicitly
If refresh fails because the refresh token is expired or revoked, return null from the authenticator so OkHttp stops retrying. Then clear local auth state and trigger a re-login flow.
A refresh system is incomplete if it can refresh successfully but has no clean failure path.
Common Pitfalls
The most common mistake is trying to refresh tokens manually inside every Retrofit call or repository method, which spreads authentication logic across the whole codebase. Another is putting refresh logic in an interceptor rather than an authenticator, which makes retry flow harder to reason about. Developers also often forget to serialize refresh attempts, so multiple 401 responses trigger several simultaneous refresh calls. Using the same Retrofit client for the refresh endpoint without any guard can cause recursive failure loops. Finally, many implementations refresh successfully but do not define what should happen when refresh fails permanently.
Summary
- Use an interceptor to attach the current access token to requests.
- Use an OkHttp authenticator to refresh after
401responses. - Keep token storage centralized in one repository or store.
- Prevent concurrent refresh storms with synchronization or another single-flight mechanism.
- Use a separate auth path for the refresh endpoint when needed.
- Define a clear logout or re-authentication path for refresh failure.
Related reading
- Regional/Edge-optimized API Gateway VS Regional/Edge-optimized custom domain name
- Reliable Webhook dispatching system
- Replacing tf.placeholder and feed_dict with tf.data API
- Repository not necessary when implementing JpaRepository?
- Regex for password must contain at least eight characters, at least one number and both lower and uppercase letters and special characters
- Remove all the Kafka ACLs
- Refreshing UITableView Asynchronously after Core Data Loaded Swift
- Register Application class in Manifest?

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.