Remove c_nonce from the token response

Issue #1956 resolved
Brian Campbell created an issue

The option to return c_nonce with token response should be dropped to simplify the spec and implementations. It’s a lot of complexity and optionality for the potential avoidance of just one HTTP request/response direct from wallet/client to credential issuer.

Comments (9)

  1. Joseph Heenan

    I was tempted to make a comment onto https://bitbucket.org/openid/connect/pull-requests/535/adding-security-considerations-on-the but this issue is probably a more appropriate place.

    It’s interesting to note that, if we made the assumption that dpop is in use, and that the (optional) dpop nonces are being used, then an optimal solution would be removing c_nonce from the token response and instead use the dpop nonce as the nonce for the VCI key proof. Doing that is probably also kind of a layering violation though.

    On the original point though, Torsten mentioned on today’s call that returning c_nonce from the token response is a nice optimisation that avoids a round trip at the resource server. I wanted to observe that when you’re using nonces with DPoP the first nonce for the resource server has to be obtained from the resource server, similarly causing an extra round trip, and I don’t remember anyone complaining much about the additional round trip for that. (I’m sure Brian will correct me if they have.)

  2. Takahiko Kawasaki

    The current spec provides implementers with two choices.

    c_nonce from token endpoint round trip at credential endpoint server implementation wallet implementation
    1 issue unnecessary 😟 cumbersome 😀 unburdensome
    2 not issue necessary 😀 unburdensome 😟 cumbersome

    Removing the option to return c_nonce from the token endpoint will result in removing the first choice in the table above.

    Even if we can agree not to issue c_nonce from the token endpoint among us at this moment, there will always be people in the future who will complain about the extra round trip. Therefore, it would be wise to provide two choices without modifying the current specification.

  3. Brian Campbell reporter

    The wallet implementation needs to be able to handle an invalid_proof (or invalid_or_missing_proof b/c the draft currently has both) error/challenge in any case so calling it cumbersome there is a misnomer. When a c_nonce from the token endpoint is an option, the wallet needs to deal with possibly getting the nonce value from two places. It's not making the wallet implementation less cumbersome. It's only optimizing around one http request / response.

  4. Pedro Felix
    • I agree that we are not simplifying the wallet by having the c_nonce on the token endpoint, namely because: 1) it is optional; 2) it may already be invalid when the wallet uses it, so the wallet needs to still correctly react to an error response and use the freshly provided c_nonce on a retry.
    • OTOH, the c_nonce on the token endpoint is currently optional, so some AS may decide to not implement that support on the token endpoint, keeping its implementation simpler; while leaving the door open for other AS to implement it.
    • So IMO, the question is: is the additional spec complexity (not necessarily AS complexity) worthwhile just to enable an optimization that some AS may decide to implement?

  5. Kristina Yasuda

    (or invalid_or_missing_proof b/c the draft currently has both

    that’s editorial error. I will do a PR removing references to invalid_or_missing_proof

  6. Kristina Yasuda

    Having read the arguments, I am increasingly in favor of removing the c_nonce from the token endpoint

  7. Torsten Lodderstedt

    I would like to hear more feedback from implementers (both wallets and issuers) before we decide.

  8. Takahiko Kawasaki

    I tried writing a virtual wallet-side code for “c_nonce” handling. (Its error handling is not perfect, though.)

    // Make a token request and receive a token response.
    token_response = make_token_request();
    
    // The access token issued from the token endpoint.
    access_token = token_response.access_token;
    
    // The token response MAY contain "c_nonce".
    c_nonce = token_response.c_nonce;
    
    // Repeat credential requests until a credential or a transaction ID is issued.
    while (true)
    {
        // Make a credential request and receive a credential response.
        // It is assumed that the "make_credential_request" method here
        // internally generates a key proof with the given "c_nonce" and
        // includes the key proof in the credential request.
        credential_response = make_credential_request(access_token, c_nonce);
    
        // If either a credential or a transaction ID has been issued.
        if (credential_response.credential     != null ||
            credential_response.transaction_id != null)
        {
            // Stop repeating credential requests.
            break;
        }
    
        // If the reason of the error is "invalid_proof" and the value
        // of "c_nonce" in the credential response is different from
        // the one used in the credential request, it is worth trying
        // to make a credential request again with the new "c_nonce".
        if (credential_response.error   == invalid_proof &&
            credential_response.c_nonce != c_nonce)
        {
            // Make a credential request again with the new "c_nonce".
            c_nonce = credential_response.c_nonce;
            continue;
        }
    
        // Give up.
        break;
    }
    

    The virtual code above indicates that whether the token response contains the c_nonce parameter or not is not a significant issue for wallet implementers. (Some people may not agree with this view, though.)

    My conclusion is that it is acceptable to allow authorization server implementations to issue c_nonce from their token endpoints if they wish to do so. However, others may reach different conclusions and prefer wallets to make credential requests at least twice (the first one to obtain c_nonce and the second one to get a credential or a transaction ID).

    A credential issuer validates an access token that has been issued by an authorization server. Therefore, there exists a relationship between a credential issuer and an authorization server to some degree. If such a relationship is assumed for acess tokens, it should not be a major concern to allow a similar relationship to be established between a credential issuer and an authorization server for c_nonces as well. If you implement an authorization server and a credential issuer, you will notice that a c_nonce always appears with an access token. However, others may have different thoughts and want to prevent a credential issuer and an authorization server from establishing a relationship for c_nonces.

  9. Log in to comment