OpenID Connect Logout Options with Spring Boot

OpenID Connect Logout Options with Spring Boot

This tutorial demonstrates the logout options you have when developing Spring applications and helps you pick the right one for you!

Soumya D

I am getting below issue with same code, please help:

Field clientRegistrationRepository in com.test.spring.okta.sso.SecurityConfiguration required a bean of type ‘org.springframework.security.oauth2.client.registration.ClientRegistrationRepository’ that could not be found.

The injection point has the following annotations:

- @org.springframework.beans.factory.annotation.Autowired(required=true)

The following candidates were found but could not be injected:

- Bean method ‘clientRegistrationRepository’ in ‘OAuth2ClientRegistrationRepositoryConfiguration’ not loaded because OAuth2 Clients Configured Condition registered clients is not available

I am trying to implement a custom logoutSuccessHandler that logs the logout:

@Component
public class myLogoutHandler extends SimpleUrlLogoutSuccessHandler {
    @Value( "${okta.oauth2.postLogoutRedirectUri}" )
    private String postLogoutRedirectUri;

    @PostConstruct
    public void init() {
        logger.info(postLogoutRedirectUri);
        super.setDefaultTargetUrl(postLogoutRedirectUri);
    }

    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
            throws IOException, ServletException {
        if (authentication != null) {
            logger.info("Logging out user " + authentication.getPrincipal().toString() );
        } else {
            logger.info("Logout after session expiration");
        }
        super.onLogoutSuccess(request, response, authentication);
    }
}

I Autowire this in the SpringSecurityConfig and set it as the logoutSuccessHandler:

    @Autowired
    private myLogoutHandler logoutSuccessHandler;

...

            .and().logout().logoutSuccessHandler(logoutSuccessHandler)

The Component is properly configured with my redirectURL (I see the log entry), and when I submit a form with action “/logout”, I get logged out, but there is no log entry. Several questions:

  1. What am I doing wrong?
  2. Is there an easier way to do this?
  3. Am I breaking my security by not using OidcClientInitiatedLogoutSuccessHandler? I can’t subclass it because it is final, but I can probably figure out a way to get around that.

OK, the correct answer is #2, there is an easier way to do this:

@Component
public class myLogoutHandler implements LogoutHandler {
    private static final Logger log = LogManager.getLogger(myLogoutHandler.class);
    @Override
    public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
        if (authentication != null) {
            String username = "unknown";
            if (authentication.getPrincipal() instanceof UserDetails) {
                UserDetails springSecurityUser = (UserDetails) authentication.getPrincipal();
                username = springSecurityUser.getUsername();
            } else if (authentication.getPrincipal() instanceof DefaultOidcUser) {
                DefaultOidcUser user = (DefaultOidcUser) authentication.getPrincipal();
                username = user.getName();
            } else if (authentication.getPrincipal() instanceof String) {
                username =  (String) authentication.getPrincipal();
            }
            log.info("Logging out user " + username );
        } else {
            log.info("Logout after session expiration");
        }        
    }
}

And in SpringSecurityConfig:

           .addLogoutHandler(logoutHandler)

Hi @jeffemandel!

I’m not sure I’m following the question and example correctly, so I’ll try to fill in some background, but if I missed the mark or didn’t answer your question, please let me know.

As mentioned in the blog post there are two different ways to “log out” of an OIDC application.

  1. Log out of just the application (this is the default behavior)
  2. Log out of the application AND from the IdP.

The 2nd option will log out of ALL applications, so if you are doing some sort of SSO, or social login, this might not be what you want.

I like to think about the two options similar to a social auth, think about how you could “Login with GitHub” to a 3rd party application. The 3rd party application wouldn’t be allowed to log you out of GitHub, but you could still log out of that 3rd party application.

If you only have a single application, then you may want to log out of the IdP as well

It’s not clear what your myLogoutHandler does other than ad a log message?

A quick note about logging, Spring Security’s log is sparse by default, if you need more info you would need to turn up the log levels under org.springframework.security.

Can you describe your use case a bit more, maybe I can give more specific advice?

How can I logout from custom filter ?

override fun filter(exchange: ServerWebExchange, chain: GatewayFilterChain): Mono {
var uri = URI.create(“http://localhost:8080/logout”)

    val modifiedRequest = exchange
        .request
        .mutate()
        .uri(uri)
        .build();

    val modifiedExchange = exchange
        .mutate()
        .request(modifiedRequest)
        .build()
    modifiedExchange.attributes[ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR] = uri

    return chain.filter(modifiedExchange)
}

Hi @rahul6941!

I’m not sure I’m following your example code. However, registering the logout handler for a reactive app would look something like:

// httpSecurity is a ServerHttpSecurity
// inject the ReactiveClientRegistrationRepository (repository)

OidcClientInitiatedServerLogoutSuccessHandler logoutSuccessHandler = new OidcClientInitiatedServerLogoutSuccessHandler(repository);
logoutSuccessHandler.setPostLogoutRedirectUri("{baseUrl}/your/path/here");

httpSecurity.logout().logoutSuccessHandler(logoutSuccessHandler);

This should be the same for Spring Cloud Gateway or any other reactive Spring Boot app.

Let me know if I didn’t answer your question!

How can I logout from filter ? in other words I need to implement force logout through programmatically

Can you provide more context of how/when you are logging out? Are you just trying to end the current session? see:
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/server/WebSession.html#invalidate--

Or are you trying to end the remote session (an RP Initiated logout?)

Issue: Spring Boot/Security is not redirecting to Okta logout URL

Description: I tried Logout sample application as given in OpenID Connect Logout Options with Spring Boot , it is working as expected.
But with the same configurations, we are unable to logout from Okta in our main/ organizations’ Application.

Expected Flow:
Step 1 - On logout button click, UI calls ‘…/testbootapp/logout’ → Spring Security by default handles logout Spring Boot logout
Step 2 - ‘OidcClientInitiatedLogoutSuccessHandler’ is configured in SpringBoot application, this should redirect to Okta logout URL
--- Here, in our application Spring Security is not redirecting to Okta logout URL

Implementation Details:

  • Spring boot dependency version: 2.7.0
  • application.properties is same as defined in blog
  • SecurityConfiguration class:

After enabling spring security logs in our application, we saw that ‘o.s.s.web.DefaultRedirectStrategy’ does not generate Okta logout URL, instead redirects to applications root

Our Application:

Jul 21 2022 12:47:16 PM IST DEBUG o.s.s.w.a.l.SecurityContextLogoutHandler -Invalidated session 280BDF27CFF81149D6C829EF2ADAC9DF
Jul 21 2022 12:47:16 PM IST DEBUG o.s.s.web.DefaultRedirectStrategy -Redirecting to /testbootapp/

Sample application given in blog:

2022-07-21 11:25:20.230 DEBUG 7382 — [nio-8080-exec-5] o.s.s.w.a.l.SecurityContextLogoutHandler : Invalidating session: C54C40030C14B14F9F03250B769D2E99
2022-07-21 11:25:20.231 DEBUG 7382 — [nio-8080-exec-5] o.s.s.web.DefaultRedirectStrategy : Redirecting to ‘https://dev-.oktapreview.com/oauth2/default/v1/logout?id_token_hint=&post_logout_redirect_uri=https://twitter.com/’

A couple of ideas to try:

Reduce the complexity of your configuration until you narrow down what is the cause.
For example, temporarily remove the httpBasic filter

If that doesn’t help, add a breakpoint in the OidcClientInitiatedLogoutSuccessHandler class and step through to see what condition is getting triggered.

@bdemers,

While debugging we saw that: org.springframework.security.oauth2.client.oidc.web.logout.OidcClientInitiatedLogoutSuccessHandler#determineTargetUrl method is called

1- With httpBasic
‘authentication’ parameter is an instance of org.springframework.security.authentication.UsernamePasswordAuthenticationToken, while the expected type is: org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken

2- After removing httpBasic
‘authentication’ parameter is null, while the expected type is: org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken

A Filter Chain is executed and it is unclear what determines authentication object type, how to debug further?

For your #1, are you logging in with OAuth or basic auth?

hi okta Dev community,
I created a local spring boot app and integrated with okta having Authorization code grant type. When i access the api, it redirects to okta login page and after successful authentication, i am able to access to api. Till here everyting is good.

Now I want to log out from okta and redirect to okta login page. I found below api for this -
GET https://${baseUrl}/logout?id_token_hint=${id_token}
Now my problem is how can i get this id_token in my local spring boot app. I tried several docs, but no luck. Please help.

Hi @ajay.surendrakumar

You shouldn’t need to call that API directly. Spring Security will handle it automatically when configured.
Take a look at the example code in this post related to the logoutSuccessHandler() method.

If that doesn’t help, can you share more details about your application?

1 Like

hi @bdemers , Thanks you for your article and advice. it was great help

hi @bdemers and okta dev team,
we have a legacy spring web app**(its not spring boot app)** . we are trying to login- authenticate via OKTA sign in page.
Currently, we can login in the application using credentials but now we want to authenticate via okta sign in page (grant type - authorization code). It means when we access the login page, it should redirect to okta sign page and then it should allow for app access.
Can you please provide reference/documentation for the same?

hi @bdemers and okta dev team,
In the above example we are using a single post redirect url. Is it possible to make is dynamic.
For example, call a custom logout api in the controller and and get the redirect url as query parameter and pass to oidcLogoutSuccessHandler to logout from okta and do the redirect.

Hi @ajay.surendrakumar !

Sorry I missed your previous question.

I’m not 100% what you are asking, but my general suggestion is if you are not on a current/supported version of spring (or other framework) is to handle the OAuth bits in another service (Spring Cloud Gateway, OAuth2-Proxy, etc.)

If those links don’t help, let us know!

hi @bdemers , Thanks for the links . I will go through them.

Currently we are trying to logout via controller and redirect to query parameter.
I have created a custom controller
@GetMapping(“/customLogout”)
public void logoutPage (HttpServletRequest request, HttpServletResponse response, @RequestParam(“redirectUrl”) String redirectUrl {

Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null){    
    new SecurityContextLogoutHandler().logout(request, response, auth);
}

response.redirect(redirectUrl);
}
This don’t logs out from okta. Kindly help on this.