What is the difference between OAuth2AuthorizedClientManager, OAuth2AuthorizedClientProvider, OAuth2AuthorizedClientService, and OAuth2AuthorizedClientRepository?
answer
- Provider = one grant; Manager = orchestrate; Service = app store; Repository = per-request
- Default manager needs request context; ServiceManager for background
- ProviderBuilder.clientCredentials().refreshToken()
- Repository delegates to Service (authed) or HttpSession (anon)
- InMemory vs Jdbc service
basics
~10 sManager orchestrates authorizing a client; Provider does the actual grant (code/client_credentials/refresh); Service stores authorized clients application-wide; Repository is the per-request/session store that (by default) delegates to the Service for logged-in users.
solid answer
~40 sThese are four cooperating roles. **`OAuth2AuthorizedClientProvider`** implements a single grant strategy — one per grant type (authorization_code, client_credentials, refresh_token, jwt-bearer). **`OAuth2AuthorizedClientManager`** is the entry point you call: it loads any existing client, runs the provider chain to authorize/re-authorize, and persists the result. Two manager flavours: `DefaultOAuth2AuthorizedClientManager` (needs a request context, uses the Repository) and `AuthorizedClientServiceOAuth2AuthorizedClientManager` (context-free, for background jobs, uses the Service). **`OAuth2AuthorizedClientService`** is the application-wide persistent store (in-memory or JDBC), keyed by registrationId + principalName. **`OAuth2AuthorizedClientRepository`** is the web-tier store bound to `HttpServletRequest`; the default delegates to the Service for authenticated principals and to the HttpSession for anonymous ones. So: Provider = how to get a token, Manager = orchestration, Service/Repository = where tokens are kept.
code
java · 25 lines// Background/service-layer manager (no HttpServletRequest available)
@Bean
OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository registrations,
OAuth2AuthorizedClientService service) {
OAuth2AuthorizedClientProvider providers =
OAuth2AuthorizedClientProviderBuilder.builder()
.clientCredentials()
.refreshToken()
.build();
AuthorizedClientServiceOAuth2AuthorizedClientManager manager =
new AuthorizedClientServiceOAuth2AuthorizedClientManager(registrations, service);
manager.setAuthorizedClientProvider(providers);
return manager;
}
// Usage from a @Scheduled job:
OAuth2AuthorizeRequest req = OAuth2AuthorizeRequest
.withClientRegistrationId("my-api")
.principal("system") // stable principal name for M2M
.build();
OAuth2AuthorizedClient client = manager.authorize(req);
String token = client.getAccessToken().getTokenValue();go deeper
Just know Manager coordinates and Service stores tokens.
Distinguish Provider (grant) from Manager (orchestration) and Service from Repository.
Explain the two manager types and their context requirements, plus the repository's delegate-to-service behaviour.
Weigh Jdbc vs in-memory service for clustering, custom provider composition, and correct manager choice for background vs request threads.
## The four roles, precisely ### 1. `OAuth2AuthorizedClientProvider` — the grant executor Each provider knows **one** grant. Given an `OAuth2AuthorizationContext` it returns a new/updated `OAuth2AuthorizedClient` or `null` (meaning 'not my job / nothing to do'): - `AuthorizationCodeOAuth2AuthorizedClientProvider` — only *reports* that user redirect is needed (throws `ClientAuthorizationRequiredException`); it doesn't do the redirect itself. - `ClientCredentialsOAuth2AuthorizedClientProvider` — machine-to-machine token via client id/secret. - `RefreshTokenOAuth2AuthorizedClientProvider` — swaps a refresh token for a fresh access token when the current one is expired. - `JwtBearerOAuth2AuthorizedClientProvider`, and the deprecated `PasswordOAuth2AuthorizedClientProvider`. You compose them with **`OAuth2AuthorizedClientProviderBuilder`**: `.authorizationCode().refreshToken().clientCredentials().build()`. The builder returns a `DelegatingOAuth2AuthorizedClientProvider` that tries each in order. ### 2. `OAuth2AuthorizedClientManager` — the orchestrator You call `manager.authorize(OAuth2AuthorizeRequest)`. It: 1. Loads the existing client (from Repository or Service). 2. Builds an `OAuth2AuthorizationContext` and invokes the provider chain. 3. On a returned client, runs the configured success handler which **saves** it; on failure, the failure handler (which may **remove** it). Two implementations differ by context: - **`DefaultOAuth2AuthorizedClientManager`** — servlet, request-scoped, uses `OAuth2AuthorizedClientRepository`. This is the one the `@RegisteredOAuth2AuthorizedClient` resolver uses by default. It expects the current `HttpServletRequest`/`HttpServletResponse` and `Authentication`. - **`AuthorizedClientServiceOAuth2AuthorizedClientManager`** — for use **outside** a request (scheduled tasks, message listeners). It uses the `OAuth2AuthorizedClientService` directly and does not require web context. Ideal for `client_credentials` background calls. ### 3. `OAuth2AuthorizedClientService` — application-wide store Persists `OAuth2AuthorizedClient`s keyed by (registrationId, principalName). Implementations: `InMemoryOAuth2AuthorizedClientService` (default) and `JdbcOAuth2AuthorizedClientService` (survives restarts / is shared across instances). Methods: `loadAuthorizedClient`, `saveAuthorizedClient`, `removeAuthorizedClient`. ### 4. `OAuth2AuthorizedClientRepository` — the web-tier store Binds storage to the current `HttpServletRequest`. The default **`AuthenticatedPrincipalOAuth2AuthorizedClientRepository`** delegates: for an authenticated principal it uses the `OAuth2AuthorizedClientService`; for an anonymous user it falls back to `HttpSessionOAuth2AuthorizedClientRepository` (session-scoped). This lets pre-login/anonymous flows work before there's a stable principal to key on. ## How they fit together `@RegisteredOAuth2AuthorizedClient` → `OAuth2AuthorizedClientArgumentResolver` → **Manager** → **Provider chain** → result saved via **Repository** → (Repository) → **Service**. ## Common gotchas - Using `DefaultOAuth2AuthorizedClientManager` from a background thread fails — no request context; use the service-based manager. - If you build a custom manager you must wire a `setAuthorizedClientProvider(...)`; otherwise it authorizes nothing. - In-memory service loses tokens on restart and isn't shared across nodes — use JDBC in production clusters. - The refresh provider only refreshes; it never performs the *initial* authorization. ## When to use which manager Request-driven, user-scoped API calls → Default (repository) manager. Background/system-to-system → Service manager.
- Which manager do you use in a @Scheduled task and why?AuthorizedClientServiceOAuth2AuthorizedClientManager — it works without an HttpServletRequest and reads/writes through the OAuth2AuthorizedClientService directly, which suits background client_credentials calls.
- Why does the default repository fall back to the HttpSession for anonymous users?Because there is no stable principalName yet to key an application-wide Service entry, so tokens obtained before login are kept in the session and migrated once the principal is authenticated.
saying these in an interview costs you the question
- Treating Manager and Service as the same thing.
- Using DefaultOAuth2AuthorizedClientManager from a non-request thread.
- Forgetting to set a provider on a hand-built manager (it then authorizes nothing).
- Relying on in-memory service across a clustered/restarting deployment.