HttpSecurity.oauth2Login() provides a number of configuration options for setting up OAuth 2.0 authorization. The main configuration options are grouped by their counterparts for protocol endpoints.

For example, oauth2Login().authorizationEndpoint() allows you to configure an authorization endpoint, while oauth2Login().tokenEndpoint() allows you to configure a token endpoint.

The following code shows an example:

Extended OAuth2 login configuration
Java
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {
	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			.oauth2Login(oauth2 -> oauth2
			    .authorizationEndpoint(authorization -> authorization
			            ...
			    )
			    .redirectionEndpoint(redirection -> redirection
			            ...
			    )
			    .tokenEndpoint(token -> token
			            ...
			    )
			    .userInfoEndpoint(userInfo -> userInfo
			            ...
			    )
			);
		return http.build();
	}
}
Kotlin
@EnableWebSecurity
class OAuth2LoginSecurityConfig {
    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            oauth2Login {
                authorizationEndpoint {
                    ...
                }
                redirectionEndpoint {
                    ...
                }
                tokenEndpoint {
                    ...
                }
                userInfoEndpoint {
                    ...
                }
            }
        }
        return http.build()
    }
}

The main purpose of creating oauth2Login() based on the DSL was to closely match the naming defined in the specifications.

The OAuth 2.0 authorization framework defines protocol endpoints as follows:

The authorization process uses two authorization server endpoints ( HTTP resources):

  • Authorization endpoint: Used by the client to obtain authorization from the owner of the resource through user agent redirection.

  • End token point: Used by a client to exchange access permission for an access token, typically when authenticating the client.

Also one client endpoint:

  • Forwarding endpoint: Used by the authorization server to return responses containing authorization credentials to the client through the resource owner user agent.

The OpenID Connect Core 1.0 specification defines UserInfo endpoint as follows:

The UserInfo endpoint is a protected OAuth resource 2.0, which returns information about the authenticated end user. To obtain the requested end user data, the client makes a request to the UserInfo endpoint using the access token obtained through OpenID Connect authentication. These declared values are typically represented by a JSON object that contains a set of name-value pairs for the declared values.

The following code demonstrates all the configuration options available for oauth2Login() based on DSL:

OAuth2 authorization configuration parameters
Java
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {
	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			.oauth2Login(oauth2 -> oauth2
			    .clientRegistrationRepository(this.clientRegistrationRepository())
			    .authorizedClientRepository(this.authorizedClientRepository())
			    .authorizedClientService(this.authorizedClientService())
			    .loginPage("/login")
			    .authorizationEndpoint(authorization -> authorization
			        .baseUri(this.authorizationRequestBaseUri())
			        .authorizationRequestRepository(this.authorizationRequestRepository())
			        .authorizationRequestResolver(this.authorizationRequestResolver())
			    )
			    .redirectionEndpoint(redirection -> redirection
			        .baseUri(this.authorizationResponseBaseUri())
			    )
			    .tokenEndpoint(token -> token
			        .accessTokenResponseClient(this.accessTokenResponseClient())
			    )
			    .userInfoEndpoint(userInfo -> userInfo
			        .userAuthoritiesMapper(this.userAuthoritiesMapper())
			        .userService(this.oauth2UserService())
			        .oidcUserService(this.oidcUserService())
			    )
			);
		return http.build();
	}
}
Kotlin
@EnableWebSecurity
class OAuth2LoginSecurityConfig {
    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            oauth2Login {
                clientRegistrationRepository = clientRegistrationRepository()
                authorizedClientRepository = authorizedClientRepository()
                authorizedClientService = authorizedClientService()
                loginPage = "/login"
                authorizationEndpoint {
                    baseUri = authorizationRequestBaseUri()
                    authorizationRequestRepository = authorizationRequestRepository()
                    authorizationRequestResolver = authorizationRequestResolver()
                }
                redirectionEndpoint {
                    baseUri = authorizationResponseBaseUri()
                }
                tokenEndpoint {
                    accessTokenResponseClient = accessTokenResponseClient()
                }
                userInfoEndpoint {
                    userAuthoritiesMapper = userAuthoritiesMapper()
                    userService = oauth2UserService()
                    oidcUserService = oidcUserService()
                }
            }
        }
        return http.build()
    }
}

In addition to oauth2Login(), DSL-based configuration also supports XML configuration.

The following code shows all the configuration options available in <security namespace:

OAuth2 login XML configuration options
<http>
	<oauth2-login client-registration-repository-ref="clientRegistrationRepository"
                  authorized-client-repository-ref="authorizedClientRepository"
                  authorized-client-service-ref="authorizedClientService"
                  authorization-request-repository-ref="authorizationRequestRepository"
                  authorization-request-resolver-ref="authorizationRequestResolver"
                  access-token-response-client-ref="accessTokenResponseClient"
                  user-authorities-mapper-ref="userAuthoritiesMapper"
                  user-service-ref="oauth2UserService"
                  oidc-user-service-ref="oidcUserService"
                  login-processing-url="/login/oauth2/code/*"
                  login-page="/login"
                  authentication-success-handler-ref="authenticationSuccessHandler"
                  authentication-failure-handler-ref="authenticationFailureHandler"
                  jwt-decoder-factory-ref="jwtDecoderFactory"/>
</http>

The following sections describe each of the available configuration options in more detail:

  • Page OAuth 2.0 login

  • Redirect endpoint

  • UserInfo endpoint

  • Verifying the ID Token Signature

  • OpenID Connect 1.0 Logout

OAuth 2.0 Login Page

By default, the login page in OAuth 2.0 is automatically generated via DefaultLoginPageGeneratingFilter. The default authorization page displays each configured OAuth client with its ClientRegistration.clientName as a link that can be used to initiate an authorization request (or OAuth 2.0 login).

For DefaultLoginPageGeneratingFilter to display links for configured OAuth clients, the registered ClientRegistrationRepository must also implement Iterable<ClientRegistration>. See InMemoryClientRegistrationRepository for reference.

The default link assignment for each OAuth client is as follows:

OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI + "/{registrationId}"

The following line is an example:

<a href="/oauth2/authorization/google">Google</a>

To override the default login page, configure oauth2Login().loginPage() and (optional) oauth2Login().authorizationEndpoint().baseUri().

The following listing is an example:

OAuth2 Login Page Configuration
Java
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {
	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			.oauth2Login(oauth2 -> oauth2
			    .loginPage("/login/oauth2")
			    ...
			    .authorizationEndpoint(authorization -> authorization
			        .baseUri("/login/oauth2/authorization")
			        ...
			    )
			);
		return http.build();
	}
}
Kotlin
@EnableWebSecurity
class OAuth2LoginSecurityConfig {
    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            oauth2Login {
                loginPage = "/login/oauth2"
                authorizationEndpoint {
                    baseUri = "/login/oauth2/authorization"
                }
            }
        }
        return http.build()
    }
}
Xml
<http>
    <oauth2-login login-page="/login/oauth2"
                     ...
    />
</http>
You need to specify @Controller for the annotation parameter @RequestMapping("/login/oauth2"), which can render a custom login page.

As noted earlier, adding oauth2Login().authorizationEndpoint().baseUri() to the configuration is optional. However, if you choose to customize your settings, make sure that each OAuth client reference matches authorizationEndpoint().baseUri().

The following line is an example:

<a href="/login/oauth2/ authorization/google">Google</a>

Redirect endpoint

The redirect endpoint is used by the authorization server to return an authorization response (which contains the authorization credentials) to the client through the resource owner's user agent.

OAuth 2.0 login uses passcode permission . Therefore, the authorization credential is the authorization code.

The default response to the authorization request for the baseUri (forward endpoint) is /login/oauth2/code/*, which is defined in OAuth2LoginAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI.

If you need to configure the BaseUri authorization response endpoint, configure it , as shown in the following example:

Forwarding endpoint configuration
Java
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {
    @Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			.oauth2Login(oauth2 -> oauth2
			    .redirectionEndpoint(redirection -> redirection
			        .baseUri("/login/oauth2/callback/*")
			        ...
			    )
			);
		return http.build();
	}
}
Kotlin
@EnableWebSecurity
class OAuth2LoginSecurityConfig {
    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            oauth2Login {
                redirectionEndpoint {
                    baseUri = "/login/oauth2/callback/*"
                }
            }
        }
        return http.build()
    }
}
Xml
<http>
    <oauth2-login login-processing-url="/login/oauth2/callback/*"
                  ...
    />
</http>

You also need to make sure that ClientRegistration.redirectUri corresponds to a custom authorization request response for baseUri.

The following listing is an example:

Java
return CommonOAuth2Provider.GOOGLE.getBuilder("google")
	.clientId("google-client-id")
	.clientSecret("google-client-secret")
	.redirectUri("{baseUrl}/login/oauth2/callback/{registrationId}")
    .build();
Kotlin
return CommonOAuth2Provider.GOOGLE.getBuilder("google")
    .clientId("google-client-id")
    .clientSecret("google-client-secret")
    .redirectUri("{baseUrl}/login/oauth2/callback/{registrationId}")
    .build()

UserInfo endpoint

UserInfo endpoint contains a number of configuration options, described in the following subsections:

  • User Permissions Mapping

  • OAuth 2.0 UserService

  • OpenID Connect 1.0 UserService

User Permissions Display

After the user has successfully authenticated through the OAuth 2.0 provider, OAuth2User.getAuthorities() (or OidcUser.getAuthorities()) can be mapped to a new set of GrantedAuthority instances, which will be passed to OAuth2AuthenticationToken when authentication is complete.

OAuth2AuthenticationToken.getAuthorities() is used to authorize requests, for example in hasRole('USER') or hasRole('ADMIN').

There are several options for displaying user permissions:

  • Usage GrantedAuthoritiesMapper

  • Delegation-based strategy using OAuth2UserService

Using GrantedAuthoritiesMapper

Specify the implementation GrantedAuthoritiesMapper and configure it as shown in the following example:

Granted Authorities Mapper Configuration
Java
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {
    @Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			.oauth2Login(oauth2 -> oauth2
			    .userInfoEndpoint(userInfo -> userInfo
			        .userAuthoritiesMapper(this.userAuthoritiesMapper())
			        ...
			    )
			);
		return http.build();
	}
	private GrantedAuthoritiesMapper userAuthoritiesMapper() {
		return (authorities) -> {
			Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
			authorities.forEach(authority -> {
				if (OidcUserAuthority.class.isInstance(authority)) {
					OidcUserAuthority oidcUserAuthority = (OidcUserAuthority)authority;
					OidcIdToken idToken = oidcUserAuthority.getIdToken();
					OidcUserInfo userInfo = oidcUserAuthority.getUserInfo();
					// Display declared values found in idToken and/or userInfo
                    // to one or more GrantedAuthorities and add it to mappedAuthorities
				} else if (OAuth2UserAuthority.class.isInstance(authority)) {
					OAuth2UserAuthority oauth2UserAuthority = (OAuth2UserAuthority)authority;
					Map<String, Object> userAttributes = oauth2UserAuthority.getAttributes();
					// Map the attributes found in userAttributes
                    // to one or more GrantedAuthorities and add it to mappedAuthorities
				}
			});
			return mappedAuthorities;
		};
	}
}
Kotlin
@EnableWebSecurity
class OAuth2LoginSecurityConfig {
    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            oauth2Login {
                userInfoEndpoint {
                    userAuthoritiesMapper = userAuthoritiesMapper()
                }
            }
        }
        return http.build()
    }
    private fun userAuthoritiesMapper(): GrantedAuthoritiesMapper = GrantedAuthoritiesMapper { authorities: Collection<GrantedAuthority> ->
        val mappedAuthorities = emptySet<GrantedAuthority>()
        authorities.forEach { authority ->
            if (authority is OidcUserAuthority) {
                val idToken = authority.idToken
                val userInfo = authority.userInfo
                // Display declared values found in idToken and/or userInfo
                // to one or more GrantedAuthorities and add it to mappedAuthorities
            } else if (authority is OAuth2UserAuthority) {
                val userAttributes = authority.attributes
               	// Map the attributes found in userAttributes
                // to one or more GrantedAuthorities and add it to mappedAuthorities
            }
        }
        mappedAuthorities
    }
}
Xml
<http>
    <oauth2-login user-authorities-mapper-ref="userAuthoritiesMapper"
                  ...
    />
</http>

Alternatively, you can register a @Bean for the GrantedAuthoritiesMapper so that it is automatically applied to the configuration, as shown in the following example:

Configuration for displaying acquired permissions via bean
Java
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {
	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
		    .oauth2Login(withDefaults());
		return http.build();
	}
	@Bean
	public GrantedAuthoritiesMapper userAuthoritiesMapper() {
		...
	}
}
Kotlin
@EnableWebSecurity
class OAuth2LoginSecurityConfig {
    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            oauth2Login { }
        }
        return http.build()
    }
    @Bean
    fun userAuthoritiesMapper(): GrantedAuthoritiesMapper {
        ...
    }
}

Delegation-based strategy using OAuth2UserService

This strategy is more advanced than using GrantedAuthoritiesMapper, however, it is also more flexible because it gives access to OAuth2UserRequest and OAuth2User (when using OAuth 2.0 UserService) or OidcUserRequest and OidcUser (when using OpenID Connect 1.0 UserService).

OAuth2UserRequest (and OidcUserRequest) provides access to the associated OAuth2AccessToken, which is very useful in cases where the delegator needs to obtain permission information from a protected resource before it can display custom permissions to the user.

The following example shows how to implement and configure a strategy based on delegation using OpenID Connect 1.0 UserService:

OAuth2UserService Configuration
Java
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {
	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			.oauth2Login(oauth2 -> oauth2
			    .userInfoEndpoint(userInfo -> userInfo
			        .oidcUserService(this.oidcUserService())
			        ...
			    )
			);
		return http.build();
	}
	private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
		final OidcUserService delegate = new OidcUserService();
		return (userRequest) -> {
			// Delegate the powers of the standard implementation to load the user
			OidcUser oidcUser = delegate.loadUser(userRequest);
			OAuth2AccessToken accessToken = userRequest.getAccessToken();
			Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
			// TODO
            // 1) Retrieve authority information from a protected resource using accessToken
            // 2) Map the authority information to one or more GrantedAuthorities and add it to mappedAuthorities
            // 3) Create a copy of oidcUser, but use mappedAuthorities
			oidcUser = new DefaultOidcUser(mappedAuthorities, oidcUser.getIdToken(), oidcUser.getUserInfo());
			return oidcUser;
		};
	}
}
Kotlin
@EnableWebSecurity
class OAuth2LoginSecurityConfig  {
    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            oauth2Login {
                userInfoEndpoint {
                    oidcUserService = oidcUserService()
                }
            }
        }
        return http.build()
    }
    @Bean
    fun oidcUserService(): OAuth2UserService<OidcUserRequest, OidcUser> {
        val delegate = OidcUserService()
        return OAuth2UserService { userRequest ->
            // Delegate the powers of the standard implementation to load the user
            var oidcUser = delegate.loadUser(userRequest)
            val accessToken = userRequest.accessToken
            val mappedAuthorities = HashSet<GrantedAuthority>()
            // TODO
             // 1) Retrieve authority information from a protected resource using accessToken
            // 2) Map the authority information to one or more GrantedAuthorities and add it to mappedAuthorities
            // 3) Create a copy of oidcUser, but use mappedAuthorities
            oidcUser = DefaultOidcUser(mappedAuthorities, oidcUser.idToken, oidcUser.userInfo)
            oidcUser
        }
    }
}
Xml
<http>
    <oauth2-login oidc-user-service-ref="oidcUserService"
                  ...
    />
</http>

OAuth 2.0 UserService

DefaultOAuth2UserService is an implementation of OAuth2UserService, which supports standard OAuth 2.0 providers.

OAuth2UserService retrieves the user attributes of the end user (owner resource) from the UserInfo endpoint (using the access token provided to the client during the authorization flow) and returns AuthenticatedPrincipal in the form OAuth2User.

DefaultOAuth2UserService uses RestOperations when requesting custom attributes in the UserInfo endpoint.

If you want to configure UserInfo request pre-processing, you can pass DefaultOAuth2UserService.setRequestEntityConverter() with custom Converter<OAuth2UserRequest, RequestEntity<?>>. The standard implementation of OAuth2UserRequestEntityConverter builds a RequestEntity representation of the UserInfo request, which by default sets OAuth2AccessToken in the Authorization header.

On the other hand, if you need to configure post-processing of the UserInfo response, you will need to pass DefaultOAuth2UserService.setRestOperations() with custom configured RestOperations. RestOperations are configured as follows by default:

RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());

OAuth2ErrorResponseErrorHandler is a ResponseErrorHandler that can handle OAuth 2.0 error (400 Bad Request). It uses OAuth2ErrorHttpMessageConverter to convert OAuth 2.0 error parameters to OAuth2Error.

Whether you configure DefaultOAuth2UserService or pass own OAuth2UserService implementation, you will need to configure it as shown in the following example:

Java
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {
	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			.oauth2Login(oauth2 -> oauth2
			    .userInfoEndpoint(userInfo -> userInfo
			        .userService(this.oauth2UserService())
			        ...
			    )
			);
		return http.build();
	}
	private OAuth2UserService<OAuth2UserRequest, OAuth2User> oauth2UserService() {
		...
	}
}
Kotlin
@EnableWebSecurity
class OAuth2LoginSecurityConfig {
    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            oauth2Login {
                userInfoEndpoint {
                    userService = oauth2UserService()
                    // ...
                }
            }
        }
        return http.build()
    }
    private fun oauth2UserService(): OAuth2UserService<OAuth2UserRequest, OAuth2User> {
        // ...
    }
}

OpenID Connect 1.0 UserService

OidcUserService is an implementation of OAuth2UserService that supports the OpenID Connect 1.0 provider.

OidcUserService uses DefaultOAuth2UserService when requesting custom attributes on an endpoint UserInfo.

If you need to configure pre-processing of the UserInfo request and/or post-processing of the UserInfo response, you will need to pass OidcUserService.setOauth2UserService() with a custom configured DefaultOAuth2UserService.

Whether you configure OidcUserService or pass your own OAuth2UserService implementation for the OpenID Connect 1.0 provider, you will need to configure it as shown in the following example :

Java
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {
	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			.oauth2Login(oauth2 -> oauth2
				.userInfoEndpoint(userInfo -> userInfo
				    .oidcUserService(this.oidcUserService())
				    ...
			    )
			);
		return http.build();
	}
	private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
		...
	}
}
Kotlin
@EnableWebSecurity
class OAuth2LoginSecurityConfig {
    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            oauth2Login {
                userInfoEndpoint {
                    oidcUserService = oidcUserService()
                    // ...
                }
            }
        }
        return http.build()
    }
    private fun oidcUserService(): OAuth2UserService<OidcUserRequest, OidcUser> {
        // ...
    }
}

ID token signature verification

OpenID Connect 1.0 authentication provides an ID token, which is a security token containing the end user's claimed authentication values from the authorization server when used by the client.

The ID token is represented as a JSON Web Token (JWT) and MUST be signed with JSON web signatures (JWS).

OidcIdTokenDecoderFactory provides JwtDecoder, used to verify the OidcIdToken signature. The default algorithm is RS256, but it can be different if you assign it during client registration. For such cases, the resolver can be configured to return the expected algorithm for JWS assigned to a specific client.

The algorithm resolver for JWS is a Function that accepts a ClientRegistration and returns the expected JwsAlgorithm for the client, such as SignatureAlgorithm.RS256 or MacAlgorithm.HS256.

The following code demonstrates how configure @Bean for OidcIdTokenDecoderFactory, which will default to MacAlgorithm.HS256 for all ClientRegistration:

Java
@Bean
public JwtDecoderFactory<ClientRegistration> idTokenDecoderFactory() {
    OidcIdTokenDecoderFactory
    idTokenDecoderFactory = new OidcIdTokenDecoderFactory(); idTokenDecoderFactory.setJwsAlgorithmResolver(clientRegistration -> MacAlgorithm.HS256);
    return idTokenDecoderFactory;
}
Kotlin
@Bean
fun idTokenDecoderFactory(): JwtDecoderFactory<ClientRegistration?> {
    val idTokenDecoderFactory = OidcIdTokenDecoderFactory()
    idTokenDecoderFactory.setJwsAlgorithmResolver { MacAlgorithm.HS256 }
    return idTokenDecoderFactory
}
For MAC-based algorithms such as HS256, HS384 or HS512, is used as the symmetric key for signature verification client-secret corresponding to client-id.
If more than one is configured for OpenID Connect 1.0 authentication ClientRegistration, the algorithm resolver for JWS can evaluate the passed ClientRegistration to determine which algorithm to return.

OpenID Connect 1.0 logout

OpenID Connect Session Management 1.0 provides the ability to log the end user logout on the provider side using the client. One of the available strategies is RP-Initiated Logout.

If the OpenID provider supports both session management and discovery, the client can receive URL of the endpoint end_session_endpoint from discovery metadata of the OpenID provider. This can be accomplished by configuring ClientRegistration with issuer-uri, as shown in the following example:

spring:
  security:
    oauth2:
      client:
        registration:
          okta:
            client-id: okta-client-id
            client-secret: okta-client-secret
            ...
        provider:
          okta:
            issuer-uri: https://dev-1234.oktapreview.com

...and the OidcClientInitiatedLogoutSuccessHandler, which implements client-initiated logout, can be configured as follows:

Java
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {
	@Autowired
	private ClientRegistrationRepository clientRegistrationRepository;
	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			.authorizeHttpRequests(authorize -> authorize
				.anyRequest().authenticated()
			)
			.oauth2Login(withDefaults())
			.logout(logout -> logout
				.logoutSuccessHandler(oidcLogoutSuccessHandler())
			);
		return http.build();
	}
	private LogoutSuccessHandler oidcLogoutSuccessHandler() {
		OidcClientInitiatedLogoutSuccessHandler oidcLogoutSuccessHandler =
				new OidcClientInitiatedLogoutSuccessHandler(this.clientRegistrationRepository);
		// Sets the location to which the end user user agent will be redirected
        // after logout on the provider side
		oidcLogoutSuccessHandler.setPostLogoutRedirectUri("{baseUrl}");
		return oidcLogoutSuccessHandler;
	}
}
Kotlin
@EnableWebSecurity
class OAuth2LoginSecurityConfig {
    @Autowired
    private lateinit var clientRegistrationRepository: ClientRegistrationRepository
    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            authorizeRequests {
                authorize(anyRequest, authenticated)
            }
            oauth2Login { }
            logout {
                logoutSuccessHandler = oidcLogoutSuccessHandler()
            }
        }
        return http.build()
    }
    private fun oidcLogoutSuccessHandler(): LogoutSuccessHandler {
        val oidcLogoutSuccessHandler = OidcClientInitiatedLogoutSuccessHandler(clientRegistrationRepository)
        // Sets the location to which the end user user agent will be redirected
        // after logout on the provider side
        oidcLogoutSuccessHandler.setPostLogoutRedirectUri("{baseUrl}")
        return oidcLogoutSuccessHandler
    }
}
OidcClientInitiatedLogoutSuccessHandler supports placeholder {baseUrl}. In case of using the main The app's URL, such as app.example.org will replace it at request time.