This is an automated email from the ASF dual-hosted git repository. gnodet pushed a commit to branch fix/rfc9068-at-jwt-type in repository https://gitbox.apache.org/repos/asf/cxf.git
commit f474343721ee59663ac6fc26f91200c82be680c0 Author: Guillaume Nodet <[email protected]> AuthorDate: Wed Mar 11 18:16:17 2026 +0100 RFC 9068: Set typ header to at+jwt for JWT access tokens Per RFC 9068 Section 2.1, JWT access tokens MUST include a typ header parameter set to "at+jwt". This change: - Adds TYPE_AT_JWT constant to JoseConstants - Adds AT_JWT member to JoseType enum with proper lookup - Sets the at+jwt type on both JWS and JWE headers when producing JWT access tokens in AbstractOAuthDataProvider Closes #990 Co-Authored-By: Claude Opus 4.6 <[email protected]> --- .../java/org/apache/cxf/rs/security/jose/common/JoseConstants.java | 1 + .../main/java/org/apache/cxf/rs/security/jose/common/JoseType.java | 5 ++++- .../cxf/rs/security/oauth2/provider/AbstractOAuthDataProvider.java | 7 ++++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/JoseConstants.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/JoseConstants.java index 092581d3fd..017f814411 100644 --- a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/JoseConstants.java +++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/JoseConstants.java @@ -43,6 +43,7 @@ public final class JoseConstants extends RSSecurityConstants { public static final String JWS_HEADER_B64_STATUS_HEADER = "b64"; public static final String TYPE_JWT = "JWT"; + public static final String TYPE_AT_JWT = "at+jwt"; public static final String TYPE_JOSE = "JOSE"; public static final String TYPE_JOSE_JSON = "JOSE+JSON"; public static final String MEDIA_TYPE_JOSE = "application/jose"; diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/JoseType.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/JoseType.java index 647fb163fe..cea5fdf0a8 100644 --- a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/JoseType.java +++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/JoseType.java @@ -22,7 +22,8 @@ package org.apache.cxf.rs.security.jose.common; public enum JoseType { JOSE(JoseConstants.TYPE_JOSE), JOSE_JSON(JoseConstants.TYPE_JOSE_JSON), - JWT(JoseConstants.TYPE_JWT); + JWT(JoseConstants.TYPE_JWT), + AT_JWT(JoseConstants.TYPE_AT_JWT); private final String type; JoseType(String type) { @@ -33,6 +34,8 @@ public enum JoseType { return null; } else if (JoseConstants.TYPE_JOSE_JSON.equals(type)) { return JOSE_JSON; + } else if (JoseConstants.TYPE_AT_JWT.equals(type)) { + return AT_JWT; } else { return valueOf(type); } diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/AbstractOAuthDataProvider.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/AbstractOAuthDataProvider.java index 26f7492849..a78f0d9df8 100644 --- a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/AbstractOAuthDataProvider.java +++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/AbstractOAuthDataProvider.java @@ -27,6 +27,7 @@ import java.util.Map; import jakarta.ws.rs.core.MultivaluedMap; import org.apache.cxf.jaxrs.ext.MessageContext; import org.apache.cxf.rs.security.jose.common.JoseConstants; +import org.apache.cxf.rs.security.jose.common.JoseType; import org.apache.cxf.rs.security.jose.jwt.JwtClaims; import org.apache.cxf.rs.security.jose.jwt.JwtConstants; import org.apache.cxf.rs.security.jose.jwt.JwtToken; @@ -669,7 +670,11 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl // It will JWS-sign (default) and/or JWE-encrypt OAuthJoseJwtProducer processor = getJwtAccessTokenProducer() == null ? new OAuthJoseJwtProducer() : getJwtAccessTokenProducer(); - return processor.processJwt(new JwtToken(jwtCliams)); + JwtToken jwt = new JwtToken(jwtCliams); + // RFC 9068 Section 2.1: JWT access tokens MUST set typ to "at+jwt" + jwt.getJwsHeaders().setType(JoseType.AT_JWT); + jwt.getJweHeaders().setType(JoseType.AT_JWT); + return processor.processJwt(jwt); } public Map<String, String> getJwtAccessTokenClaimMap() {
