SIOP response with vp_token only?

Issue #1470 resolved
Torsten Lodderstedt created an issue

A question that comes up frequently in conversions about SIOP and OIDC4VPs is: “Why do I need sub value and id token if all I want is a VP?“. I think there are use cases where a VP alone is sufficient, e.g. a verifier wants to check a diploma or a certain authorisation represented by a verifiable credential. In those cases, there is no need to establish a sub value for the user.

From a protocol perspective, we could modify SIOP +OIDC4VPs so it would allow a RP to request a sub/id token or a vp token or a combination of id and vp token.

What does the WG think?

Comments (29)

  1. Torsten Lodderstedt reporter

    I think the RP should indicate that in the request. We could use a new scope value (since “openid” requires an id_token to be issued).

    There might be a relationship to the way SIOP is requested (#1431).

  2. David W Chadwick

    I think this is a valid use case. The user may not have an account at the RP, and may not wish to login or authenticate, but simply present a set of VCs in a VP according to the RPs requirements (which are set in the PD)

  3. David Waite Account Deactivated

    This seems appropriate to distinguish with response_type=vp_token, vs openid scope omission.

    Where would the presentation submission go in the absence of an id_token?

  4. Kristina Yasuda
    • changed status to open

    Discussed in 2022-Mar-31 SIOP call

    Many WG members remarked that "not sending the openid scope might make it harder for existing providers to add support for the new features". Suggestions were made to use response_type, or response_mode. This would be especially relevant if we will expand definition of SIOP and allow self-issued ID Tokens to be sent using code flow.

    Implementor who started implementing SIOPv2/OIDC4VP with an existing VC/DID infrastructure shared that they got VP Token part straightforward, but still struggle with ID Token implementation.

    We agreed to explore mechanisms to turn off a feature to return ID Tokens, also taking into account existing OIDC implementations, who might support self-signed ID Token features.

  5. Kristina Yasuda

    @David Waite

    Where would the presentation submission go in the absence of an id_token?

    In the VP, that is already an option in section 5.2 of OIDC4VP specification.

  6. Michael Jones

    I agree with keeping the openid scope. How the RP can signal to the OP that it wants this behavior is a key question.

    Another key question is what the RP should and should not do with the VP in the absence of an accompanying ID Token. The ID Token would have given the RP a stable identifier for the user. The VP may not, but developers may be tempted to treat it that way. What practical and security guidance should we give developers in this regard?

  7. David W Chadwick

    How can the RP signal to the OP that it wants this behaviour? By adding an additional flag/protocol element that has the semantics of id_token is not required. It could be a new scope or something else.

    What should the RP do/not do with the VP? This depends upon the nature of the process that the RP has started with the user. If it was to get information from the user, with no intention of creating a user account, e.g. to fill in a form from the contents of the user’s attributes in the returned VP/VCs, then the RP can continue the form processing without logging in the user and simply say Thankyou to the user. If it was to identify the user with the intention of creating a user account, by matching the user’s certified attributes in the VCs, with those attributes already stored in its database, for example, it has the passport details already stored for thousands of users, then it can continue the session with the user by using the public key in the VCs which the user has proved possession of by signing the VP. It does not need a key in the id_token if this is the same public key as in the VP and VCs.

  8. Ronald Koenig

    I prefer the new response_type vp_token with the following semantic:

    response_type = vp_token

    The RP requests verifiable credentials only. The authentication response contains a vp_token. The token contains a list of verifiable presentations with credentials which contains claims about different subjects asserted by different issuers. There is no id_token. Consequently, there is no unique OpenID user identifier (issuer:sub) and the claims are not related to the OpenID user.

    response_type = id_token

    The RP explicitly requests claims about the OpenId user. The provided id_token contains self asserted claims as well VC’s with claims about the OpenID user. Therefore the parameter sub and the ids of the credentialSubjects need to be the same, e.g. a DID (EdDSA / Ed25519). The id_token is signed with the private key belonging to this DID in order to provide a cryptographic proof that the claims are about the OpenID user. This type of token allows a RP to register new accounts and initialize them with the claims from the VC’s and subsequently allow login with the unique OpenID user identifier (issuer:sub) only. The id_token is a valid jwt_vp.

    response_type = id_token vp_token

    This is the current semantic. The authentication response contains claims about different subjects including the OpenID user from different issuers. The claims about the OpenID user are contained in the id_token. The claims about other subjects are contained in the vp_token. The presentations are signed by the user (holder) so he can proof that the claims are about him.

    So far, we have prototyped response_type = id_token in an existing VC/DID infrastructure.

  9. Kristina Yasuda

    There is no option in the current OIDC4VP spec to return VCs embedded inside an ID Token. If we allow an option to return only VP, there is no difference between what you describe as `response_type = id_token` option and `response_type = vp_token`.

    You seem to be making a distinction whether the claims are about “OpenID user“ or not - what does that mean? whether the user is returning user to that RP or not? If we are to allow an option to return only VP, without an ID Token, I think we should be giving a clear guidelines what should be used as user identifier for re-authentication - iss in VP most likely, though this will depend on Credential format since in some formats user identifier is blinded.

    In short, in my mind,

    • response_type = vp_token: only VP returned
    • response_type = id_token OR response_type = code: only ID Token returned, no VC embedded
    • response_type = id_token vp_token: ID Token and VP returned

  10. Kristina Yasuda

    by matching the user’s certified attributes in the VCs, with those attributes already stored in its database, for example, it has the passport details already stored for thousands of users,

    as has been repeatedly said on the calls identifying the user based on the claims is a security anti-pattern and should not be done. If we are allowing sending only VP, the spec should say that in those cases NO user authentication is happening, which would make it a stateless protocol which is a big leap… However, regardless of what the spec will say, I can imagine implementations still using claims to identify the user, which makes me a little reluctant to accept this option, even if I understand the use-case.

    then it can continue the session with the user by using the public key in the VCs which the user has proved possession of by signing the VP

    as I have been repeatedly highlighting, user’s public key in the VC is user’s identifier with the Issuer, I do see issues - potentially correlation - with Verifier just taking it and using as a user identifier at the Verifier.

  11. Torsten Lodderstedt reporter

    I can imagine implementations still using claims to identify the user, which makes me a little reluctant to accept this option, even if I understand the use-case.

    Not supporting this option won’t RPs to use the sub in the id token to authenticate users.

    I would like to understand why using a claim from a VP is considered an anti pattern. Is there text in the spec about it?

  12. David W Chadwick

    Kristina and myself fundamentally disagree about a verifiable claim or VP from a trusted issuer being an anti-pattern. My view is that it is not an anti-pattern, and I see no difference in terms of either security or trust, between an assertion from a standard OP (the trusted issuer) that identifies and authenticates the user, and a VP signed by the user, containing a VC from the same trusted issuer containing the user’s public key that signed the VP.

  13. Ronald Koenig

    There is no option in the current OIDC4VP spec to return VCs embedded inside an ID Token.

    You are right. Currently, this option is not specified. Nevertheless, I believe this option make sense and should be added if we distinguish between the different response types.

    You seem to be making a distinction whether the claims are about “OpenID user“ or not - what does that mean?

    The OpenID user is the subject of the id_token, i.e. the user which controls the local OP (SIOP) or the user which was identified and authenticated by the OP (standard OP). Either way the OpenID user is uniquely identified by the claim sub of the id_token. Please note, that the subjects of the VC’s are usually not the same as the sub. The subject of an ldp_vc is uniquely defined by the idof the credentialSubject. If you want to make sure that the claims in the id_token and the vp_tokens are about the same user you have to provide proper holder bindings by appropriate authentication proofs of the presentations and you have to make sure that the signature of the id_token and the authentication proofs were applied in the same transaction (e.g. by including a nonce/challenge in all proofs and signatures). It’s possible, but unnecessary complicate. Therefore, we have focused to analyse the feasibility to provide a single id_token where all claims are about the sub and the whole token is signed by a single signature using the private key of the sub. Further, this id_token can easily requested by a presentation definition as a jwt_vp.

  14. David W Chadwick

    Ronald you said “Please note, that the subjects of the VC’s are usually not the same as the sub.” Two points. Firstly I disagree with this statement. Secondly, your example above disagrees with your statement!

  15. Ronald Koenig

    Here is a real id_token. The matching DID’s kid, iss, sub and credentialSubject.id make sure that all claims are about the OpenID user.

    header:

    {
      "alg": "EdDSA",
      "kid": "did:key:z6MkfJa11VRUFattxGJeTo1TUWjCMi5k8Mt9EE5XM4dzknXH",
      "typ": "JWT"
    }
    

    payload:

    {
      "iss": "did:key:z6MkfJa11VRUFattxGJeTo1TUWjCMi5k8Mt9EE5XM4dzknXH",
      "sub": "did:key:z6MkfJa11VRUFattxGJeTo1TUWjCMi5k8Mt9EE5XM4dzknXH",
      "nbf": 1648199153,
      "iat": 1648199153,
      "exp": 1648235153,
      "aud": "https://relyingParty.com/oidc",
      "nonce": "d4b95f1f-5d69-4349-87f4-c7551441954c",
      "vp": {
        "@context": [
          "https://www.w3.org/2018/credentials/v1",
          "https://w3id.org/security/bbs/v1"
        ],
        "type": [
          "VerifiablePresentation"
        ],
        "verifiableCredential": [
          {
            "@context": [
              "https://www.w3.org/2018/credentials/v1",
              "https://w3id.org/citizenship/v1",
              "https://w3id.org/security/bbs/v1"
            ],
            "id": "urn:bnid:_:c14n0",
            "type": [
              "PermanentResidentCard",
              "VerifiableCredential"
            ],
            "credentialSubject": {
              "id": "did:key:z6MkfJa11VRUFattxGJeTo1TUWjCMi5k8Mt9EE5XM4dzknXH",
              "type": [
                "Person",
                "PermanentResident"
              ],
              "birthDate": "1958-07-17",
              "familyName": "Mustermann",
              "givenName": "Marion"
            },
            "issuanceDate": "2022-03-25T10:05:29.410523600",
            "issuer": "did:key:zUC7324D9sqpAWfcpAjMZHS5173zV52A5Pys7wj4tC4yprmXwGbuHztBVCyyLaX6MaEh2ypFoeFMyWhddA88LMASefov9GQk8WKnPYSyKPDHJbX29xRAD1wa2NqPZSnqMEKiaEX",
            "proof": {
              "type": "BbsBlsSignatureProof2020",
              "nonce": "J4N9iksyC+Q7wbYvH5MF11isTkTCzAXuqEDVaKrjLlKbu2BnbVnX7HhtTzPo43CnFvo=",
              "proofValue": "ABQPg7+vW+/wMK7lwTa3q46k75zGbQsB2fv9/xqpwgAu3OwOwe+hQdWn07DBx0wMKx3BEr2FXY7rtuavIGJcHFB0vrANcqj2gj8ZZlzjs5B3+DcgkJsP0vQfbIbB1VAY6SJ7ZWK1PMf8eD3rjvuu1YysuK6gCpkpa0aGPtfxaRCZNyxFfw/xvOjnMr2fdcEJ4YF8gvgAAAB0hI4bWGZ2e48enH9zmH65skHf71KyaK21lY2OlvESJGlRHyBB0tZ8k+GXc63bcD3QAAAAAi9ku4D5FB2mkAlMPMYCUF2UxNGxELOGlE6GA0uqk3XKQ/n6MHfNzZ9TyNdVCVplIeyDfOtOjUTgYnhFo6hGX+uKtS8a73vgHbYOxqonJQ1DtvPMELPlgueDsNxWn8swDp/gztl1bCEhWNaTbz6Xoy0AAAAIDkp26dWE+xR6RP32BQONsGNgQvsjOBHQKNASDVrTMQdXi527drdmgtvmzpon7iYI1m3m1I1lHr4gx12QtTvbnyDGwEppudzM65Po94GhcJdnfUDBIw2EExlACFrljeVGG5FTvwfv+7FYz58NcaNLld6Y8bbdRfqpj3BBBlNSlPZBNg1/BG17DzI1OIC9dQcCVNQWw4Ly6KqELC4RgnjiaHCXDo0Ivi72TTj8pyJ3w9lKNCGCLD6bpgOirdmP6fzaAwpihUUcpOqUt3lmLZlFxF97D6wKVpN66VctiNikHRkNEWy41kHgT2zTShxSQy9qjtZRTZpCvIs72r9o8ytF8A==",
              "verificationMethod": "did:key:zUC7324D9sqpAWfcpAjMZHS5173zV52A5Pys7wj4tC4yprmXwGbuHztBVCyyLaX6MaEh2ypFoeFMyWhddA88LMASefov9GQk8WKnPYSyKPDHJbX29xRAD1wa2NqPZSnqMEKiaEX#zUC7324D9sqpAWfcpAjMZHS5173zV52A5Pys7wj4tC4yprmXwGbuHztBVCyyLaX6MaEh2ypFoeFMyWhddA88LMASefov9GQk8WKnPYSyKPDHJbX29xRAD1wa2NqPZSnqMEKiaEX",
              "proofPurpose": "assertionMethod",
              "created": "2022-03-25T09:05:31.265643+00:00"
            }
          }
        ],
        "presentation_submission": {
          "id": "f0902676-a57c-47fe-a21d-c61fdd3120a7",
          "definition_id": "6728ee4f-ba17-4a02-8989-ed48eb51d73f",
          "descriptor_map": [
            {
              "id": "citizenship",
              "format": "ldp_vc",
              "path": "$.verifiableCredential[0]"
            }
          ]
        }
      }
    }
    

  16. Ronald Koenig

    David, if the holder wishes to present the VC’s in a single ID token he needs to make sure that all VC’s are issued for the sub. I.e. the credentialSubject.id is set to sub. He is doing that by handing over the same holder_did in the corresponding VC requests to the issuer. Sometime, he cannot do that (prevent profiling, requires selective disclosure). Then he will use different DID’s for different credentials. Especially, he will not use his OpenID did as holder did. He can pack these credentials into one vp_token, but then he has to proof the holder binding and the relation to the id_token as described above. In short:

    1. If the sub and the credentialSubject.id's of all VC’s are the same then I would propose to use an id_token to easily express that all claims are about the sub.
    2. If the sub and the credentialSubject.id's are different then use response_type id_token vp_token and proof the relation of the claims to the user as described above.

    I believe there are a lot of use cases where option 1 is more suitable.

  17. David W Chadwick

    Ronald. The VP was expressly created by W3C for the holder to present VCs to an RP/Verifier. The vp_token was created by OIDF to hold the VP. So we already have a mechanism for expressing all your requirements in the vp_token holding a VP, regardless of the IDs of the holder. If the subject IDs are all the same (as in your example) it is easy for the holder to prove possession. If the IDs are different then this increases the complexity for the holder to prove (and the verifier to verify) that all the VCs rightfully belong to the holder, and that he did not simply harvest them from elsewhere. (The annex of the W3C DM gives some suggestions). So personally I don't think we should be putting VCs in the id_token.

  18. Ronald Koenig

    Understood, but your are missing one important point. If the RP (verifier) cannot explicitly request a simple id_token with embedded VC’s (jwt_vp), it has to implement the full complexity (id_token vp_token) or ignore the id_token completely (vp_token). The id_token with embedded VC’s (jwt_vp) is just an additional option. It definitely fits our needs better than the current options.

  19. David W Chadwick

    Ronald I am all for simplicity, which is why I am trying to simplify DIF PE, which is currently being mandated to request a VP. I am not sure how you are proposing to request a set of VCs without using DIF PE. I can assure you that the complexity of implementing DIF PE will outweigh any difficulty of requesting different types of tokens containing the VCs.

  20. Ronald Koenig

    We request a set of VCs by embedding the presentation_defintion of DIF PE into the id_token section of the claims parameter. Here is the authentication request to the above mentioned authentication response:

    {
      "scope": "openid",
      "claims": {
        "id_token": {
          "vp": {
            "presentation_definition": {
              "format": {
                "ldp_vc": {
                  "proof_type": [
                    "Ed25519Signature2018",
                    "BbsBlsSignature2020"
                  ]
                },
                "jwt_vp": {
                  "alg": [
                    "EdDSA"
                  ]
                }
              },
              "input_descriptors": [
                {
                  "schema": [
                    {
                      "uri": "https://www.w3.org/2018/credentials#VerifiableCredential"
                    },
                    {
                      "uri": "https://w3id.org/citizenship#PermanentResidentCard",
                      "required": true
                    }
                  ],
                  "name": "Permanent Resident Card",
                  "id": "citizenship",
                  "constraints": {
                    "limit_disclosure": "required",
                    "fields": [
                      {
                        "path": [
                          "$.credentialSubject.id"
                        ],
                        "id": "ea9da655-3c0c-4015-99b0-3108d24675ba"
                      },
                      {
                        "path": [
                          "$.credentialSubject.givenName"
                        ]
                      },
                      {
                        "path": [
                          "$.credentialSubject.familyName"
                        ]
                      },
                      {
                        "path": [
                          "$.credentialSubject.birthDate"
                        ]
                      }
                    ],
                    "is_holder": [
                      {
                        "field_id": [
                          "ea9da655-3c0c-4015-99b0-3108d24675ba"
                        ],
                        "directive": "required"
                      }
                    ]
                  }
                }
              ],
              "id": "6728ee4f-ba17-4a02-8989-ed48eb51d73f"
            }
          }
        }
      },
      "response_type": "id_token",
      "redirect_uri": "https://relyingParty.com/oidc",
      "state": "66ff8c76-a77c-4658-b6ae-d6eb2581d318",
      "nonce": "d4b95f1f-5d69-4349-87f4-c7551441954c",
      "client_id": "https://relyingParty.com/oidc"
    }
    

  21. David W Chadwick

    I am trying to tease out the rationale for your proposal. Is that, if the subject IDs of the VCs are all the same, then an id_token can be returned without any need to prepare a VP? but if the IDs are different then a VP should be created and returned?

    The problem I have with this is that (most?all?) wallets will already be producing VPs in response to requests, so to ignore this and return a set of VCs to the SIOP might cause more churn for existing wallets. The SIOP then has to create the id_token, which serves the same function as the VP. So wouldn’t it be better for the wallet to return the VP to the SIOP (as it is already doing), and the SIOP place that in the vp_token and not need to create an id_token. This would certainly be the easiest option for my team to implement.

  22. Torsten Lodderstedt reporter

    I advocate for a solution that also works for code flow. I could envision an additional authorization request parameter or scope value “no_id_token” instead of a new response type.

  23. Ronald Koenig

    The rational of our proposal is the following:

    The RP expects an id_token with claims about a single subject (the user) asserted by the user (SIOP) by a strong cryptographic proof. The best way to satisfy these expectations is to respond with a single id_token signed by the user.

    The problem I have with this is that (most?all?) wallets will already be producing VPs in response to requests, so to ignore this and return a set of VCs to the SIOP might cause more churn for existing wallets.

    We don’t ignore this. We just assume that the wallets supports both presentation formats:

    • ldp_vp
    • jwt_vp

    On the presentation exchange layer the only difference between the presentation_definition of a verifier and a RP is the requested format of the presentation:

    • "ldp_vp": { "proof_type": [ "Ed25519Signature2018", ] }

    • "jwt_vp": { "alg": [ "EdDSA" ] }

    The resulting response is either a ldp_vp (verifier) or a jwt_vp (RP) which from the RP perspective is an id_token with embedded VC’s.

  24. David W Chadwick

    Ronald I dont think you are correct about the RP and the Verifier. The VP format being requested does not depend upon the requester’s role: verifier or RP. Either of them can request either format, depending upon their crypto capabilities. However, I might expect an OIDC RP to request JWT format since this is what it already supports for a normal OP. But it can request the ld proofed format if it can support it.

    Furthermore the proof format of the embedded VCs is independent of the proof format of the encapsulating VP, although I would expect both to normally have the same proof formats.

    You also said “We just assume that the wallets supports both presentation formats:” but this confirms what I said, that the wallets will produce VPs and return these, rather than raw VCs.

  25. Kristina Yasuda

    noting that SIOP without an ID Token might be closer to another layer on top of OAuth, than a pure extension of OIDC, which might be interesting given that OAuth2.1 omits implicit flow…

  26. Michael Jones

    Indeed, per Kristina'a comment, if we go down this route, we should contemplate the relationship to OAuth 2.0 as well as OpenID Connect.

  27. Log in to comment