I am trying to implement an end-user initiated logout
mechanism.
I have 4 main entities involved.
Angular
app registered as a public OIDC
client on KeycloakSpring Boot
application with a secure REST
endpointWhen the end-user initiates a logout
, a call is made by the Angular
application to Keycloak’s end_session_endpoint
. I have configured the logout
URL for my identity provider (Spring Authorization Server
) in Keycloak as http://localhost:9000/logout which is the default Spring Security
logout endpoint.
FYI: I haven't enabled BackChannel
or FrontChannel
logout.
In the Network
tab of Developer Console
, the sequence of calls happen as below:
While inspecting the DEBUG
logs in the Spring Authorization Server
, I am able to see the logout
happen for that particular end-user including invalidating the JSESSIONID
, however the session doesn’t terminate in Keycloak which causes the user to stay logged in and access the secure REST
endpoint.
Is the Spring Authorization Server
expected to return a specific response back to Keycloak to convey that the logout
process is complete at it’s end and that Keycloak can end the session now?
This is my logic for logout
at Spring Authorization Server
.
@Bean
@Order(Ordered.LOWEST_PRECEDENCE)
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(
authorize -> authorize.mvcMatchers("/hello/**").permitAll().anyRequest().authenticated())
.formLogin(form -> form.loginPage("/login").permitAll())
.addFilterAfter(cookieFilter, ChannelProcessingFilter.class)
.logout().logoutSuccessUrl("http://localhost:4200");
return http.build();
}
I am totally clueless about what I am missing to make Keycloak end the session at it’s end. Any leads will be greatly appreciated.
Thank you!
Update: A post_logout_redirect_uri
parameter is sent in the logout
request to the Spring Authorization Server
. I am not able to see a redirection happen to this URI which may be the reason that Keycloak session doesn't terminate.
post_logout_redirect_uri=http://127.0.0.1:8080/auth/realms/SpringBootKeycloak/broker/oidc/endpoint/logout_response
Got this to work finally!
The logoutSuccessUrl("http://localhost:4200")
is incorrect.
As I mentioned in the Update part of my question that Keycloak sends a post_logout_redirect_uri
parameter (inspected the logout
endpoint in the Network
calls in Chrome Developer Console
), the logoutSuccessUrl
or the redirectUri
should be set to
http://127.0.0.1:8080/auth/realms/SpringBootKeycloak/broker/oidc/endpoint/logout_response
Also, note that the above URL takes in state
as a request parameter. Initially, it gave me a 400 Bad Request
as I didn't send the state
.
Since I was required to intercept the state
parameter when logout
is initiated at the Spring Authorization Server
, I added a custom logout handler to do the job.
@Component
public class IdpLogoutHandler implements LogoutHandler {
private static final String STATE = "state";
@Override
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
String state = request.getParameter(STATE);
try {
response.sendRedirect(
"http://127.0.0.1:8080/auth/realms/SpringBootKeycloak/broker/oidc/endpoint/logout_response?state="
+ state);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Updated WebSecurityConfig
:
http.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(
authorize -> authorize.mvcMatchers("/hello/**").permitAll().anyRequest().authenticated())
.formLogin(form -> form.loginPage("/login").permitAll())
.addFilterAfter(cookieFilter, ChannelProcessingFilter.class).logout()
.addLogoutHandler(customLogoutHandler);