skip to content

OAuth2, OIDC & Resource Server

Spring's OAuth2 and OIDC support in all four roles: logging users in through a provider, calling APIs as a client, protecting an API as a resource server with JWT or opaque tokens, and running your own authorization server. Any interview involving SSO or token-based APIs lands here.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

explore

questions

30

What is Spring Authorization Server, and what role do RegisteredClient and RegisteredClientRepository play in it?

level: juniorimportance: must knowfreq 60%

answer

  1. Separate project, not Security core
  2. Issues access + id tokens
  3. RegisteredClient = one allowed app
  4. InMemory vs Jdbc repository
  5. findByClientId on each request

basics

~20 s

Spring Authorization Server is a standalone project that turns your app into an OAuth2/OIDC provider — it issues tokens. A RegisteredClient is one app allowed to request tokens; RegisteredClientRepository stores and looks up those clients.

solid answer

~40 s

Spring Authorization Server (a separate project from Spring Security, not part of the core framework) provides a compliant OAuth2 Authorization Server and OpenID Connect 1.0 Provider. It exposes endpoints like /oauth2/authorize, /oauth2/token and /oauth2/jwks and issues access tokens and OIDC id tokens. A RegisteredClient models a client application permitted to obtain tokens: its clientId/clientSecret, allowed authorization grant types (e.g. authorization_code, client_credentials), redirect URIs, and scopes. RegisteredClientRepository is the abstraction that saves and finds those clients — InMemoryRegisteredClientRepository for demos/tests, JdbcRegisteredClientRepository for persistence. On each token request the server loads the RegisteredClient by clientId to validate the request and decide what it may be issued.

code

java · 16 lines
java
RegisteredClient client = RegisteredClient.withId(UUID.randomUUID().toString())
    .clientId("web-app")
    .clientSecret("{bcrypt}$2a$10$...")
    .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
    .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
    .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
    .redirectUri("https://app.example.com/login/oauth2/code/web-app")
    .scope(OidcScopes.OPENID)
    .scope("read")
    .clientSettings(ClientSettings.builder().requireProofKey(true).build())
    .build();

@Bean
RegisteredClientRepository registeredClientRepository() {
    return new InMemoryRegisteredClientRepository(client);
}

go deeper

for a junior

Know it issues tokens and that RegisteredClient = an app allowed to get tokens.

for a middle

Explain RegisteredClient fields (grant types, scopes, redirect URIs) and InMemory vs Jdbc repositories.

for a senior

Discuss client authentication methods, PKCE for public clients, and custom RegisteredClientRepository implementations.

for a principal

Weigh self-hosting an IdP vs delegating to Keycloak/Okta; persistence, multi-instance, and client-lifecycle management.

**What it is.** Spring Authorization Server is a dedicated Spring project (artifact `org.springframework.security:spring-security-oauth2-authorization-server`) that lets you host your own **OAuth2 Authorization Server** and **OpenID Connect (OIDC) 1.0 Provider**. It is *not* bundled in Spring Security core — you add it as a separate dependency. Its job is to **authenticate clients/users and issue tokens** that resource servers (APIs) then trust. **Vocabulary (assume nothing).** - *OAuth2*: a delegated-authorization protocol. A *client* application gets an **access token** to call protected APIs on a user's behalf. - *OIDC*: an identity layer on top of OAuth2 that additionally issues an **id token** (a JWT describing *who* the user is) and a discovery/userinfo mechanism. - *Client*: an application (e.g. a SPA, mobile app, or backend service) that requests tokens — distinct from the end user. - *Grant type*: the flow used to get a token (authorization_code, client_credentials, refresh_token, etc.). **RegisteredClient.** An immutable value object describing exactly one client that is allowed to talk to the server. Built via `RegisteredClient.withId(...)`. Key fields: - `clientId` / `clientSecret` — the client's credentials (secret typically encoded with a `PasswordEncoder`). - `clientAuthenticationMethod(s)` — how the client proves itself, e.g. `CLIENT_SECRET_BASIC`, `NONE` for public clients using PKCE. - `authorizationGrantType(s)` — `AUTHORIZATION_CODE`, `CLIENT_CREDENTIALS`, `REFRESH_TOKEN`, etc. - `redirectUri(s)` — allowed callback URLs (validated exactly on the authorization_code flow). - `scope(s)` — permissions the client may ask for; `OidcScopes.OPENID` is required to get an id token. - `clientSettings` / `tokenSettings` — e.g. require PKCE, require consent, token TTLs, token format. **RegisteredClientRepository.** The strategy interface the server uses to persist and retrieve clients. Two methods matter: `save(RegisteredClient)` and `findByClientId(String)` / `findById(String)`. Built-in implementations: - `InMemoryRegisteredClientRepository` — a fixed in-memory list; great for tests and demos, lost on restart. - `JdbcRegisteredClientRepository` — persists to a relational database using the schema shipped with the project; the production choice. You can also implement it yourself (e.g. to load clients from your own tables or a config service). **How it fits at runtime.** When a token request arrives, the server extracts the `clientId`, calls `findByClientId`, and uses the returned `RegisteredClient` to validate the request (is this grant allowed? is the redirect URI registered? are the scopes permitted?) and to shape the issued tokens. **Gotchas.** - The server is a separate deployable/config; don't confuse it with `spring-security-oauth2-client` (which makes your app a *client*) or `spring-security-oauth2-resource-server` (which makes your app validate tokens). - `InMemoryRegisteredClientRepository` state is lost on restart and not shared across instances — never use it in production. - A missing `openid` scope means no id token is issued even though it's an OIDC-configured server. **When to use.** Choose Spring Authorization Server when you need to *own* your identity/token issuance (internal IdP, first-party SSO) instead of delegating to Okta/Auth0/Keycloak.

  • Which repository implementation would you use in production and why?
    JdbcRegisteredClientRepository, so clients survive restarts and are shared across all server instances via the database; InMemory is only for tests/demos.
  • How does the server know which app is calling?
    The client authenticates (e.g. clientId+secret via CLIENT_SECRET_BASIC, or PKCE for public clients); the server looks up the RegisteredClient by clientId to validate the request.

saying these in an interview costs you the question

  • Thinking Spring Authorization Server is part of Spring Security core rather than a separate project
  • Confusing it with oauth2-client (consumer) or resource-server (validator)
  • Believing InMemoryRegisteredClientRepository is fine for production

context

open as a page

What does JwtTimestampValidator check on an incoming JWT, and why does it allow a small clock skew by default?

level: juniorimportance: must knowfreq 62%

basics

~20 s

JwtTimestampValidator checks the token's time claims: it rejects tokens that are expired (exp) or not yet valid (nbf). It allows a default 60-second clock skew so tokens are not rejected just because server clocks differ slightly.

open as a page

What is an OAuth2AuthorizedClient in Spring Security, and how does oauth2Client() differ from oauth2Login()?

level: juniorimportance: must knowfreq 60%

basics

~20 s

An OAuth2AuthorizedClient holds the access token (and optional refresh token) your app got to call another API on a user's behalf. oauth2Client() lets your app CALL other APIs; oauth2Login() logs the USER into your app.

open as a page

What does oauth2Login() enable in a Spring Security application, and what OAuth2 flow does it use?

level: juniorimportance: must knowfreq 70%

basics

~20 s

oauth2Login() lets users sign in to your app using an external provider like Google or GitHub. It uses the OAuth2 authorization-code flow: Spring redirects the user to the provider, gets a code back, and exchanges it for tokens to log the user in.

open as a page

How do you configure a Spring Security application to act as an OAuth2 Resource Server that accepts JWT bearer tokens?

level: juniorimportance: must knowfreq 78%

basics

~10 s

In the SecurityFilterChain, call http.oauth2ResourceServer(oauth2 -> oauth2.jwt(...)). Add a jwk-set-uri or issuer-uri in application.yml so Spring can fetch the keys and verify each incoming Bearer token's signature.

open as a page

What is an opaque token in a Spring Security resource server, and how do you configure the resource server to validate one?

level: juniorimportance: must knowfreq 62%

basics

~10 s

An opaque token is a random string with no readable content. The resource server can't decode it, so it calls the authorization server's introspection endpoint to check it. You enable it with oauth2ResourceServer().opaqueToken().

open as a page

How does Spring Authorization Server issue access tokens versus OIDC id tokens, and how do they differ?

level: middleimportance: must knowfreq 50%

basics

~20 s

The access token authorizes API calls (it says what the client may do); the id token is proof of the user's identity for the client (it says who logged in). The id token is only issued when the client requests the openid scope.

open as a page

How do you compose multiple JWT validators (timestamp, issuer, audience) into a single decoder, and why is JwtValidators.createDefaultWithIssuer preferred over building the chain by hand?

level: middleimportance: must knowfreq 58%

basics

~20 s

Combine validators with DelegatingOAuth2TokenValidator, which runs each in turn and aggregates errors, then attach it via decoder.setJwtValidator(...). JwtValidators.createDefaultWithIssuer(issuer) is preferred because it bundles the timestamp validator plus issuer check so you don't accidentally drop the defaults.

open as a page

How do you get an access token inside a controller using @RegisteredOAuth2AuthorizedClient, and what happens under the hood?

level: middleimportance: must knowfreq 55%

basics

~10 s

Add an OAuth2AuthorizedClient parameter annotated @RegisteredOAuth2AuthorizedClient("registration-id") to your controller method. Spring resolves it, authorizing (or refreshing) as needed, and you read client.getAccessToken().getTokenValue().

open as a page

What are ClientRegistration and ClientRegistrationRepository, and how does Spring populate them?

level: middleimportance: must knowfreq 60%

basics

~20 s

A ClientRegistration holds the config for one OAuth2 provider — client id/secret, scopes, and the provider's endpoint URLs. ClientRegistrationRepository is the store of all registrations, looked up by registrationId. Spring Boot builds them from your application.yml properties.

open as a page

Explain the difference between OAuth2User and OidcUser, and the role of OAuth2UserService.

level: middleimportance: must knowfreq 55%

basics

~20 s

OAuth2User is the authenticated principal for plain OAuth2 logins, exposing the provider's user attributes and granted authorities. OidcUser extends it for OIDC logins, adding access to the id_token and standard OIDC claims. OAuth2UserService loads that principal after the token exchange.

open as a page

How does NimbusJwtDecoder verify a JWT's signature, and what is the difference between configuring it with jwk-set-uri versus issuer-uri?

level: middleimportance: must knowfreq 70%

basics

~20 s

NimbusJwtDecoder downloads the authorization server's public keys (the JWK set), picks the key matching the token header's kid, and checks the signature. jwk-set-uri points straight at the keys; issuer-uri discovers the jwks URL and also validates the iss claim.

open as a page

What is the OpaqueTokenIntrospector interface, and how does Spring use it to turn an opaque token into an authenticated principal?

level: middleimportance: must knowfreq 55%

basics

~10 s

OpaqueTokenIntrospector has one method, introspect(token), that calls the introspection endpoint and returns an OAuth2AuthenticatedPrincipal with the token's attributes and authorities. Spring's OpaqueTokenAuthenticationProvider calls it and builds a BearerTokenAuthentication.

open as a page

How does a JWT's scopes/claims become Spring Security GrantedAuthorities, and how do you customize that mapping with JwtAuthenticationConverter?

level: seniorimportance: must knowfreq 66%

basics

~20 s

By default Spring reads the scope (or scp) claim and turns each value into a SCOPE_<value> authority. To use different claims — like Keycloak realm roles — supply a JwtAuthenticationConverter with a custom JwtGrantedAuthoritiesConverter (prefix + claim name) via oauth2ResourceServer().jwt().jwtAuthenticationConverter(...).

open as a page

Compare opaque introspected tokens with self-contained JWTs for a resource server. What are the trade-offs, and when would you pick each?

level: seniorimportance: must knowfreq 58%

basics

~20 s

JWTs are validated locally (fast, no network) but can't be revoked until they expire and expose claims to anyone. Opaque tokens require a network introspection call per request (slower, central dependency) but give instant revocation and keep claims private. Choose opaque when revocation matters, JWT for scale/latency.

open as a page

What is the OIDC /.well-known discovery endpoint, and which core endpoints does Spring Authorization Server expose by default?

level: middleimportance: should knowfreq 45%

basics

~10 s

The discovery endpoint /.well-known/openid-configuration returns JSON metadata (issuer plus URLs of the authorize, token, jwks, and userinfo endpoints) so clients can auto-configure. Spring Authorization Server also exposes /oauth2/authorize, /oauth2/token, and /oauth2/jwks.

open as a page

How do you customize the claims in issued tokens and configure JWT signing in Spring Authorization Server?

level: seniorimportance: should knowfreq 35%

basics

~20 s

Register an OAuth2TokenCustomizer<JwtEncodingContext> bean to add or change claims per token type. Provide a JWKSource<SecurityContext> bean holding your signing key(s); the server signs JWTs with the private key and publishes the public key at /oauth2/jwks.

open as a page

Write and explain a custom audience validator (OAuth2TokenValidator<Jwt>) for the aud claim. Why is validating audience important?

level: seniorimportance: should knowfreq 47%

basics

~10 s

Implement OAuth2TokenValidator<Jwt>, check that jwt.getAudience() contains your API's identifier, and return OAuth2TokenValidatorResult.success() or failure with an OAuth2Error. It matters because it stops a token minted for another API from being accepted by yours.

open as a page

How do you mint a signed JWT in Spring using JwtEncoder/NimbusJwtEncoder? Walk through the JWK source, JwsHeader, JwtClaimsSet, and encode call.

level: seniorimportance: should knowfreq 44%

basics

~20 s

Create a NimbusJwtEncoder backed by a JWKSource holding your signing key. Build a JwtClaimsSet (issuer, subject, audience, issuedAt, expiresAt, custom claims) and a JwsHeader (algorithm), then call jwtEncoder.encode(JwtEncoderParameters.from(header, claims)) to get a signed Jwt whose getTokenValue() is the JWT string.

open as a page

How do you configure and use the client_credentials grant for machine-to-machine calls in Spring Security's OAuth2 client?

level: seniorimportance: should knowfreq 50%

basics

~10 s

Register a client with authorization-grant-type: client_credentials (client id, secret, token-uri, scopes). No user is involved — the app authenticates itself. A ClientCredentialsOAuth2AuthorizedClientProvider fetches the token; you attach it to downstream calls.

open as a page

What is the difference between OAuth2AuthorizedClientManager, OAuth2AuthorizedClientProvider, OAuth2AuthorizedClientService, and OAuth2AuthorizedClientRepository?

level: seniorimportance: should knowfreq 45%

basics

~10 s

Manager 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.

open as a page

How does automatic access-token refresh work in Spring Security's OAuth2 client, and what are its limits?

level: seniorimportance: should knowfreq 40%

basics

~20 s

If an OAuth2AuthorizedClient has a refresh token and its access token is expired, the RefreshTokenOAuth2AuthorizedClientProvider trades the refresh token for a fresh access token automatically when you next request the client. It never does the initial login.

open as a page

How does Spring Security handle and validate the OIDC id_token during oauth2Login()?

level: seniorimportance: should knowfreq 45%

basics

~20 s

For OIDC logins Spring parses the id_token JWT, checks its signature against the provider's public keys (JWK set), and verifies claims like issuer, audience, expiry, and the nonce. Only if all checks pass is the OidcUser created and the user logged in.

open as a page

Beyond signature verification, what claims should a JWT resource server validate, and how do you add a custom validator such as an audience check?

level: seniorimportance: should knowfreq 52%

basics

~10 s

Validate exp/nbf (timestamps) and iss (issuer) — the defaults cover these when you use issuer-uri. Add an audience (aud) check with a custom OAuth2TokenValidator<Jwt> combined via DelegatingOAuth2TokenValidator and set it on the NimbusJwtDecoder.

open as a page

Introspection adds a network call to every request. How do you design a Spring resource server to keep opaque-token validation performant, and what does that cost you?

level: seniorimportance: should knowfreq 34%

basics

~20 s

Wrap the OpaqueTokenIntrospector in a cache keyed by the token so repeated requests skip the introspection call. Bound the cache by a short TTL and the token's exp. The cost is that a revoked token stays accepted until its cache entry expires.

open as a page

You are running Spring Authorization Server as a multi-instance production IdP. What are the key architectural concerns and how do you address them?

level: principalimportance: should knowfreq 25%

basics

~20 s

Persist clients and authorizations in a shared database (Jdbc*Repository, not in-memory), load stable signing keys from a secret store with a rotation plan, set an explicit issuer that matches the public URL behind your proxy, and enforce PKCE/consent and short token TTLs.

open as a page

For a multi-service platform, how would you design the JWT validation strategy end-to-end (defaults, issuer, audience, clock skew, key rotation) and what are the failure modes you must guard against?

level: principalimportance: should knowfreq 33%

basics

~20 s

Each resource server keeps the default timestamp validator, adds issuer validation bound to the trusted authorization server, and adds an audience validator for its own identifier. Keep clock skew tight, verify signatures against a rotating JWK set by kid, and fail closed on any error.

open as a page

You need to provision local accounts and map provider claims to roles on OAuth2/OIDC login across multiple providers. How do you design this in Spring Security?

level: principalimportance: should knowfreq 35%

basics

~20 s

Plug in a custom OAuth2UserService/OidcUserService that delegates to the default, then enriches the principal: look up or just-in-time create a local account keyed by issuer+subject, and translate provider claims into GrantedAuthorities. Return a custom OAuth2User/OidcUser carrying those authorities.

open as a page

You're setting token strategy for a platform of many microservices behind one authorization server. Argue for opaque introspected tokens vs JWTs, and describe a topology that gets the best of both.

level: principalimportance: should knowfreq 26%

basics

~20 s

Use short-lived JWTs internally for low-latency, no-network validation, and opaque tokens (with introspection) where instant revocation or claim confidentiality matters. A common topology: opaque tokens at the edge, exchanged for internal JWTs, with introspection or a denylist guarding sensitive operations.

open as a page

As a platform architect, how would you handle multi-tenant JWT issuers and decide between local JWT validation and opaque-token introspection?

level: principalimportance: nice to knowfreq 34%

basics

~20 s

For many issuers, use a JwtIssuerAuthenticationManagerResolver so each tenant's iss routes to its own decoder. Choose local JWT validation for speed and offline verification; choose opaque-token introspection when you need instant revocation and central control, at the cost of a network call per request.

open as a page