Hi Filip,
answers are inline:
On 4/11/25 12:18, Filip Skokan wrote:
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.
You are basically describing self-contained/state-less nonces. While we
agree that self-contained nonces are best practice, it's not the core
problem being addressed with nonce fetching. We may however add some
recommendations in the implementation consideration.
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.
We agree that returning nonces on any response is a good idea, that we
already have on the radar
(https://github.com/oauth-wg/draft-ietf-oauth-attestation-based-client-auth/issues/101)
and plan to add for the next draft. Especially for ecosystems defining
their rules/setups, this can be handy.
However, that does not solve the following two problems, that are the
actual motivation for explicit nonce fetching mechanism:
- on a cold start, especially with PAR Request without any prior
communication, there is no previous communication
- in some situations, like Authorization Response through the user
agent/Browser, there is possibility to pass HTTP Headers in the response
Furthermore, it was suggested to request nonces with errors, as being
done by DPoP. This solution is either unreliable or expensive:
- if we send some kind of fake request, it's unreliable because we don't
know which error will be triggered, e.g. runs validation far enough in
AS code to trigger nonce error? this behavior is not standardized and
hence unreliable
- if we send a real request containing no nonce, it's potentially
expensive, if we use hardware key stores or remote key stores
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*
Summarizing, we agree with your proposal but it does not solve the
problem, and hence we believe that explicit nonce requesting is still
necessary. For now, we haven't heard any blockers to the proposed
solution using HTTP OPTIONS and no better solutions were proposed either.
Best regards,
Paul
On Sat, 5 Apr 2025 at 17:16, Christian Bormann
<[email protected]> 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 <http://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 <http://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 <http://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
<http://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 -- [email protected]
To unsubscribe send an email to [email protected]
_______________________________________________
OAuth mailing list [email protected]
To unsubscribe send an email [email protected]
_______________________________________________
OAuth mailing list -- [email protected]
To unsubscribe send an email to [email protected]