I'm new to using Spring Boot and Spring security; I'm trying to build an Identity broker with Spring security Oauth2 components. The broker handles all the authorization, token and logout requests from my SPA(React) clients. It then delegates authentication to an external Identity Provider (Keycloak) which supports RP initiated logout.
I'm following the Federated Identity Sample provided in this issue.
The login works fine without any issues. As for logout, only the local session within the Identity broker is cleared. There is no request firing to the Identity provider's end_session_endpoint
.
I did some reading and found the following code in the Spring security docs.
@Configuration
@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 that the End-User's User Agent will be redirected to
// after the logout has been performed at the Provider
oidcLogoutSuccessHandler.setPostLogoutRedirectUri("{baseUrl}");
return oidcLogoutSuccessHandler;
}
}
I configured the LogoutSuccessHandler
to the Security filter chain. However, it is not being invoked when logout request is issued to the end_session_endpoint
of my Identity broker /connect/logout
from my React SPA. The parameters to the request are id_token_hint
and post_logout_redirect_uri
which is a Uri in my React app registered with my Identity broker (Authorization Server).
After some debugging, I noticed that the OidcLogoutEndpointFilter
configured by default, handles the logout request at /connect/logout
and checks for a post_logout_redirect_uri
in the parameters and redirects to it.
How can I implement the RP initiated logout through my Identity broker in this scenario? The expected behavior is when I logout from my React app, the Identity broker issues logout request to the Federated Identity Provider, clears the local session and redirects back to my app.
I have found several questions and issues around this topic, but none that fits this specific case. Please point out to me if this has already been answered and I failed to find it. Thanks!
I'm posting a solution that worked well for me.
After some reading, I found from the spring docs, and oidcLogoutEndpointFilter
that the logoutResponseHandler
is configurable. It is basically an implementation of the AuthenticationSuccessHandler
interface.
In my custom implementation of this interface, first, clearing out the local session associated with the requesting client by invoking the SecurityContextLogoutHandler
. Then, constructing a redirect url using the end_session_endpoint
of the external IdP, id_token
issued by the external IdP, and the post_logout_redirect_uri
from the original logout request and sending a redirect response back to the browser (https://external-idp.com/connect/logout?id_token_hint=''&post_logout_redirect_uri='')
. Then, I configured this implementation as the logoutResponseHandler
to the oidc.logoutEndpoint
in the SecurityFilterChain
for authorization server.
This way, the user's session in the Identity broker is cleared as usual, and the session in the external IdP is also cleared by sending a request to its end_session_endpoint
from the user's browser.