Possibility to abort transaction when requirements given by RP cannot be fulfilled

Issue #1210 resolved
Kai Lehmann created an issue

The current standard says that a claim which cannot be provided by the OP should be omitted in the response. Likewise if the RP requires a specific evidence/method and if the OP cannot fulfil this requirement, the response will not contain this information.

If the RP now receives such a partial dataset which it is not able to consume as the requirements were not fulfilled entirely, the RP cannot do anything with the data and needs to throw them away. Still, the RP might get charged for the data transfer by the OP as some data was provided. This makes the financial aspect tedious/complicated.

We should introduce the possibility for an RP to specifically state that if a specific requirement cannot be fulfilled, the whole transaction shall be aborted instead of partially completed.

Comments (39)

  1. Joseph Heenan

    This was discussed discussed on today’s call and I pointed out that essential is defined flexibility in OIDCC:

    By requesting Claims as Essential Claims, the RP indicates to the End-User that releasing these Claims will ensure a smooth authorization for the specific task requested by the End-User. Note that even if the Claims are not available because the End-User did not authorize their release or they are not present, the Authorization Server MUST NOT generate an error when Claims are not returned, whether they are Essential or Voluntary, unless otherwise specified in the description of the specific claim.

    (from https://openid.net/specs/openid-connect-core-1_0.html#IndividualClaimsRequests )

    I believe the eKYC claims could define essential: true to mean return an error if the claim will not be returned - as Connect does for the acr claim. (I am not sure if this is the best approach, at this stage I’m just pointing out that it seems to be a possible approach.)

  2. Kai Lehmann reporter

    Yes, this is also my understanding. Additionally, the verified_claims segment is basically another structure within the claims parameter and although we mostly follow the structure and semantics of the OIDC core spec, we could still decide on redefining some of it. So in the end it’s up to us/the EKYC spec if the essential attribute can force an abort criteria when the associated claim/assertion cannot be fulfilled.

  3. Kai Lehmann reporter

    There is also the question of what error should be returned if a request with essential verified_claims cannot be fulfilled. there is this “consent_required”, but this could only be applied to use cases where the user decided against giving consent. If a claim was marked as essential which the user cannot decide upon (e.g. a specific assurance level which an OP cannot provide) this error would be inappropriate.

  4. Kai Lehmann reporter

    The current OIDC IDA spec has the following:

    6.2.1. Error Handling

    The OP has the discretion to decide whether the requested verification data is to be provided to the RP. An OP MUST NOT return an error in case it cannot return a requested verification data, even if it was marked as essential, regardless of the data being unavailable or the End-User not authorizing its release.

    If we could use “essential” to abort the transaction, this would need to be updated.

  5. Torsten Lodderstedt

    I think having an option to let the OP know that the RP is not interested in a result at all if a certain or some claims cannot be provided is needed.

    The way “essential” is defined and used today instructs the OP to omit claims it cannot provide. That’s reasonable if one wants to provide at least a subset of claims in order to support the RP (partially).

    That changes significantly if the RP is supposed to pay for these claims. The subset might not be sufficient to fulfil the RP’s process and the RP might be required to obtain the remaining data somewhere else. Most likely, the alternative source will provide the whole data set for the full price. So the RP is ending up with higher cost than expected. This causes conflicts.

    I suggest to introduce a new field to mark the claims a RP definitely wants to turn up in an assertion. The semantics should be that the OP shall abort the transaction if any of those claims cannot be provided.

    Name ideas:

    • “critical”
    • “abort_if_not_available”

    We could also refine “essential” for our purposes (and the context of verified_claims). I would like to hear what OP implementers think about this.

    ´

  6. Kai Lehmann reporter

    A separate attribute like “critical” sounds reasonable to me. The abort_if_not_available is just too long for my taste 🙂

    Another approach would be using essential:true to mark the claims the RP definitely requires as usual and introducing a new property in the request to make essentials claims critical like so:

    {
      "verified_claims": {
        "essentials_are_critical": true,
        "claims": {
          "given_name": { "essential": true },
          "msidn": { "essential": true }
        }
      }
    }
    

  7. Kai Lehmann reporter

    I do understand the reasoning behind not aborting the transaction even when essential claims cannot be provided. In that case, the RP at least gets a subject identifier and can identify the end-user in its database.

    There is an alternative to aborting the whole transaction; omitting the whole “verified_claims” part in the response/userinfo or have it with a specific content which tells the RP that the dataset could not be returned due to critical claims not being available. This would allow the RP to at least identify the customer based on the sub or other unverfied claims requested alongside. This would also work for the premium usecase where a RP must pay for verified data, but can still have unverified data free of charge:

    {
      "sub": "291a6fc2-dd7c-4854-8e98-0f2a69c67bd3",
      "email": "max@musermann.name",
      "verified_claims": false
    }
    

  8. Torsten Lodderstedt

    I like the idea but would not like to limit it to verified claims. We could also use “critical” or any suitable named field to tell the OP: “provide all of the claims marked this way or none”.

  9. Joseph Heenan

    In the case of the at_least_age claim (or it’s evolution) there’s several cases:

    1. Age is not known
    2. Age is held, but is not “verified”/evidence not held.
    3. User refuses release of age
    4. User’s age does not meet criteria
    5. Age is held, verified, user does meet criteria & authorises release

    Is the intention of ‘critical: true’ (when combined with ‘verified_claims’) that it would abort the transaction in all cases except ‘5'?

    I think I’d agree with Kai that at least one of the above cases should probably have a new error code defined that the OP can return.

  10. Torsten Lodderstedt

    very subtle 🙂

    I guess you are right, although I personally would not like that reaction in case ‘4'. I think omitting the claims marked as ‘critical’ instead of aborting the transaction is even more appealing in this case.

  11. Kai Lehmann reporter

    @Torsten Lodderstedt I’m not sure if we should apply a critical property to the claimset outside of the verified_claims section. Wouldn’t we break the OIDCC specification with that when the transaction is aborted if a core claim cannot be provided?

  12. Kai Lehmann reporter

    Re @Joseph Heenan cases: I think we agree that 1 and 2 will be an abort criteria as we would like to have it. Case 5 in a success.

    Case 3 could result in an abort or we could define that an OP should not allow an enduser to independently give consent to critical claims. there shouldn’t be checkboxes on the consent page for critical claims. However, the user will still be able to abort the transaction themselves with a “do not consent” option which could result in another error code “consent_required”.

    For case 4 there are two aspects: If the user does not meet a minimum age requirement, the RP will most likeley not be able to fulfil its service and might not even be legally allowed to receive/process any personal information of the end user. An abort in this case would be the best choice. On the other hand, the identity provider did in fact fulfil its part of the contract, i.e., the age verification service. So the identity provider would still want to charge the RP for the verification service even if the verification turns out to be negative. This is the same case with assertions for other claims where the RP provides the values the enduser might have entered and the identity provider verifies that this information was correct or not (see #1218):

    Request:

    { "verified_claims": { "claims": { "given_name": { "value": "Max", "critical": true } } } }
    

    The verification service would have been fulfilled (and should be paid for), but the result of that process is negative and the data will not be returned. If we want to consider the monetary aspect here, we will probably need a different error code or a response with null/false values.

  13. Torsten Lodderstedt

    @Torsten Lodderstedt

    I’m not sure if we should apply a critical property to the claimset outside of the verified_claims section. Wouldn’t we break the OIDCC specification with that when the transaction is aborted if a core claim cannot be provided?

    I don’t think we break core if we define a new field. So in my opinion, “critical” or “required” would be fine, if we go with “essential” we should limit it to verified_claims.

  14. Achim Schlosser

    For me it would be fine to refine essential in this context, but that is given we interpret essential very similar today already (i.e. required for the fulfilment of a service) compared to voluntary. Other than that required seems more tangible than critical

  15. Takahiko Kawasaki

    I prefer "required" to reuse of "essential".

    Frankly speaking, from a viewpoint of authorization server implementation, "essential":true is meaningless in most cases. Reusing "essential" would confuse those who are familiar with OIDC specs.

  16. Sebastian Ebling

    +1 for “required”.

    I believe, the reuse of "essential" with partially different semantics is prone to errors.

  17. Vladimir Dzhuvinov

    I would like to suggest to keep the parameter story simple and clear for developers when they read the spec or encounter the parameter in some example request or whatever.

    The existing OIDC facility for letting an RP indicate whether a claim is essential or not for the RP’s needs and those of the end-user is good and people have come to understand it.

    Though, if Nat was in this thread, he would point out (and rightly so) that RPs shouldn’t be asking for claims that aren’t essential, in the spirit of data minimisation and privacy :)

    So, using essential:true to signal “this claim is required”, I’d suggest to not overload that, or introduce a new parameter name which is a synonym of essential, but it has a side-effect and this side-effect is what we are actually after. This can confuse developers and implementers.

    My understanding of Kai’s original need is to simply have a way for an RP to say “If you cannot fulfil this claim, abort the entire request”.

    If we follow from this, abort_if_not_available isn’t such a bad idea. The parameter name clearly says what the intent of the parameter is. Yes, it’s longish, so let’s shorten it to abort_if_unavailable. Or abort_if_withheld (-3 chars). Then we can limit the spec of the param to simply describing the expected behaviour from the OP when this parameter is received (return error code if it cannot be provided). If we go for “required” or “critical” the language will not be easy. The spec will be drawn into having an explanation what “required” actually means and how it differs from OIDC “essential”, because it’s encroaching into “essential” territory. This will also raise the question of whether “required” and “essential” can be used together or how to deal with such situations. abort_if_unavailable doesn’t have this issue and can potentially be used together with essential, without causing any semantic conflict.

    Error code: I’d suggest claim_unavailable .

  18. Torsten Lodderstedt

    @Vladimir Dzhuvinov Would you see any value in omitting the claims instead of aborting the transaction?

  19. Torsten Lodderstedt

    I would like to sum up the current discussion. I perceive we lean towards defining a new field fr that purpose. I think “required” is reasonable.

    There is one open question: what happens if the OP cannot provide all claims marked as “required”?

    1. Abort the transaction
    2. Omit claims marked as “required”

    What do you think?

  20. Achim Schlosser

    Hi,

    my vote is for abort transaction. If a claim is requested with this new strict semantic beyond essential, required means that the RP cannot continue with the business process in which the call is integrated thus it should be aborted.

    Best

    Achim

  21. Vladimir Dzhuvinov

    If not receiving the claim is a deal breaker for the RP, why continue the transaction?

    From a privacy standpoint going on will be a bad thing, as the OP can end up releasing other bits of non-critical information useless to the RP, which the RP will then have to discard.

    Continuing the transaction can also open up a path for malicious data collecting RPs to still obtain some claims and verification metadata from non-savvy users. A cautious OP can mitigate this risk in the case of not receiving consent for a critical claim by withholding all other claims, but why rely on such discernment.

    In case we end up agreeing on the transaction abort, my request is to consider the parameter naming anew. I’m all for self-evident parameter names that leave no questions to their effect. Besides, the verb “abort” sounds so much juicier than an adjective :)

  22. Kai Lehmann reporter

    I’m also in favor of aborting the transaction, even if that means that the RP may not be able to at least receive the sub to identify the customer for a SSO.

    I’m also in favor of having a new attribute per claim to mark it as important.

    I’m not sure about naming the attribut “required” though. The term “required” is used throughout the spec already with a different meaning. For instance: “the RP should only request the claims it requires”. That’s why I am leaning towards “critical”.

  23. Daniel Fett

    I suggest to

    • differentiate between things that "can go wrong" with a claim (the data is not available vs. it does not fulfill the value/values/max_age requirements),
    • differentiate between the behavior that can be triggered (abort the transaction vs. omit the claim vs. ...),
    • and to use clearer terms to allow deriving the semantics from reading the request.

    Therefore, I propose to use the following syntax:

     {
       "given_name": {
          "value": "Max",
          "if_unavailable": "abort",
          "if_no_match": "omit"
       },
       "family_name": {
          "if_unavailable": "abort"
       },
       ...
    }
    

    Instead of required, we would use one of two "case keys":

    • if_no_match: Behavior if the data does not match the value/values/max_age requirements
    • if_unavailable: Behavior if the data is not available

    Initially, I propose two possible "behavior values":

    • omit: Default. Omit this particular claim.
    • abort: Abort the transaction.

    If we have a concrete application, we could later on add other behaviors, like omitting a group of claims or similar. Likewise, we could add other case keys later.

    More details, to be discussed:

    • if_unavailable can only be used together with value/value/max_age
    • If data is unavailable, if_unavailable takes precedence over if_no_match.
    • Essential remains orthogonal to all of this.

    What do you think?

  24. Vladimir Dzhuvinov

    Hi Kai,

    I’m also in favor of aborting the transaction, even if that means that the RP may not be able to at least receive the sub to identify the customer for a SSO.

    Do you have a need in your application to rely on the same IdP for both SSO and eKYC?

  25. Vladimir Dzhuvinov

    Hi Daniel,

    I like the path you propose.

    “Essential” remains as it is, a UI hint to the IdP. While defining a more refined concept solely about the action the IdP should take on the requested claim.

    Instead of required, we would use one of two "case keys":

    if_no_match: Behavior if the data does not match the value/values/max_age requirements
    if_unavailable: Behavior if the data is not available

    +1

    Initially, I propose two possible "behavior values":

    omit: Default. Omit this particular claim.
    abort: Abort the transaction.

    +1 (brilliant ! 🙂 )

    More details, to be discussed:

    if_unavailable can only be used together with value/value/max_age

    Do you mean “if_no_match”?

    If data is unavailable, if_unavailable takes precedence over if_no_match.

    Makes sense to give “if_unavailable” precedence, because it’s the more general case. “if_no_match” is a subset of “available”.

    Essential remains orthogonal to all of this.

    +1

  26. Daniel Fett

    Of course, that was meant to say “if_no_match can only be used together with value/values/max_age”.

  27. Sascha Preibisch

    The ticket was created with this thought in mind:

    … Still, the RP might get charged for the data transfer by the OP as some data was provided …

    Looking at that, I wonder if a provider would not charge for processing a request anyways, even if data (or some data) could not be provided? With that in mind I wonder if we need the distinction between ‘if_no_match’ and ‘if_unavailable’ with ‘omit’ and ‘abort’?

    If I would be a provider I would process a request and fail as soon as I cannot find or deliver a required claim. It was marked as required for a reason I’d think.

    Overall, I am questioning if the added complexity of those two attributes is necessary.

    For the moment I would be happy with a ‘required’ attribute per claim.

  28. Alberto Pulido Moyano

    Hi all,

    In my opinion and thinking more from an End-User point of view, having a required data point by the RP does not help to protect my private information, and seems difficult to understand the real need for sharing that data otherwise I would not be able to complete whatever process I was trying to do. Specially considering that all that normally happens in the consent screen and before going back to the RP, I think it could provoke a reaction from user to almost feel like is somehow forced to release private information.

    I think that RPs should be prepared to received all, none or partial data points/claims requested, as per End-User choice, and the current core specification with the 'essential' field already covers that, and is widely accepted as a valid user experience.

  29. Kai Lehmann reporter

    @Alberto Pulido Moyano This is true for claims which are not necessarily verified as the RP can simply ask the user for this information if not provided by the OP. If the RP needs verified claims though, they cannot do this and are left with nothing they can work with.

  30. Alberto Pulido Moyano

    Hi @Kai Lehmann , I understand the problem however, it looks more a RP issue and nothing that should impact users so drastically when interacting with OP.

    How do you clearly explain the user the consequences of aborting the authorisation? I think that should be a responsibility of the RP and not the OP.

  31. Kai Lehmann reporter

    That’s why the RP should be able to decide wether the transaction should be aborted if the request cannot be fulfilled by the OP.

  32. Torsten Lodderstedt

    @Sascha Preibisch

    I don’t know other IDP's price models, we charge per claim not per transaction.

  33. Log in to comment