Describe the bug
OIDC Backchannel Logout does not allow logout tokens having typ header of logout+jwt. By default the logoutTokenDecoderFactory creates a decoder that only allows null or JWT and this logoutTokenDecoderFactory doesn't seem to be easily configurable using the DSL.
In the OpenID Connect Back-Channel Logout specification it is recommended that the typ Header Parameter is set with a value of logout+jwt.
To Reproduce
Have an identity provider send a back-channel logout request to the Spring backend with a logout token with typ header of logout+jwt instead of JWT.
An error [invalid_request] An error occurred while attempting to decode the Jwt: JOSE header typ (type) logout+jwt not allowed occurs.
Expected behavior
The OIDC Backchannel Logout should by default accept and process tokens having typ header of logout+jwt.
Comment From: jzheaux
Thanks for the report, @justin-tay.
Since this is not required by the spec, but only recommended, I've published this to main and not backported it to 6.2.x, simply to keep the maintenance branch changes as small as possible. Please let me know, though, if this causes an issue, and we can take another look together at backporting.
Comment From: OLibutzki
Today, Keycloak 25 has been released. In this version they set the type of the backchannel logout request to logout+jwt: https://github.com/keycloak/keycloak/issues/28939
As Keycloak is a very widespread IAM tool, it might be worth thinking about backporting this fix.
Comment From: OLibutzki
@jzheaux I tried to use a custom OidcBackChannelLogoutAuthenticationProvider, but most of the classes are package private and as far as I can see one needs to copy a lot of Spring Security classes to customize the behaviour.
If you have any idea to how workaround this issue, I'd highly appreciate it. Nevertheless, a 6.2.x backport seems to be the best solution.
Comment From: jeffvictor
@OLibutzki Just experienced this issue today. I'm working on an sample project and article for configuring multi tenant login with the latest versions of keycloak (25) and spring boot (spring security 6.3.0).
Obviously I wouldn't recommend this for production but I was able to get it working by building the latest source in the main branch and then using the spring-security-config-6.4.0-SNAPSHOT jar.
It's fine for me since this is just for a sample project which I'll update when spring security 6.4.0 comes out.
Once I started using the new jar I came across another issue which is discussed in #14553. I'm running my spring boot app behind an ngrok tunnel so I had to explicity set the backchannel logout URI as by default it points to localhost WITHOUT the server port which obviously won't work.
.oidcLogout().backChannel(bc -> {bc.logoutUri("http://localhost:" + serverProperties.getPort() + "/logout");})
With this in place backchannel logout works great.
Comment From: OLibutzki
@jeffvictor thanks for confirming.
As you said, in a sample project it's ok to use the latest 6.4.0-SNAPSHOT, but that's not feasable for production.
I created a PR for backporting to 6.2.x: #15277
Comment From: tamasmak
@jzheaux Do you also plan to backport this to 6.3.x?
Comment From: c1rd3cm
Is there any reason that a fix to also support logout+jwt was not done in spring reactive? I'm using Spring Cloud Gateway and I also have the same issue when configuring back channel logout.
Error has been observed at the following site(s):
*__________Mono.error ⇢ at org.springframework.security.config.web.server.OidcBackChannelLogoutReactiveAuthenticationManager.lambda$decode$2(OidcBackChannelLogoutReactiveAuthenticationManager.java:92)
*__Mono.onErrorResume ⇢ at org.springframework.security.config.web.server.OidcBackChannelLogoutReactiveAuthenticationManager.decode(OidcBackChannelLogoutReactiveAuthenticationManager.java:88)
|_ Mono.map ⇢ at org.springframework.security.config.web.server.OidcBackChannelLogoutReactiveAuthenticationManager.authenticate(OidcBackChannelLogoutReactiveAuthenticationManager.java:80)
|_ Mono.map ⇢ at org.springframework.security.config.web.server.OidcBackChannelLogoutReactiveAuthenticationManager.authenticate(OidcBackChannelLogoutReactiveAuthenticationManager.java:83)
*________Mono.flatMap ⇢ at org.springframework.security.config.web.server.OidcBackChannelLogoutWebFilter.filter(OidcBackChannelLogoutWebFilter.java:90)
Caused by: com.nimbusds.jose.proc.BadJOSEException: JOSE header typ (type) logout+jwt not allowed
at com.nimbusds.jose.proc.DefaultJOSEObjectTypeVerifier.verify(DefaultJOSEObjectTypeVerifier.java:148)
at com.nimbusds.jwt.proc.DefaultJWTProcessor.process(DefaultJWTProcessor.java:378)
at com.nimbusds.jwt.proc.DefaultJWTProcessor.process(DefaultJWTProcessor.java:340)
at org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder.createClaimsSet(NimbusReactiveJwtDecoder.java:292)
at org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder$JwkSetUriReactiveJwtDecoderBuilder.lambda$processor$13(NimbusReactiveJwtDecoder.java:449)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:113)
at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onNext(FluxOnAssembly.java:539)