Hello Christian,

I've deployed the following optimization for DPoP on the AS in the past
that we may get inspired by. Given the DPoP "nonce" mechanism, much like
what we're talking about in the attestation based client authentication
context here, is to ensure freshness and not be a real "number used only
once" the AS doesn't respond with traditional timestamped values but
instead have a server side TOTP-like mechanism. In this mechanism using a
TOTP-like step interval (and a secret only known to the server) the AS
keeps a list of currently acceptable values that get continuously rolled
following the step interval. At a given time the server accepts values
produced by 5 step counters, 2 steps from the past, current step, and 2
future steps. When a new value needs to be returned (e.g. because the one
used is already not accepted or is about to not be acceptable soon) the AS
returns the current step + 1 value, leaving current step + 2 as a mechanism
for dealing with the different instance server side clock skew. This allows
the AS to always return a header value it knows would be accepted by any of
its instances regardless of whether a client needs one or not with no
computational burden and it allows the client that regularly communicates
with the AS to never not have a fresh value to use in its assertions at
hand. Upon a cold start the client does metadata discovery and it can
already get a valid value there before kicking off e.g. a PAR request where
it can already submit a DPoP Proof for the purpose of Authorization Code
and Public Key Binding.

This means in an ideal scenario that no additional requests need to be made.

Back to a general "freshness" mechanism. What if we designated an HTTP
Response Header parameter applicable to *any* AS HTTP response that carries
a currently accepted value? A client that regularly communicates with the
AS would always have a very likely usable value to use. Cold start clients
that perform discovery could get a value that way. The header value could
even carry a valid until timestamp or an expires_in delta value to let the
client know not to use an expired value. Much like in DPoP-Nonce case a new
header value received means to stop using the old one and use the new. And
to get a fresh value in the scenario where the value client has is expired
(based on the indicated delta or timestamp) the client can do a request to
the authenticated endpoint (e.g. PAR, or token endpoints) without the
expensive to generate credentials expecting an error response in which a
fresh value would be carried by HTTP Response Headers.

That's a long-winded way of saying, TL;DR, let's *consider *the
option of giving the AS the option to return a freshness challenge value in
every HTTP response via a header, have the header be structured to indicate
the value and its expiration, have the client behave right when new values
are received and, specific to Attestation-Based Client Authentication, tell
the client that if it doesn't have a valid challenge value to use - make
the request to the endpoint without credentials (or possibly with just a
client_id. We don't need to specify a new endpoint and end up with a
freshness mechanism that might be usable for future cases. Would AS
implementers tolerate the occasional client authentication error response
if it means no introduction of contentious endpoints?

S pozdravem,
*Filip Skokan*


On Sat, 5 Apr 2025 at 17:16, Christian Bormann <chris.bormann=
40gmx...@dmarc.ietf.org> wrote:

> Hi All,
>
>
>
> We had a discussion about a nonce fetching mechanism for the
> Attestation-Based Client Authentication draft at the
>
> IETF 122 session. Since we didn’t really reach a consensus there, we’d
> like to continue the discussion on the mailing list.
>
>
>
> To summarize the problem briefly: The draft specifies a proof of
> possession that optionally signs over a server-provided
>
> nonce to guarantee freshness of said proof of possession. Since we expect
> this specification to be used in some contexts
>
> where creating a PoP might be expensive (e.g., require a user
> interaction), we were searching for a mechanism where
>
> the nonce is not provided via an error  (as is the case for DPoP - which
> would often require the generation of 2 PoPs),
>
> but in a way that guarantees that we have a fresh nonce before creating a
> PoP.
>
> We were thinking about either
>
>    - a dedicated nonce endpoint (within the scope of an AS or RS)
>    - or a mechanism to explicitly ask for a nonce in a request to an
>    existing OAuth endpoint (e.g., the PAR endpoint).
>
>
>
> After some discussion at OAuth Security Workshop, we proposed to use a
> dedicated header to signal a request for a new
>
> nonce. This could work at any existing OAuth endpoint that wishes to use
> an attestation-based client authentication. Brian
>
> rightfully mentioned that only adding one header field and completely
> changing the behaviour of said endpoint does not
>
> sound like a good idea and proposed to use a different HTTP method. Brian
> initially proposed HEAD and after some more
>
> discussion we ended with an OPTIONS request as the seemingly best idea.
>
>
>
> The idea as currently document in the draft is to use an OPTIONS request
> with a specific header field to request a nonce.
>
> The current proposal would mean that for a request to a PAR endpoint
>
>    1. The client discovers via metadata that the PAR endpoint requires
>    attestation-based client authentication with a nonce
>    2. The client sends an OPTIONS request:
>
> OPTIONS /as/par HTTP/1.1
>
> Host: as.example.com
>
> attestation-nonce-request: true
>
>    3. The client receives a nonce in the response:
>
> HTTP/1.1 200 OK
>
> Host: as.example.com
>
> attestation-nonce: AYjcyMzY3ZDhiNmJkNTZ
>
>    4. The client does the “real” request to the PAR endpoint including
>    the client authentication (via header fields):
>
> POST /as/par HTTP/1.1
>
> Host: as.example.com
>
> Content-Type: application/x-www-form-urlencoded
>
> OAuth-Client-Attestation: eyJ0eXAiOiJvYXV0aC…
>
> OAuth-Client-Attestation-PoP: eyJhbGciOiJFUzI…
>
>
>
> response_type=code&state=af0ifjsldkj&client_id=s6BhdRkqt3
>
> &redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
>
> &code_challenge=K2-ltc83acc4h0c9w6ESC_rEMTJ3bww-uCHaoeK1t8U
>
> &code_challenge_method=S256&scope=account-information
>
>
>
> At the IETF 122 session, Filip voiced concerns that since OPTIONS is used
> for CORS preflight requests, it would mean that at
>
> least for frontend clients, this mechanism would result in several OPTIONS
> requests.  For JavaScript clients, the CORS preflight
>
> requests cannot be used or modified and the client would then manually
> create another OPTIONS request to get the nonce.
>
> From a simple OPTIONS (preflight) and POST requests (normal request to
> PAR), we would get to OPTIONS (preflight),
>
> OPTIONS (nonce fetch), OPTIONS (preflight), POST requests.
>
>
>
> We tried to capture those concerns in this issue:
> https://github.com/oauth-wg/draft-ietf-oauth-attestation-based-client-auth/issues/102
>
> and would like to pick that discussion up again to find some consensus
> what the best option would be to for a nonce request.
>
>
>
> Would people be more comfortable if we instead point to an endpoint that
> can be used to request a nonce (dedicated endpoint
>
> that could for example, be discoverable via metadata), or is it fine to
> cause more requests and we should move ahead with the
>
> current variant based on OPTIONS?
>
>
>
> Best Regards,
>
> Christian, Paul, Tobias
> _______________________________________________
> OAuth mailing list -- oauth@ietf.org
> To unsubscribe send an email to oauth-le...@ietf.org
>
_______________________________________________
OAuth mailing list -- oauth@ietf.org
To unsubscribe send an email to oauth-le...@ietf.org

Reply via email to