Hi Niel

>While I can see the motivation, IMO the HTTP-specificity of DPoP is an
advantage from a security point of view. Otherwise, like this draft, you
end up with lots of crucial checks being conditional.
Are you suggesting separating drafts by protocols or suggesting that other
protocols should not be supported?

>The problem I think you have is that the EPOP proof is wrapping the token
..
>EPOP seems to have the further issue that the proof itself contains ..

The trust establishment pattern you describe as "suspending disbelief" is
the same two-phase model used in certificate-based authentication and
codified in RFC 9883: a self-asserted public key is presented, the relying
party verifies the signature with it (establishing key possession), and
authorization of that key is then confirmed via a separate chain check.
Nobody considers TLS client certificate authentication problematic on these
grounds. EPOP follows the same principle: steps 1–3 establish that the
sender holds the private key; step 8 (cnf.jkt cross-check) establishes that
the AS authorized that key for the nested credential. These answer
different questions and must run in sequence.

On parsing an "untrusted" token: after steps 1–3 pass, the outer token is
not unexamined — its signature has been verified. This proves key
possession. An attacker who wraps a stolen access token in their own EPOP
envelope will pass steps 1–3 but fail step 8, because the cnf.jkt inside
the AS-issued nested token does not match their self-generated JWK
thumbprint. The AS bound that value at issuance; it is not under attacker
control in the resource access flow.

On the cnf.jkt concern: I think there may be a conflation of two distinct
flows. In authorization code exchange, cnf.jkt is client-declared (same as
client_assertion in RFC 7521), and PKCE provides the complementary binding.
In resource access, cnf.jkt is embedded in the AS-issued access token and
is not under attacker control — this is the primary token substitution
defense. In rotation flow, new cnf.jkt is attested by the previously known
EPOP key, which is attested by the underlying refresh token.

On conditionality: DPoP has the same structural characteristic — nonce is
optional, ath is conditional on token type. EPOP's validation algorithm in
§5 is a strict sequential procedure with explicit normative requirements at
each step. I am open to discussion on whether specific conditions in the
draft need tighter language.

Regards
Ashwin

On Wed, May 20, 2026 at 1:04 PM Neil Madden <[email protected]> wrote:

>
>
> > On 20 May 2026, at 19:52, Ashwin Ambekar <[email protected]> wrote:
> >
> > 
> > Hi Gabriel,
> >
> > There is a broader point that I think gets missed in the ~ vs nesting
> discussion: neither SD-JWT nor DPoP address sender-constraining for opaque
> access tokens across non-HTTP transports. SD-JWT requires JWT structure —
> it has nothing to work with for opaque tokens. DPoP handles opaque tokens
> on HTTP via ath, but the htm/htu claims make it HTTP-only. A client holding
> an opaque AT on Kafka, MQTT, or SASL has no sender-constraining path under
> either mechanism.
>
> While I can see the motivation, IMO the HTTP-specificity of DPoP is an
> advantage from a security point of view. Otherwise, like this draft, you
> end up with lots of crucial checks being conditional.
>
> >
> > EPOP's ntk treats JWT and opaque tokens identically: the credential goes
> in ntk, the outer envelope provides the proof, and validation follows the
> same path regardless of token format or transport. This uniform treatment
> of opaque tokens across all transports is a primary design goal, not an
> incidental feature.
> > There is a convergence path where SD tokens can be the ntk claim inside
> the EPOP token, which I'll be willing to explore as a follow-on draft if
> you are interested.
>
> The problem I think you have is that the EPOP proof is wrapping the token,
> but the token needs to be validated in order to establish trust in the
> proof key. Sure, you can do that, but it means you have to suspend
> disbelief for a while - validating the EPOP proof based on a self-asserted
> JWK and only much later do you get around to checking if that key is
> trusted. That seems a problematic design to me. (I had a similar concern
> with DPoP, but this seems a step even further down that road). I shouldn’t
> be having to parse an untrusted token to find another token that’ll
> eventually let me tie off the trust knot. That way lies doom.
>
> EPOP seems to have the further issue that the proof itself contains a
> self-asserting cnf/jkt claim that sometimes seems to have to match the jwk
> header (both under attacker control, so pointless), but at other times
> might be a nested token where it matches the outer proof key.
>
> I think there’s just far too much complexity and conditionality in this as
> specified to make a robust security mechanism.
>
> — Neil





Regards
Ashwin Ambekar
_______________________________________________
OAuth mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to