Comprehensive OAuth2 and OpenID Connect (OIDC) support including OAuth2 client, resource server, and authorization server configuration.
Configure OAuth2/OIDC login for single sign-on.
package org.springframework.security.config.annotation.web.configurers.oauth2.client;
public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
extends AbstractAuthenticationFilterConfigurer<B, OAuth2LoginConfigurer<B>,
OAuth2LoginAuthenticationFilter> {
public OAuth2LoginConfigurer<B> loginPage(String loginPage);
public OAuth2LoginConfigurer<B> authorizationEndpoint(
Customizer<AuthorizationEndpointConfig> authorizationEndpointCustomizer
);
public OAuth2LoginConfigurer<B> redirectionEndpoint(
Customizer<RedirectionEndpointConfig> redirectionEndpointCustomizer
);
public OAuth2LoginConfigurer<B> tokenEndpoint(
Customizer<TokenEndpointConfig> tokenEndpointCustomizer
);
public OAuth2LoginConfigurer<B> userInfoEndpoint(
Customizer<UserInfoEndpointConfig> userInfoEndpointCustomizer
);
public OAuth2LoginConfigurer<B> clientRegistrationRepository(
ClientRegistrationRepository clientRegistrationRepository
);
public OAuth2LoginConfigurer<B> authorizedClientService(
OAuth2AuthorizedClientService authorizedClientService
);
public OAuth2LoginConfigurer<B> authorizedClientRepository(
OAuth2AuthorizedClientRepository authorizedClientRepository
);
public OAuth2LoginConfigurer<B> loginProcessingUrl(String loginProcessingUrl);
public OAuth2LoginConfigurer<B> successHandler(
AuthenticationSuccessHandler successHandler
);
public OAuth2LoginConfigurer<B> failureHandler(
AuthenticationFailureHandler failureHandler
);
public OAuth2LoginConfigurer<B> permitAll();
}Usage Example:
http
.oauth2Login(oauth2 -> oauth2
.loginPage("/login")
.defaultSuccessUrl("/dashboard")
.userInfoEndpoint(userInfo -> userInfo
.userService(customOAuth2UserService)
.oidcUserService(customOidcUserService)
)
.tokenEndpoint(token -> token
.accessTokenResponseClient(customAccessTokenResponseClient)
)
);
// application.yml configuration
spring:
security:
oauth2:
client:
registration:
google:
client-id: YOUR_CLIENT_ID
client-secret: YOUR_CLIENT_SECRET
scope:
- openid
- profile
- email
provider:
google:
issuer-uri: https://accounts.google.comConfigure OAuth2 client for accessing protected resources.
package org.springframework.security.config.annotation.web.configurers.oauth2.client;
public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>>
extends AbstractHttpConfigurer<OAuth2ClientConfigurer<B>, B> {
public OAuth2ClientConfigurer<B> clientRegistrationRepository(
ClientRegistrationRepository clientRegistrationRepository
);
public OAuth2ClientConfigurer<B> authorizedClientRepository(
OAuth2AuthorizedClientRepository authorizedClientRepository
);
public OAuth2ClientConfigurer<B> authorizedClientService(
OAuth2AuthorizedClientService authorizedClientService
);
public OAuth2ClientConfigurer<B> authorizationCodeGrant(
Customizer<AuthorizationCodeGrantConfigurer> authorizationCodeGrantCustomizer
);
}Usage Example:
http
.oauth2Client(Customizer.withDefaults());
// Use in controller
@RestController
public class ApiController {
@GetMapping("/api/data")
public String getData(@RegisteredOAuth2AuthorizedClient("my-client") OAuth2AuthorizedClient authorizedClient) {
String accessToken = authorizedClient.getAccessToken().getTokenValue();
// Use access token to call external API
return restTemplate.exchange(
"https://api.example.com/data",
HttpMethod.GET,
new HttpEntity<>(createHeaders(accessToken)),
String.class
).getBody();
}
}Configure OAuth2 resource server with JWT or opaque token validation.
package org.springframework.security.config.annotation.web.configurers.oauth2.server.resource;
public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<OAuth2ResourceServerConfigurer<H>, H> {
public OAuth2ResourceServerConfigurer<H> jwt(
Customizer<JwtConfigurer> jwtCustomizer
);
public OAuth2ResourceServerConfigurer<H> opaqueToken(
Customizer<OpaqueTokenConfigurer> opaqueTokenCustomizer
);
public OAuth2ResourceServerConfigurer<H> authenticationManagerResolver(
AuthenticationManagerResolver<HttpServletRequest> authenticationManagerResolver
);
public OAuth2ResourceServerConfigurer<H> authenticationEntryPoint(
AuthenticationEntryPoint entryPoint
);
public OAuth2ResourceServerConfigurer<H> bearerTokenResolver(
BearerTokenResolver bearerTokenResolver
);
public OAuth2ResourceServerConfigurer<H> accessDeniedHandler(
AccessDeniedHandler accessDeniedHandler
);
// JWT Configurer
public final class JwtConfigurer {
public JwtConfigurer decoder(JwtDecoder jwtDecoder);
public JwtConfigurer jwkSetUri(String jwkSetUri);
public JwtConfigurer jwtAuthenticationConverter(Converter<Jwt, ? extends AbstractAuthenticationToken> jwtAuthenticationConverter);
public JwtConfigurer jwtAuthenticationConverter(JwtAuthenticationConverter jwtAuthenticationConverter);
}
// Opaque Token Configurer
public final class OpaqueTokenConfigurer {
public OpaqueTokenConfigurer introspectionUri(String introspectionUri);
public OpaqueTokenConfigurer introspectionClientCredentials(String clientId, String clientSecret);
public OpaqueTokenConfigurer introspector(OpaqueTokenIntrospector introspector);
}
}Usage Examples:
// JWT Resource Server
http
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/api/public/**").permitAll()
.requestMatchers("/api/**").hasAuthority("SCOPE_read")
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> jwt
.jwkSetUri("https://idp.example.com/.well-known/jwks.json")
.jwtAuthenticationConverter(jwtAuthenticationConverter())
)
);
// Using issuer URI (auto-configuration)
http
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(Customizer.withDefaults())
);
// application.yml
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://idp.example.com
// Opaque Token Resource Server
http
.oauth2ResourceServer(oauth2 -> oauth2
.opaqueToken(opaque -> opaque
.introspectionUri("https://idp.example.com/introspect")
.introspectionClientCredentials("client-id", "client-secret")
)
);
// Custom JWT authentication converter
@Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
JwtGrantedAuthoritiesConverter authoritiesConverter = new JwtGrantedAuthoritiesConverter();
authoritiesConverter.setAuthoritiesClaimName("roles");
authoritiesConverter.setAuthorityPrefix("ROLE_");
converter.setJwtGrantedAuthoritiesConverter(authoritiesConverter);
return converter;
}
// Accessing JWT claims in controller
@GetMapping("/user")
public Map<String, Object> user(@AuthenticationPrincipal Jwt jwt) {
return Map.of(
"sub", jwt.getSubject(),
"email", jwt.getClaim("email"),
"roles", jwt.getClaim("roles")
);
}Configure OAuth2 authorization server.
package org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization;
public final class OAuth2AuthorizationServerConfigurer
extends AbstractHttpConfigurer<OAuth2AuthorizationServerConfigurer, HttpSecurity> {
public OAuth2AuthorizationServerConfigurer clientAuthentication(
Customizer<OAuth2ClientAuthenticationConfigurer> clientAuthenticationCustomizer
);
public OAuth2AuthorizationServerConfigurer authorizationEndpoint(
Customizer<OAuth2AuthorizationEndpointConfigurer> authorizationEndpointCustomizer
);
public OAuth2AuthorizationServerConfigurer pushedAuthorizationRequestEndpoint(
Customizer<OAuth2PushedAuthorizationRequestEndpointConfigurer> parEndpointCustomizer
);
public OAuth2AuthorizationServerConfigurer tokenEndpoint(
Customizer<OAuth2TokenEndpointConfigurer> tokenEndpointCustomizer
);
public OAuth2AuthorizationServerConfigurer tokenIntrospectionEndpoint(
Customizer<OAuth2TokenIntrospectionEndpointConfigurer> tokenIntrospectionEndpointCustomizer
);
public OAuth2AuthorizationServerConfigurer tokenRevocationEndpoint(
Customizer<OAuth2TokenRevocationEndpointConfigurer> tokenRevocationEndpointCustomizer
);
public OAuth2AuthorizationServerConfigurer deviceAuthorizationEndpoint(
Customizer<OAuth2DeviceAuthorizationEndpointConfigurer> deviceAuthorizationEndpointCustomizer
);
public OAuth2AuthorizationServerConfigurer deviceVerificationEndpoint(
Customizer<OAuth2DeviceVerificationEndpointConfigurer> deviceVerificationEndpointCustomizer
);
public OAuth2AuthorizationServerConfigurer clientRegistrationEndpoint(
Customizer<OAuth2ClientRegistrationEndpointConfigurer> clientRegistrationEndpointCustomizer
);
public OAuth2AuthorizationServerConfigurer authorizationServerMetadataEndpoint(
Customizer<OAuth2AuthorizationServerMetadataEndpointConfigurer> authorizationServerMetadataEndpointCustomizer
);
public OAuth2AuthorizationServerConfigurer oidc(
Customizer<OidcConfigurer> oidcCustomizer
);
public RequestMatcher getEndpointsMatcher();
// OIDC Configurer
public final class OidcConfigurer {
public OidcConfigurer userInfoEndpoint(
Customizer<OidcUserInfoEndpointConfigurer> userInfoEndpointCustomizer
);
public OidcConfigurer providerConfigurationEndpoint(
Customizer<OidcProviderConfigurationEndpointConfigurer> providerConfigurationEndpointCustomizer
);
public OidcConfigurer clientRegistrationEndpoint(
Customizer<OidcClientRegistrationEndpointConfigurer> clientRegistrationEndpointCustomizer
);
public OidcConfigurer logoutEndpoint(
Customizer<OidcLogoutEndpointConfigurer> logoutEndpointCustomizer
);
}
}Usage Example:
@Configuration
public class AuthorizationServerConfig {
@Bean
@Order(1)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfigurer authzServer =
new OAuth2AuthorizationServerConfigurer();
http
.securityMatcher(authzServer.getEndpointsMatcher())
.with(authzServer, authz -> authz
.oidc(oidc -> oidc
.userInfoEndpoint(userInfo -> userInfo
.userInfoMapper(context -> {
// Custom user info mapping
})
)
)
)
.authorizeHttpRequests(authorize -> authorize
.anyRequest().authenticated()
);
return http.build();
}
@Bean
public RegisteredClientRepository registeredClientRepository() {
RegisteredClient client = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId("client-id")
.clientSecret("{noop}secret")
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.redirectUri("http://localhost:8080/login/oauth2/code/client")
.scope(OidcScopes.OPENID)
.scope(OidcScopes.PROFILE)
.scope("read")
.scope("write")
.clientSettings(ClientSettings.builder()
.requireAuthorizationConsent(true)
.requireProofKey(true)
.build())
.tokenSettings(TokenSettings.builder()
.accessTokenTimeToLive(Duration.ofHours(1))
.refreshTokenTimeToLive(Duration.ofDays(7))
.reuseRefreshTokens(false)
.build())
.build();
return new InMemoryRegisteredClientRepository(client);
}
@Bean
public OAuth2AuthorizationService authorizationService() {
return new InMemoryOAuth2AuthorizationService();
}
@Bean
public OAuth2AuthorizationConsentService authorizationConsentService() {
return new InMemoryOAuth2AuthorizationConsentService();
}
@Bean
public JWKSource<SecurityContext> jwkSource() {
KeyPair keyPair = generateRsaKey();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
RSAKey rsaKey = new RSAKey.Builder(publicKey)
.privateKey(privateKey)
.keyID(UUID.randomUUID().toString())
.build();
JWKSet jwkSet = new JWKSet(rsaKey);
return new ImmutableJWKSet<>(jwkSet);
}
@Bean
public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
}
@Bean
public AuthorizationServerSettings authorizationServerSettings() {
return AuthorizationServerSettings.builder()
.issuer("http://localhost:9000")
.build();
}
}Configure OpenID Connect logout (back-channel and front-channel).
package org.springframework.security.config.annotation.web.configurers.oauth2.client;
public final class OidcLogoutConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<OidcLogoutConfigurer<H>, H> {
public OidcLogoutConfigurer<H> backChannel(
Customizer<BackChannelLogoutConfigurer> backChannelCustomizer
);
// Back-Channel Logout Configurer
public final class BackChannelLogoutConfigurer {
public BackChannelLogoutConfigurer logoutUri(String logoutUri);
public BackChannelLogoutConfigurer logoutHandler(OidcBackChannelLogoutHandler logoutHandler);
}
}Usage Example:
http
.oauth2Login(Customizer.withDefaults())
.oidcLogout(oidcLogout -> oidcLogout
.backChannel(Customizer.withDefaults())
);// Client Registration
public final class ClientRegistration {
public String getRegistrationId();
public String getClientId();
public String getClientSecret();
public ClientAuthenticationMethod getClientAuthenticationMethod();
public AuthorizationGrantType getAuthorizationGrantType();
public String getRedirectUri();
public Set<String> getScopes();
public ProviderDetails getProviderDetails();
}
// OAuth2 Authorized Client
public class OAuth2AuthorizedClient {
public ClientRegistration getClientRegistration();
public String getPrincipalName();
public OAuth2AccessToken getAccessToken();
public OAuth2RefreshToken getRefreshToken();
}
// OAuth2 Access Token
public class OAuth2AccessToken {
public TokenType getTokenType();
public String getTokenValue();
public Instant getIssuedAt();
public Instant getExpiresAt();
public Set<String> getScopes();
}
// JWT
public interface Jwt extends AbstractOAuth2Token {
Map<String, Object> getClaims();
Map<String, Object> getHeaders();
String getSubject();
Instant getIssuedAt();
Instant getExpiresAt();
<T> T getClaim(String claim);
}