Connect2id server 19.4
This Connect2id server release ships full DPoP support for applications using the token exchange grant. It also enables grant handler plugins to find out whether the issued access token is going to be mTLS or DPoP-bound, to inform authorisation decisions. Two old issues in the integration APIs receive a fix.
Exchange of DPoP access tokens
In January 2020 the OAuth working group published the final spec of the token exchange grant RFC 8693, for applications that need to exchange tokens, of any purpose and kind, for an access token, potentially accompanied by a refresh token and an ID token.
A common use case has been the exchange of one access token for another. For
instance, to enable web APIs to obtain secondary, or downstream, access tokens
for backend services. For access tokens of the
bearer and the
mTLS-bound type the
token exchange is fully specified. However, for
DPoP tokens, a crucial
bit is not found in the spec - how to pass the required DPoP proof when the
subject_token or the actor_token is DPoP. This gray area is due to
the token exchange RFC 8693
predating DPoP RFC 9949 by a few
years.
Connect2id made steps to address this situation in the OAuth WG on several
occasions, and earlier this month an informal agreement was reached: to use the
DPoP HTTP request header for the submitted as well as the newly issued access
tokens. In order for this to work, the ath (access token hash) JWT claim,
normally reserved for DPoP proofs for resource server access, is to be included
in the DPoP proof that the client mints for the token
endpoint.
Example token exchange request with a DPoP subject_token:
POST /token HTTP/1.1
Host: c2id.com
Content-Type: application/x-www-form-urlencoded
DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6IkVDIiwiY3J2I
joiUC0yNTYiLCJ4IjoiNER4cHlGTTcxTVVTSzUyVnlGZVNMYUJoWTIzOUxSTkM5MTFPb1JGX3pEOCI
sInkiOiI3MTBSOHpZUjlxakY2UHFGamVfaVN5eFBjdkNmdlFkNmM0QlNIclRidW5zIn19.eyJodG0i
OiJQT1NUIiwiaHR1IjoiaHR0cHM6Ly9jMmlkLmNvbS90b2tlbiIsImF0aCI6InlhajNHRzJUZ1hlRG
tGLTE0MW9iNlA1SkNNTmdKV3ZqLUliWFp0eEZ5RzQiLCJpYXQiOjE3NjE3MzAwMTksImp0aSI6ImM4
VGVtUG5Qc1FLVmU1azBpR25WUkF5NmdzQ1FsN3V2THdnbGRMQ1NaUjgifQ.MBEDQTTgPQC5Dgo_CTl
bceQRv9-YBE7RF59vGzIfOGhuQtHNt5ImxDgkHlG74eQYNHTIXNSvtfZ46DVHrMVkiw
grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Atoken-exchange
&client_id=123
&subject_token=l_Lre_1cHe29DBDymbMxIQ.Wuy0HNMwgxgBaRZQcRCGIg
&subject_token_type=urn%3Aietf%3Aparams%3Aoauth%3Atoken-type%3Aaccess_token
&scope=
Note how the DPoP proof JWT includes a hash (ath) of the submitted access
token, as if a protected resource is being accessed. The Connect2id server will
use the ath to verify the binding of the proof to the subject_token:
{
"htm" : "POST",
"htu" : "https://c2id.com/token",
"ath" : "yaj3GG2TgXeDkF-141ob6P5JCMNgJWvj-IbXZtxFyG4",
"iat" : 1761730019,
"jti" : "c8TemPnPsQKVe5k0iGnVRAy6gsCQl7uvLwgldLCSZR8"
}
The public JWK in DPoP proof JWT header will be used to check the client key
binding to the subject_token and then to bind the newly issued DPoP access
token:
{
"typ" : "dpop+jwt",
"alg" : "ES256",
"jwk" : { "kty" : "EC",
"crv" : "P-256",
"x" : "4DxpyFM71MUSK52VyFeSLaBhY239LRNC911OoRF_zD8",
"y" : "710R8zYR9qjF6PqFje_iSyxPcvCfvQd6c4BSHrTbuns"
}
}
The use of DPoP access tokens and proofs is explained in the docs for token exchange grant handler and the token endpoint.
Finding out the token binding method in a grant handler plugin
The available grant handler SPIs were updated to enable plugins to find out whether the issued access token is going to be sender-constrained via mTLS or DPoP:
This can be used to inform authorisation decisions, for example what lifetime to assign to the issued refresh token.
A plugin can obtain the applicable binding by calling the
GrantHandlerContext.getTokenBindingMethods
which returns a Set<TokenBindingMethod>:
- If the set is empty the access token is simple bearer access token.
- Otherwise the set contains an enum of
TokenBindingMethod.MTLSTokenBindingMethod.DPOP
When an access token is sender-constrained, this is normally done by a single binding method.
Fixed issues
This release fixes two issues in the authorisation session
API and the direct
authorisation API.
In cases when the client is not registered in the grant_types metadata to use
refresh tokens, the API must internally take this into account, instead of
issuing a refresh token that is then rejected as unusable at the token
endpoint.
More information about this release can be found below.
Download 19.4
For the signature validation: Public GPG key
Standard Connect2id server edition
Apache Tomcat package with Connect2id server 19.4: Connect2id-server.zip
GPG signature: Connect2id-server.zip.asc
SHA-256: ab7d419e88ff95b679acf734e851d9878e395ea1f322781931c0f4fdb05286d0
Connect2id server 19.4 WAR package: c2id.war
GPG signature: c2id.war.asc
SHA-256: 730a1a8358339be26e5af240ece9760761d1ba77bd140a0c480cda28c95027aa
Multi-tenant edition
Apache Tomcat package with Connect2id server 19.4: Connect2id-server-mt.zip
GPG signature: Connect2id-server-mt.zip.asc
SHA-256: a0cf40f39d0c0330da25e6d0abb65840d233da1f70a5526a1dfb33faa2b9ce96
Connect2id server 19.4 WAR package: c2id-mt.war
GPG signature: c2id-mt.war.asc
SHA-256: 7a9d2cbcd47a800bb6274f552410c62d450dd94e789ef53eb1b422c6a3204e37
Questions?
For technical questions about this new release contact Connect2id support. To purchase a production license for the Connect2id server, renew or upgrade your support and updates subscription, email our sales.
Release notes
19.4 (2025-10-28)
-
OAuth 2.0 token exchange (RFC 8693) use cases in which clients exchange DPoP (RFC 9449) access tokens for other access tokens are now fully supported by
the Connect2id server. Previously, when the Connect2id server received a DPoP access token in thesubject_tokentoken request parameter, it was only able to perform introspection of the token, due to the lack of specification text how to pass a DPoP proof for thesubject_tokenand theactor_tokenin a token exchange grant.For an OAuth authorisation server to validate a DPoP access token it must also receive a DPoP proof that includes the
ath(access token hash) JWT claim. This kind of DPoP proof was originally specified for protected resource access, not for the token endpoint.This Connect2id server release is updated to accept DPoP proofs with the
athclaim at the token endpoint for token exchange grants. The DPoP proof is used to validate the binding of a DPoP access token submitted in thesubject_tokentoken request parameter. The same DPoP proof is then used to bind the issued access token (as well as refresh token, for a public client). This “dual” use of the DPoP proof header in token exchange grants was informally agreed upon in the OAuth working group in October 2025. -
Grant handler plugins are now able to find out if the issued access token is going to be bound via mutual TLS (RFC 8705) or DPoP (RFC 9449).
Web API
-
/token
- When processing OAuth 2.0 token exchange grants (RFC 8705) the Connect2id
server is now able to verify the binding of DPoP access tokens (RFC 9449)
submitted in the
subject_tokentoken request parameter. To verify the binding the Connect2id server must receive a token request with aDPoPproof header that is normally constructed for resource servers - theath(access token hash) JWT claim must be included in the DPoP proof. If the Connect2id server detects asubject_tokenthat is a locally issued DPoP access token and the DPoP proof header is missing or doesn’t match the token introspection or the token hash, it marks the access token as invalid.
- When processing OAuth 2.0 token exchange grants (RFC 8705) the Connect2id
server is now able to verify the binding of DPoP access tokens (RFC 9449)
submitted in the
SPI
-
Upgrades the Connect2id server SDK to com.nimbusds:c2id-server-sdk:5.14
- The
GrantHandlerContextreceives a newgetTokenBindingMethodsmethod that returns the binding method for the token(s) to be issued for the handled OAuth 2.0 grant, such as client credentials or token exchange. The Connect2id server supports the methods MTLS for client X.509 certificate bound tokens (RFC 8705) and DPoP for JWK bound tokens (RFC 9449). Intended to inform authorisation decisions in grant handler plugins.
- The
Resolved issues
-
The Connect2id server must ignore the
refresh_token.issueconsent parameter in the authorisation code flow when the registered clientgrant_typesdoes not includerefresh_token. Similarly, the server must ignore therti(refresh token issue) authorisation record parameter when using stored end-user consent in the authorisation code flow and the registered clientgrant_typesdoes not includerefresh_token. Note that a refresh token issued in these circumstances is unusable at the token endpoint, which always performs a check for the presence ofrefresh_tokenin the registered clientgrant_types(issue server / 1125). -
The Connect2id server must ignore the
refresh_token.issueparameter in requests to the direct authorisation web API (/direct-authz/rest/v2) when the registered clientgrant_typesdoes not includerefresh_token. Note that a refresh token issued in this circumstance is unusable at the token endpoint, which always performs a check for the presence ofrefresh_tokenin the registered clientgrant_types(issue server / 1126).
Dependency changes
-
Upgrades to com.nimbusds:c2id-server-sdk:5.14
-
Updates to com.nimbusds:oauth2-oidc-sdk:11.30