OAuth Token Manager
Difficulty: Hard · Topics: Design, Concurrency, API, Auth
Difficulty: Hard | Tags: API, Auth, Design, Concurrency
Description
Implement an OAuth 2.0 token manager that handles the full lifecycle: obtaining tokens, caching them, refreshing before expiry, and thread-safe concurrent access.
Implement:
OAuthTokenManager
OAuthTokenManager(config) — initialize with client credentials
getAccessToken() → String — return valid access token (auto-refresh)
forceRefresh() → String — force a new token
revokeToken() — revoke current token
isTokenValid() → boolean — check if current token is still valid
Config:
{
clientId: "your-client-id",
clientSecret: "your-client-secret",
tokenUrl: "https://auth.example.com/oauth/token",
refreshUrl: "https://auth.example.com/oauth/refresh",
grantType: "client_credentials" | "authorization_code" | "refresh_token",
scopes: ["read", "write"]
}
Examples
Example 1 — Auto-refresh:
manager = new OAuthTokenManager(config)
token1 = manager.getAccessToken() // Fetches new token from auth server
token2 = manager.getAccessToken() // Returns cached token (still valid)
// ... token expires ...
token3 = manager.getAccessToken() // Auto-refreshes, returns new token
Example 2 — Concurrent access (no duplicate requests):
// Token expired. 10 threads call getAccessToken() simultaneously:
// Only ONE thread actually calls the auth server.
// Other 9 threads wait and receive the same refreshed token.
Example 3 — Proactive refresh:
// Token expires at t=3600s
// Manager proactively refreshes at t=3300s (5 min before expiry)
// No request ever sees an expired token
Token Response (from auth server):
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "dGhpcyBpcyBhIHJlZnJlc2g...",
"scope": "read write"
}
Constraints
- Thread-safe: concurrent
getAccessToken()calls must not cause multiple simultaneous refresh requests. - Proactive refresh: refresh 5 minutes (configurable) before expiry.
- Cache the token — don't hit the auth server on every call.
- Handle auth server errors gracefully (retry once, then throw).
- Support both
client_credentialsandrefresh_tokengrant types. - Revoke must invalidate the cached token.
Hints
Hint 1
Use a ReentrantLock or synchronized block around the refresh logic. Check the token again after acquiring the lock (double-checked locking).
Hint 2
Store expiresAt = System.currentTimeMillis() + (expiresIn * 1000) - bufferMs and check currentTime >= expiresAt for proactive refresh.
Follow-up
- Add support for multi-tenant token management (one manager, multiple client credentials).
- Add token encryption at rest (don't store plain tokens in memory dump).
- Integrate with a circuit breaker for auth server failures.