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]

Reply via email to