Section 2.2. - Missing parameter to determine the credential type.

Issue #1276 open
Nat Sakimura created an issue

The draft is missing a parameter to determine the credential type.

This is important to allow OPs to support multiple credentials, e.g. a bank could issue identity and credit score credentials, without to need to set up different issuers.

Comments (30)

  1. Tom Jones

    It is not clear that the type of credential is of any help. What the RP needs is proof of something. Take the DHS real-world issue, proof of right ot work. In the US a large number of credentials types will satisfy the need. Do we make it up to the RP to say what type of cred is needed or what proof needs to be presented.

  2. Nat Sakimura reporter

    Torsten probably wants a concrete type of VC.

    The presentation spec has something similar.

    8.1. Embedded Verifiable Presentations

    A Verifiable Presentation embedded in an ID Token (or userinfo response) is requested by adding an element verifiable_presentations to the id_token (or userinfo) top level element of the claims parameter. This element must contain the following element:

    credential_types Object array containing definitions of credential types the RP wants to obtain along with an (optional) definition of the claims from the respective credential type the RP is requesting. Each of those object has the following fields:

    • type REQUIRED String denoting a credential type
    • claims OPTIONAL An object determining the claims the RP wants to obtain using the same notation as used underneath id_token.
    • format OPTION String designating the VP format. Predefined values are vp_ldp and vp_jwt.

    Here is a non-normative example:

    (Source) https://openid.net/specs/openid-connect-4-verifiable-presentations-1_0.html#name-embedded-verifiable-present

    @Torsten Lodderstedt , please verify.

  3. Tobias Looker

    Outstanding questions I have are around credential type are:

    1. What does it infer options include:

      1. A logical set of claims offered AND OR
      2. The format the credential is offered in AND OR
      3. Assurance information about the claims offered in the credential and or other aspects or assurance like authentication assurance
    2. What is the constraints around the value a credential type can be e.g MUST be a string or MUST be a URI

    3. Are there considerations around how values maybe registered for interoperability purposes

  4. Torsten Lodderstedt

    I’m seeking for a way to request issuance of verifiable credentials. The Caller (IDA, Wallet) shall be able to determine type and format of the respective credential.

    I propose to reuse PE syntax we also use in OIDC4VP since the constraints re credentials are basically the same.

    Here is some syntax I played with.

    {
        "c_token": {
            "input_descriptors": [
                {
                    "schema": [
                        {
                            "uri": "https://did.itsourweb.org:3000/smartcredential/Ontario-Health-Insurance-Plan"
                        }
                    ],
                    "constraints": {
                        "format": "jwt_vc"
                    }
                },
                {
                    "schema": [
                        {
                            "uri": "https://www.w3.org/2018/credentials/examples/v1/PassportCredential"
                        }
                    ],
                    "constraints": {
                        "format": "ldp_vc"
                    }
                }
            ]
        }
    }
    

    The “claims” parameter used to request authorization of credential issuance could use input_descriptor elements underneath the new c_token top level element. Every input descriptor elements requests authorization of a certain credential of the type(s) determined by the respective schema elements (see https://identity.foundation/presentation-exchange/spec/v1.0.0/#input-descriptor-object). constraints allows for the definition of further constraints. I think a format element determining the expected credential format would make sense.

    The claims parameter towards the claims endpoint would include a subset of the input descriptors authorized by the end-user.

    Note: I used the current PE syntax. The schema element will be changed to a string array in the next revision (https://github.com/decentralized-identity/presentation-exchange/issues/213).

  5. Kristina Yasuda

    There has been a concern raised during 2021-08-30 call that usually in OIDC ecosystem “credential“ means “machine readable“ “log-in” credentials (password, biometrics, etc.) as opposed to “human-readable“ “about human“ credentials (insurance, mobile driving license, etc.). and to clarify that this PR is about the latter.

    I think using “Identity Credential“ as in Issue #1271 should solve the concern?

  6. Nat Sakimura reporter

    IMHO, “identity credential”, in light of the comment in the call today, will still cause problems. It probably is worth mentioning that this is not only for OIDC ecosystem. ISO/IEC 24760 etc. are in line with OIDC definition – in fact, we made sure that we are basically aligned. The followings are the definition from ISO/IEC 24760-1, which is the foundational document for many other standards.

    3.3.5
    credential
    representation of an identity (3.1.2) for use in authentication (3.3.1)

    3.3.1
    authentication
    formalized process of verification (3.2.2) that, if successful, results in an authenticated identity (3.3.2) for an entity (3.1.1)

  7. Nat Sakimura reporter

    Also, in today’s call, we summarize that there are two basic topics that this issue is posing beside the terminology issue.

    • How to represent the set of claims.

      • This aspect is represented by the “schema/uri” element in Torsten’s example.
      • OIDC has two ways of doing it: as individual claims, and scope value that can work as the shorthand for the set of claims, e.g., “profile”. We need to ask if it is a good idea to add yet another way of doing it as it will against the goal of standardization. If we are, we need to have a very good reason why it cannot be done with the existing way of doing it.
    • How to express the desired response format.

      • This aspect is represented by the “constraints/format” element in Torsten’s example.
      • Questions arise in the case of when the issuing authority (claims provider) is not providing that particular format etc. Does the client need to select one from the options that IA is providing? Or if there is not enough information about the formats that IA is supporting, would the client list all possible options that it can consume?

  8. Tom Jones

    Not exactly clear what IA means or how this involves any parties except the RP and user (who is hosting the OP) It seems that the RP is requesting a lot from the wallet which i cannot imagine that it has the resources in the user’s smartphone to respond rationally. What exactly is it that the user’s smartphone should be expected to perform here?

  9. Jeremie Miller Account Deactivated

    It seems that the RP is requesting a lot from the wallet which i cannot imagine that it has the resources in the user’s smartphone to respond rationally.

    The wallet software can host metdata about its capabilities on its own app site’s .well-known endpoint or have it published in a trust framework/registry. There isn’t any known safe ways to request metadata from a wallet app directly without already having gotten some authoritative metadata already.

  10. Tom Jones

    There are well-known ways to get secure data from remote apps that have been around for at least 10 years. If you mean that those methods are not widely-deployed, then i might agree with you. I guess the question is whether we should be building standards based on known, but unused, security methods. Or just stick to the existing app models. Personally, I want to move in the direction of known-good apps running on smartphones. I really don’t see any other way to get security for self-issued identifiers. I understand the fatalistic view that it would be difficult. I just disagree that we should therefore abandon all hope.

  11. Torsten Lodderstedt

    @tom this issue is related to the interface between wallet and credential provider. The credential provider acts as OpenID Connect OP. The wallet might be hosted at the user’s device.

  12. Tom Jones

    i agree with your earlier suggestion to separate the csp from the op. It is really hard to follow the spec as written.

  13. Tobias Looker

    Here are a few suggested proposals:

    • The type communicates the logical set of claims conveyed by the credential and not the format of the credential
    • The only constraint on the type value is that it must be a string, hence it can ALSO be any form of valid URI but it doesn’t have to be
    • We define syntax that allows to request a credential type as a scope e.g something like openid_credential:<credential-type>

  14. Nat Sakimura reporter

    SO, @Torsten Lodderstedt and @Kristina Yasuda, what is your concrete text proposal?
    Perhaps a PR?

  15. Nat Sakimura reporter

    @Tobias Looker , Torsten Lodderstedt,

    From this thread, I see that there are three “wants”:

    1. What claims the Client (Wallet, Intermediary, or the final client) wants;
    2. In which representation (content-type) the Client wants them; and
    3. Specify schema for non-IANA registered claims via URI (e.g., https://did.itsourweb.org:3000/smartcredential/Ontario-Health-Insurance-Plan)

    For 1, we do have an existing way in OIDC so it should not be an issue. We should just be able to use it. claims parameter or score (though it has to be defined in the ecosystem) should suffice.

    For 2, we need to express the desired response format. To me, that looks a lot like a mime media type. If we assume HTTP, we could as well use the standard Accept: request headers. It can provide more than one.

    Torsten’s example uses input_descriptors/constraints/format JSON object for this purpose instead.

    To me, trying to request it in the request JSON looks a bit too SOAPy. Yes, if you are using some other protocols than HTTP, we may need to do so, but I would like it to be demonstrated that such protocols have no native way of expressing it.

    For 3, Torsten’s example is using the input_descriptors/schema/uri as the claim name and https://did.itsourweb.org:3000/smartcredential/Ontario-Health-Insurance-Plan as its value. This seems to be assuming a lot in the background, e.g., The Claims Issuer (Issuing Authority, IA) can support multiple schema, wallets or Intermediary IdPs can provide schema translation, claims consumer knows the schema that IA and wallets support etc. Am I right?

  16. Nat Sakimura reporter

    On the AB/C Pacific Call today (2021-10-18), we discussed it for about 30 min.

    Summary:

    1. There is a want for expressing groups of claims, just like “profile” scope. That’s what “schema” in Torsten’s example is and now is replaced with “type” in PE drafts.
    2. There is a want for expressing the format that each set of claims to be returned. In the PE context, it is proposed to be expressed through an array of JSON objects. For example:

        "input_descriptors": [
          {
            "id": "bankaccount_input",
            "name": "Full Bank Account Routing Information",
            "purpose": "We can only remit payment to a currently-valid bank account, submitted as an ABA RTN + Acct # or IBAN.",
            "schema": [{
                "uri": "https://bank-standards.example.com/fullaccountroute.json"
            }],
            "limit_disclosure": "required",
            "fields": [ ...field constraints ]
          }
        ]
    (Source: https://github.com/decentralized-identity/presentation-exchange/issues/212)
    

    (I am not sure the “schema” above should now be “type”)

    Hearing that, there was a question if we really want to do it like this. It is typically a backend call in OAuth/OpenID Connect and these “credentials” (logical set of claims) is a resource. Then, they should be accessed as a regular OAuth resource. So, typically, it would be like:

    GET /fullaccoutroute.json HTTP/1.1
    Host: bank-standards.example.com
    Authorization: Bearer SlAV32hkKG
    Accept: appliation/jose
    

    and repeats that to each resource (logical set of claims).

    This seems to go better with the current models of OAuth and OpenID Connect, which is RESTy instead of SOAPy ones above.

    There was also a question of consent asked in the call.

    It was clarified that the consent at the Issuing Authority (Credential Provider) has to happen at the consent set-up phase. In the phase, the End-User goes through the usual OAuth/OpenID Connect redirect flow to provide “consent” to the IA/CP through the front channel. Then, the Intermediate Identity Provider/wallet as a client can further constrain the claims that it requests to the resource but if it wants to expand the claims, it has to get additional “consent” via redirect or CIBA like flow.

    To express the response media types, it was pointed out that SOAP way is more versatile than REST way in which the client has to do so according to each underlying protocol (such as HTTP) but the simplicity of REST way has so far captured the world so there are pros and cons around it.

  17. Torsten Lodderstedt

    Based on the conversations at IIW last week, I see two (complementary) options.

    Simple type element denoting the verifiable credential type as URI:

    {
        "vc_token":{
            "type": ["uri":"..."]
        }
    }
    

    Use of the credential_application as defined in https://identity.foundation/credential-manifest/

    {
        "vc_token": {    
          "credential_application": {
            "id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
            "manifest_id": "WA-DL-CLASS-A",
            "format": {
              "ldp_vc": {
                "proof_type": [
                  "JsonWebSignature2020",
                  "EcdsaSecp256k1Signature2019"
                ]
              }
            }
          }
       }
    }
    

  18. Tobias Looker

    Is the first syntax proposal suppose to be

    {
        "vc_token":{
            "type": ["<uri>"]
        }
    }
    

    OR

    {
        "vc_token":{
            "type": [{ "uri":"..." }]
        }
    }
    

    IMO ideally the syntax should be additive e.g simplest case is just defining a type which sets the set of claims (or the credential) the RP is requesting. Downscoping with further restrictions can be added by expanding on other elements in the vc_token object.

  19. Nat Sakimura reporter

    I am still vague on what the “type” means. From Tobias’s description, it looks like a response from a resource URL that contains multiple claims associated with at least one “proof”. Am I right?

    If so, why would not just a simple GET to a resource (with appropriate Authorization and Accept header) work? Is there any reason for using SOAP pattern instead of REST pattern?

  20. Nat Sakimura reporter

    In the AB/C Atlantic call today, Torsten explained that “type” is an abstract notion of a set of claims with proof, e.g., Verifiable Credential representing Driver’s License, and is not the format. His wants are to express it in the authorization request to the issuer.

    In OIDC/OAuth context, this sounds awfully like a value in scope. It could also be a claim, as the corresponding claim value can be JSON object or JWT.

    So, 8.2, 8.3, and 8.4 in https://openid.net/specs/openid-connect-claims-aggregation-1_0.html#setup-phase can become something like this.

    8.2.  Authorization request and response

    8.2.1 Authorization request

    A Signed Claim Set (including W3C VC) Request uses the OpenID and OAuth2.0 request parameters as outlined in section 3.1.2.1 of OpenID Connect core.

    When requesting a type of W3C VC, the IdA MUST do so by selecting one of the mechanism below:

    • List the W3C VC Type values that it is requesting in the scope in the Authentication Request; OR
    • LIST the W3C VC Type values as the claim names with c_token; OR
    • List the W3C VC Type values in the “claims/vc_token/type” claim as a JSON array in the Authentication Request;

    Following is a non-normative example for the scope case, which is the most OAuth like syntax among the three presented here. (Line wraps are for the ease of reading only.)

    GET /authorize?
        response_type=code
        &scope=openid%20https://did.exmaple.org/mDL
        &client_id=s6BhdRkqt3
        &state=af0ifjsldkj
        &redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb HTTP/1.1
    Host: server.example.com
    

    Following is a non-normative example for using the native OIDC claims syntax where the top-level member of c_token JSON object denotes the type. (Line wraps are for the ease of reading only.)

    {
       "c_token":
        {
         "https://did.exmaple.org/mDL": {"essential":true},
         "https://did.example.org/healthCard":null
        },
       "id_token":
        {
         "auth_time": {"essential": true},
         "acr": {"values": ["urn:mace:incommon:iap:silver"] }
        }
    }
    

    Following is a non-normative example for the new syntax leveraging “type” member.

    {
       "c_token":
        {
         "type":["https://did.exmaple.org/mDL", "https://did.example.org/healthCard"]
        },
       "id_token":
        {
         "auth_time": {"essential": true},
         "acr": {"values": ["urn:mace:incommon:iap:silver"] }
        }
    }
    

    NOTE: “c_token” and “vc_token” are not returned from the Token Endpoint but will be returned from the respective resource endpoints.

    The IdA can also leverage OIDC4IA to obtain verified claims.

    Following is a non-normative example when IdA utilizes OIDC4IA.

      "c_token": {
        "verified_claims": {
          "verification": {
            "trust_framework": null
          },
          "claims": {
            "given_name": {
              "essential": true
            },
            "family_name": {
              "essential": true
            },
            "birthdate": null
          }
        }
      }
    

    8.2.2 Successful Authorization Response

    Successful and Error Authentication Response are in the same manner as OpenID Connect Core 1.0 with the code parameter always being returned with the Authorization Code Flow.

    The following is a non-normative example of a successful token response.

    HTTP/1.1 302 Found
    Location: https://client.example.net/cb?
        code=SplxlOBeZQQYbYS6WxSbIA
        &state=af0ifjsldkj
    

    8.2.3 Unsuccessful Authorization Response

    The error response MUST follow 3.1.2.6 of [OIDC].

    The following is a non-normative example of a failed token response.

    HTTP/1.1 302 Found
    Location: https://client.example.net/cb?
        error=invalid_request
        &error_description=
          Unsupported%20response_type%20value
        &state=af0ifjsldkj
    

    8.3.  Token Endpoint Request and Response

    8.3.1 Token endpoint request

    On receiving the successful authorization response, the IdA MUST send a Token Request with the following parameters:

    • grant_type REQUIRED. The value MUST be authorization_code  
    • code REQUIRED. The value MUST be the value of the code parameter received in the Authorization Response.

    The following is a non-normative example of a token request.

    POST /token HTTP/1.1
    Host: server.example.org
    Content-Type: application/x-www-form-urlencoded
    Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
    
    grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
        &redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
    

    8.3.2 Successful Token Endpoint Response

    The following is a non-normative example of a response from the token endpoint, whereby the access_token authorizes the IdA to request a credential from the claimset endpoint.

    {
        "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6Ikp..sHQ",
        "token_type": "bearer",
        "expires_in": 86400,
        "id_token": "eyJodHRwOi8vbWF0dHIvdGVuYW50L..3Mz"
    }
    

    EDITOR’S NOTE: In the above, the same access_token value is used to request userinfo, c_token, vc_token. Alternatively, it could return distinct access tokens from this endpoint, e.g.,

    {
        "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6Ikp..sHQ",
        "token_type": "bearer",
        "expires_in": 86400,
        "id_token": "eyJodHRwOi8vbWF0dHIvdGVuYW50L..3Mz", 
        "c_token": {"url":"https://server.example.org/c", "access_token": "eyJhbGafsd..qVV"}
    }
    

    8.3.3 Token Endpoint Error Response

    If the Token Request is invalid or unauthorized, the Authorization Server constructs the error response. The parameters of the Token Error Response are defined as in Section 5.2 of OAuth 2.0 [RFC6749]. The HTTP response body uses the application/json media type with HTTP response code of 400.

    The following is a non-normative example Token Error Response:

    HTTP/1.1 400 Bad Request
    Content-Type: application/json
    Cache-Control: no-store
    Pragma: no-cache
    
    {
       "error": "invalid_request"
    }
    

    8.4 Claimset/VC Request and Response

    NOTE: This section conceptually should belong to section 9.5. However, since many readers do not get that claims collection can happen out-of-sync with the CC request, it is brought here.

    8.4.1 Claimset/VC Request

    To obtain the OIDC Signed Claimset or W3C Verifiable Credentials, the IdA sends Request using either HTTP GET or HTTP POST. The Access Token obtained 8.3.2 MUST be sent as a Bearer Token, per Section 2 of OAuth 2.0 Bearer Token Usage.

    Note: The access token used here is bound to the subject (user) so the claimset endpoint can figure out which subject’s claimset/VC that it needs to return.

    Also note that to establish the binding between the user of the IdA and the claimset being returned, a binding material MUST be included in the request.

    When the Claimset/VC is issued on-the-fly to the CC request, the nonce in the CC request MUST be sent as the binding material.

    When the Claimset/VC is issued independently to the CC request, then a nonce created by IdA MUST be included in the request as nonce member.

    The following is a non-normative example of a Signed Credential request.

    POST /claims HTTP/1.1
    Host: https://issuer.example.org
    Authorization: Bearer <access-token>
    Content-Type: application/json
    {
      "request": <signed-jwt-request-obj>
    }
    

    where the decoded payload of the request parameter is as follows:

    {
        "aud": "https://issuer.example.com",
        "iss": "https://wallet.example.com",
        "sub": "urn:uuid:dc000c79-6aa3-45f2-9527-43747d5962a5",
        "sub_jwk": {
            "crv":"secp256k1",
            "kid":"YkDpvGNsch2lFBf6p8u3",
            "kty":"EC",
            "x":"7KEKZa5xJPh7WVqHJyUpb2MgEe3nA8Rk7eUlXsmBl-M",
            "y":"3zIgl_ml4RhapyEm5J7lvU-4f5jiBvZr4KgxUjEhl9o"
        },
        "claimset_format": "w3cvc-jwt",
        "nonce": "43747d5962a5",
        "iat": 1591069056,
        "exp": 1591069556
    }
    

    8.4.2 Successful Claimset/VC Response

    Upon receiving the request in 8.4.1, the claims endpoint first verifies the request by:

    • Verify the access token is still valid;
    • Verify the signature of the request using the supplied sub_jwk.
    • Verify the request is well-formed.

    When the verification succeeds, it returns Claimset/VC Successful Response.

    The following is a non-normative example of a claims endpoint response in JSON-LD.

    {
      "format": "w3cvc-jsonld",
      "credential": {
        "@context": [
          "https://www.w3.org/2018/credentials/v1",
          "https://www.w3.org/2018/credentials/examples/v1"
        ],
        "id": "http://example.gov/credentials/3732",
        "type": ["VerifiableCredential", "UniversityDegreeCredential"],
        "issuer": "https://issuer.edu",
        "issuanceDate": "2020-03-10T04:24:12.164Z",
        "credentialSubject": {
          "id": "did:example:1234",
          "degree": {
            "type": "BachelorDegree",
            "name": "Bachelor of Science and Arts"
          }
        },
        "proof": {
          "type": "Ed25519Signature2018",
          "created": "2020-04-10T21:35:35Z",
          "verificationMethod": "https://issuer.edu/keys/1",
          "proofPurpose": "assertionMethod",
          "jws": "eyJhbGciOiJFZERTQSIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..l9d0YHjcFAH2H4dB9xlWFZQLUpixVCWJk0eOt4CXQe1NXKWZwmhmn9OQp6YxX0a2LffegtYESTCJEoGVXLqWAA"
        }
      }
    }
    

    The following is a non-normative example of a VC Response in JWT:

    // JWT decoded for readability
    {
        "alg": "RS256",
        "typ": "JWT",
        "kid": "did:example:abfe13f712120431c276e12ecab#keys-1"
    }.
    {
      "sub": "did:example:ebfeb1f712ebc6f1c276e12ec21",
      "jti": "http://example.edu/credentials/3732",
      "iss": "https://example.com/keys/foo.jwk",
      "nbf": 1541493724,
      "iat": 1541493724,
      "exp": 1573029723,
      "nonce": "660!6345FSer",
      "vc": {
        "@context": [
          "https://www.w3.org/2018/credentials/v1",
          "https://www.w3.org/2018/credentials/examples/v1"
        ],
        "type": ["VerifiableCredential", "UniversityDegreeCredential"],
        "credentialSubject": {
          "name": "Alex Johnson",
          "major": "Mechanical Engineering",
          "date":  "06/15/1998",
          "studentId": "12515010",
        }
      }
    }.
    BND3LDTn9H7FQokEsUEi8jKwXhGvoN3JtRa51xrNDgXDb0cq1UTYB-rK4Ft9YVmR1NI_ZOF8oGc_7wAp
    8PHbF2HaWodQIoOBxxT-4WNqAxft7ET6lkH-4S6Ux3rSGAmczMohEEf8eCeN-jC8WekdPl6zKZQj0YPB
    1rx6X0-xlFBs7cl6Wt8rfBP_tZ9YgVWrQmUWypSioc0MUyiphmyEbLZagTyPlUyflGlEdqrZAv6e
    

    Then, the 9.5 will be replaced by the following:

    9.5.  Claims Collection for the on-the-fly sequence

    If the IdA has not collected the W3C VC or signed claimset previously, then to provide a valid response to CC, IdA needs to collect them on the fly according to what is specified in 8.4.

  21. Kristina Yasuda

    Thank you, Nat for the thoughtful proposal! We have been collecting requirements from the industry/implementors and should be able to post them in this comment soon as promised.

  22. Log in to comment