This is an automated email from the ASF dual-hosted git repository. coheigea pushed a commit to branch coheigea/c_hash in repository https://gitbox.apache.org/repos/asf/cxf.git
commit 8d2db70781a87a20f055f693c10017d64179ad12 Author: Colm O hEigeartaigh <[email protected]> AuthorDate: Wed Jun 17 13:16:50 2026 +0100 Require c_hash for the hybrid case --- .../cxf/rs/security/oidc/idp/IdTokenResponseFilter.java | 3 +++ .../org/apache/cxf/rs/security/oidc/rp/IdTokenReader.java | 14 +++++++++++++- .../cxf/systest/jaxrs/security/oidc/OIDCFlowTest.java | 2 ++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/idp/IdTokenResponseFilter.java b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/idp/IdTokenResponseFilter.java index 674371ea26e..59bba1a6d73 100644 --- a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/idp/IdTokenResponseFilter.java +++ b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/idp/IdTokenResponseFilter.java @@ -56,6 +56,9 @@ public class IdTokenResponseFilter extends OAuthServerJoseJwtProducer implements if (ct.getApprovedScope() == null || !ct.getApprovedScope().contains(OidcUtils.OPENID_SCOPE)) { return; } + if (st.getResponseType() != null) { + ct.getParameters().put(OAuthConstants.RESPONSE_TYPE, st.getResponseType()); + } String idToken = getProcessedIdToken(st); if (idToken != null) { ct.getParameters().put(OidcUtils.ID_TOKEN, idToken); diff --git a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/IdTokenReader.java b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/IdTokenReader.java index a28947d6627..38e0488e838 100644 --- a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/IdTokenReader.java +++ b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/IdTokenReader.java @@ -21,6 +21,7 @@ package org.apache.cxf.rs.security.oidc.rp; import org.apache.cxf.rs.security.jose.jwt.JwtToken; import org.apache.cxf.rs.security.oauth2.client.Consumer; import org.apache.cxf.rs.security.oauth2.common.ClientAccessToken; +import org.apache.cxf.rs.security.oauth2.utils.OAuthConstants; import org.apache.cxf.rs.security.oidc.common.IdToken; import org.apache.cxf.rs.security.oidc.utils.OidcUtils; @@ -44,7 +45,11 @@ public class IdTokenReader extends OidcClaimsValidator { String idJwtToken = at.getParameters().get(OidcUtils.ID_TOKEN); JwtToken jwt = getIdJwtToken(idJwtToken, client); OidcUtils.validateAccessTokenHash(at, jwt, requireAtHash); - OidcUtils.validateCodeHash(code, jwt, requireCodeHash); + if (code != null) { + // The spec requires c_hash to be present in the id_token for hybrid flows, + // but we allow it to be optional for token endpoint id_tokens + OidcUtils.validateCodeHash(code, jwt, requireCodeHash || isHybridFlow(at)); + } return jwt; } public JwtToken getIdJwtToken(ClientAccessToken at, Consumer client) { @@ -55,6 +60,13 @@ public class IdTokenReader extends OidcClaimsValidator { validateJwtClaims(jwt.getClaims(), client.getClientId(), true); return jwt; } + + private boolean isHybridFlow(ClientAccessToken at) { + String responseType = at.getParameters().get(OAuthConstants.RESPONSE_TYPE); + return OidcUtils.CODE_ID_TOKEN_RESPONSE_TYPE.equals(responseType) + || OidcUtils.CODE_ID_TOKEN_AT_RESPONSE_TYPE.equals(responseType); + } + private IdToken getIdTokenFromJwt(JwtToken jwt) { return new IdToken(jwt.getClaims().asMap()); } diff --git a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oidc/OIDCFlowTest.java b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oidc/OIDCFlowTest.java index cd03952ea73..489e2eea5be 100644 --- a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oidc/OIDCFlowTest.java +++ b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oidc/OIDCFlowTest.java @@ -672,6 +672,8 @@ public class OIDCFlowTest extends AbstractBusClientServerTestBase { OAuth2TestUtils.getAccessTokenWithAuthorizationCode(client, code); assertNotNull(accessToken.getTokenKey()); assertTrue(accessToken.getApprovedScope().contains("openid")); + assertEquals(OidcUtils.CODE_ID_TOKEN_RESPONSE_TYPE, + accessToken.getParameters().get(OAuthConstants.RESPONSE_TYPE)); // Check id_token from the token endpoint idToken = accessToken.getParameters().get("id_token");
