Summary
Before my final logout success redirect, I am attempting to make an additional call to a logout endpoint given by my OpenID provider.
The provider (login.gov) states that my logout request should have this form:
https://idp.int.identitysandbox.gov/openid_connect/logout?
id_token_hint=eyJ0eX...&
post_logout_redirect_uri=${REDIRECT_URI}&
state=abcdefghijklmnopabcdefghijklmnop`
Where id_token_hint is:
An id_token value from the token endpoint response.
Their doc: https://developers.login.gov/oidc/#logout
Actual Behavior
1) I login via my /login endpoint.
2) I verify I can obtain my user info by hitting my /login_profile endpoint.
3) I navigate to /logout.
4) Upon reaching the onLogoutSuccess callback of SimpleUrlLogoutSuccessHandler, I receive a cast error:
java.lang.ClassCastException: org.springframework.security.oauth2.core.user.DefaultOAuth2User cannot be cast to org.springframework.security.oauth2.core.oidc.user.OidcUser
I attempt this by casting my Authentication object as a OAuth2AuthenticationToken. That cast is successful, but I cannot cast the principal of that new object as an OidcUser. It is assuming the principal is an OAuth2User which does not have an idToken property.
Expected Behavior
I expect to be able to retrieve the id_token (a signed JWT) that was originally returned from my token request from my onLogoutSuccess method.
override fun onLogoutSuccess(request: HttpServletRequest?, response: HttpServletResponse?, authentication: Authentication?) {
val authenticationToken: OAuth2AuthenticationToken = authentication as OAuth2AuthenticationToken
val user: OidcUser = authenticationToken.principal as OidcUser
val idToken: OidcIdToken = user.idToken
Configuration
override fun configure(http: HttpSecurity) {
http.authorizeRequests()
// login, login failure, and index are allowed by anyone
.antMatchers(
LOGIN_ENDPOINT,
LOGIN_SUCCESS_ENDPOINT,
LOGIN_PROFILE_ENDPOINT,
LOGIN_FAILURE_ENDPOINT,
LOGOUT_ENDPOINT,
LOGOUT_SUCCESS_ENDPOINT,
"/"
)
.permitAll()
// any other requests are allowed by an authenticated user
.anyRequest()
.authenticated()
.and()
// custom logout behavior
.logout()
.logoutRequestMatcher(AntPathRequestMatcher(LOGOUT_ENDPOINT))
.logoutSuccessUrl(LOGOUT_SUCCESS_ENDPOINT)
.deleteCookies("JSESSIONID")
.invalidateHttpSession(true)
.logoutSuccessHandler(LoginGovLogoutSuccessHandler(authorizedClientService))
.and()
// configure authentication support using an OAuth 2.0 and/or OpenID Connect 1.0 Provider
.oauth2Login()
.authorizationEndpoint()
.authorizationRequestResolver(LoginGovAuthorizationRequestResolver(clientRegistrationRepository))
.authorizationRequestRepository(authorizationRequestRepository())
.and()
.tokenEndpoint()
.accessTokenResponseClient(accessTokenResponseClient())
.and()
.failureUrl(LOGIN_FAILURE_ENDPOINT)
.successHandler(LoginGovAuthenticationSuccessHandler())
}
Version
springBootVersion = '2.1.0.RELEASE'
Sample
Here is my project on GitHub.
Please refer to the class LoginGovLogoutSuccessHandler for the code in question.
Comment From: jgrandja
@forgo I believe the issue you are having is related to your scope: openid email configuration. The scope(s) should be comma separated so scope: openid, email - the YAML reader will read this into 2 elements instead of 1 element containing both scopes, as in your case, which results in you NOT going through the OpenID Connect flow - hence no ID Token and your Principal is DefaultOAuth2User.
Try that out and let me know how it goes.
Comment From: forgo
@jgrandja
Like a boss, dude! I think I originally had a "+" between "openid" and "email", and that was causing problems until I added the space. I would have been lost without this suggestion. That comma allowed my cast to succeed so I could extract the id_token!
Thanks again!
Comment From: IrfanOjas
Hi i am also facing the same issue i,e java.lang.ClassCastException: org.springframework.security.oauth2.core.user.DefaultOAuth2User cannot be cast to org.springframework.security.oauth2.core.oidc.user.OidcUser
Here i am only using an offline scope in my client application. Can someone please help to resolve the issue.