aries-cloudagent-python icon indicating copy to clipboard operation
aries-cloudagent-python copied to clipboard

DIF Presentation Issue: Credential Not Identified Despite Matching Schema Context

Open Sshovon opened this issue 10 months ago • 7 comments

I am using acapy-v1.2.0 and issuing a json-ld credential. Following is the payload for credential issuance.

{
  "connection_id": "8d6571c3-f738-458a-a57b-0c45ef8e3050",
  "comment": "",
  "auto_remove": false,
  "filter": {
    "ld_proof": {
      "credential": {
        "@context": [
          "https://www.w3.org/2018/credentials/v1",
          "https://w3c-ccg.github.io/citizenship-vocab/contexts/citizenship-v2.jsonld"
        ],
        "type": [
          "VerifiableCredential",
          "Person"
        ],
        "issuer": "did:key:z6MkoNaEEqvz3k1RmVbxbnN5vxjuXrf9bv6UHbwdwWYW2e6L",
        "issuanceDate": "2025-01-13T18:37:13.298Z",
        "credentialSubject": {
          "birthDate": "1958-07-17",
          "familyName": "SMITH",
          "gender": "female",
          "givenName": "ALICE",
          "type": [
            "Person"
          ]
        }
      },
      "options": {
        "proofType": "Ed25519Signature2018"
      }
    }
  }
}

If I call /credentials/w3c/, I get following output for the received credential.

{
  "results": [
    {
      "contexts": [
        "https://w3c-ccg.github.io/citizenship-vocab/contexts/citizenship-v2.jsonld",
        "https://www.w3.org/2018/credentials/v1"
      ],
      "expanded_types": [
        "https://www.w3.org/2018/credentials#VerifiableCredential",
        "https://schema.org/Person"
      ],
      "schema_ids": [],
      "issuer_id": "did:key:z6MkoNaEEqvz3k1RmVbxbnN5vxjuXrf9bv6UHbwdwWYW2e6L",
      "subject_ids": [
        "did:key:z6Mknu7uS59C94C1zHq5mnWhpCfZcfZGEFmPsWFYYQMrWH6g"
      ],
      "proof_types": [
        "Ed25519Signature2018"
      ],
      "cred_value": {
        "@context": [
          "https://www.w3.org/2018/credentials/v1",
          "https://w3c-ccg.github.io/citizenship-vocab/contexts/citizenship-v2.jsonld"
        ],
        "type": [
          "VerifiableCredential",
          "Person"
        ],
        "issuer": "did:key:z6MkoNaEEqvz3k1RmVbxbnN5vxjuXrf9bv6UHbwdwWYW2e6L",
        "issuanceDate": "2025-01-13T18:37:13.298Z",
        "credentialSubject": {
          "birthDate": "1958-07-17",
          "familyName": "SMITH",
          "gender": "female",
          "givenName": "ALICE",
          "type": [
            "Person"
          ],
          "id": "did:key:z6Mknu7uS59C94C1zHq5mnWhpCfZcfZGEFmPsWFYYQMrWH6g"
        },
        "proof": {
          "type": "Ed25519Signature2018",
          "proofPurpose": "assertionMethod",
          "verificationMethod": "did:key:z6MkoNaEEqvz3k1RmVbxbnN5vxjuXrf9bv6UHbwdwWYW2e6L#z6MkoNaEEqvz3k1RmVbxbnN5vxjuXrf9bv6UHbwdwWYW2e6L",
          "created": "2025-01-13T18:37:37+00:00",
          "jws": "eyJhbGciOiAiRWREU0EiLCAiYjY0IjogZmFsc2UsICJjcml0IjogWyJiNjQiXX0..ElIQ--tE7WFWTN-8zRvWqi6v2vSJ37zVcg3xYLtxRUZWnY8-ZSjUXEKHb1YVkUwUQ38s7_euD5q58RxBTNkhCg"
        }
      },
      "cred_tags": {},
      "record_id": "1683a4095dd842669e65dfe10eb31bcd"
    }
    
  ]
}

Now I want to verify this credential. To do so from verifier I send a proof request using following payload.

{
  "connection_id": "8d6571c3-f738-458a-a57b-0c45ef8e3050",
  "presentation_request": {
    "dif": {
      "options": {
        "challenge": "4af538f3-26ed-4064-90f6-78ef150b778d",
        "domain": "wEYJDTwvop1G"
      },
      "presentation_definition": {
        "id": "ceb9b176-dd1c-4f51-9e76-fe386f4fc72c",
        "name": "proof-request",
        "purpose": "authentication",
        "input_descriptors": [
          {
            "id": "5ca22614-2931-4234-8841-11f8141e4c43",
            "name": "proof-request",
            "schema": [
              {
                "uri": "https://w3c-ccg.github.io/citizenship-vocab/contexts/citizenship-v2.jsonld"
              }
            ],
            "constraints": {
              "fields": [
                {
                  "path": [
                    "$.credentialSubject.familyName"
                  ],
                  "purpose": "authentication"
                }
              ]
            }
          }
        ]
      }
    }
  }
}

But when I run /present-proof-2.0/records/{pres_ex_id}/credentials on holder it is not able to find the credential for presentation. But if I change the schema uri to https://schema.org/Person (which is technically the @id of Person in https://w3c-ccg.github.io/citizenship-vocab/contexts/citizenship-v2.jsonld and also present in the expanded_type in w3c credential record) then it is able to find the credential for presentation. . I am a little bit confused here..shouldn't the schema uri be as same as the one used in context during issuance ? Please let me know if I am missing out something.

Sshovon avatar Jan 13 '25 20:01 Sshovon

@PatStLouis @dbluhm — can either of you help here?

swcurran avatar Jan 13 '25 20:01 swcurran

@https://github.com/openwallet-foundation/acapy/blob/38d79b97bf3f73a052f87625fa0c50f03078f69b/acapy_agent/protocols/present_proof/dif/pres_exch_handler.py#L1016 here in this function, it's trying to find the id in expanded_types. adding a find in context might help..

Sshovon avatar Jan 13 '25 20:01 Sshovon

Try adding #Person onto the end of the uri in the presentation definition:

            "schema": [
              {
                "uri": "https://w3c-ccg.github.io/citizenship-vocab/contexts/citizenship-v2.jsonld#Person"
              }
            ]

I haven't questioned this or looked deeply into it but I've discovered that, in order to request a presentation with a schema uri, the implementation expects the type to be on the end of the uri as a fragment. As another example, to match the root VerifiableCredential type, you have to use the following URI:

https://www.w3.org/2018/credentials#VerifiableCredential

dbluhm avatar Jan 13 '25 21:01 dbluhm

@dbluhm, You are absolutely correct about the root one. But the other one doesn't work if I add #Person. This is the payload.

{
  "created_at": "2025-01-13T21:19:27.466103Z",
  "state": "request-received",
  "proof_id": "c042b929-39e9-492d-9a01-6bc9e29cbffa",
  "connection_id": "2e3dbe84-2c6a-4e8a-aced-ae0f04dd1788",
  "presentation_request": {
    "json": {
      "options": {
        "challenge": "c5494c67-3c3d-44a6-92fc-f2d4110640e4",
        "domain": "Zr22cEpmHfrG"
      },
      "presentation_definition": {
        "id": "d395e550-4fa2-4ea1-9475-7a56c0acecc7",
        "name": "proof-request",
        "purpose": "authentication",
        "input_descriptors": [
          {
            "id": "26951b81-055b-4d9e-a023-58e230d574ca",
            "name": "proof-request",
            "schema": [
              {
                "uri": "https://w3c-ccg.github.io/citizenship-vocab/contexts/citizenship-v2.jsonld#Person"
              }
            ],
            "constraints": {
              "fields": [
                {
                  "path": [
                    "$.credentialSubject.familyName"
                  ],
                  "purpose": "authentication"
                }
              ]
            }
          }
        ]
      }
    }
  }
}

I can give you another example.. If I try to issue similar credential with context https://w3id.org/citizenship/v1 and and type PermanentResident then /present-proof-2.0/record/id/credential returns me credentials for presentation if i use https://w3id.org/citizenship#PermanentResident as schema uri. In both cases, if we observe the context and expanded_types values then we can see some similarities. That contexts are somehow resolved into the values that is being stored in the expanded_types. Even for the root , https://www.w3.org/2018/credentials/v1 is being stored as https://www.w3.org/2018/credentials#VerifiableCredential For the latest issuance,

"contexts": [
        "https://www.w3.org/2018/credentials/v1",
        "https://w3id.org/citizenship/v1"
      ],
  "expanded_types": [
    "https://w3id.org/citizenship#PermanentResident",
    "https://www.w3.org/2018/credentials#VerifiableCredential"
],

And this is for the initial issuance,

"contexts": [
        "https://www.w3.org/2018/credentials/v1",
        "https://w3c-ccg.github.io/citizenship-vocab/contexts/citizenship-v2.jsonld"
      ],
"expanded_types": [
  "https://www.w3.org/2018/credentials#VerifiableCredential",
  "https://schema.org/Person"
],

If I am not wrong then it seems schema uri directly trying to match the stored value in the expanded_types.

Example issuance payload,

{
  "connection_id": "a5014870-ae94-4ffe-bded-39fe682a4d31",
  "comment": "",
  "auto_remove": false,
  "filter": {
    "ld_proof": {
      "credential": {
        "@context": [
          "https://www.w3.org/2018/credentials/v1",
          "https://w3id.org/citizenship/v1"
        ],
        "type": [
          "VerifiableCredential",
          "PermanentResident"
        ],
        "issuer": "did:key:z6Mkj2Fu8R8UsT4FDzgeSR1wAMGKHMVLWbBf7P5CXLwmSj3y",
        "issuanceDate": "2025-01-13T21:24:19.444Z",
        "credentialSubject": {
          "givenName": "ALICE",
          "familyName": "SMITH",
          "gender": "Female",
          "birthCountry": "Bahamas",
          "birthDate": "1958-07-17",
          "type": [
            "PermanentResident"
          ]
        }
      },
      "options": {
        "proofType": "Ed25519Signature2018"
      }
    }
  }
}

Example verification payload,

{
  "connection_id": "a5014870-ae94-4ffe-bded-39fe682a4d31",
  "presentation_request": {
    "dif": {
      "options": {
        "challenge": "205cd470-ab7b-44b6-966b-eba94667a3f0",
        "domain": "7ZzrrXpzarXP"
      },
      "presentation_definition": {
        "id": "45b4806d-1cd4-4509-b230-8520459dfbfe",
        "name": "proof-request",
        "purpose": "authentication",
        "input_descriptors": [
          {
            "id": "fe8b17b1-7605-4d01-ac52-26ffe9d0111b",
            "name": "proof-request",
            "schema": [
              {
                "uri": "https://w3id.org/citizenship#PermanentResident"
              }
            ],
            "constraints": {
              "fields": [
                {
                  "path": [
                    "$.credentialSubject.familyName"
                  ],
                  "purpose": "authentication"
                }
              ]
            }
          }
        ]
      }
    }
  }
}

Sshovon avatar Jan 13 '25 21:01 Sshovon

I did some exploration with your examples and have recreated the scenario you described. ACA-Py is indeed "expanding" the type of the credential and using the @id from the json-ld context for the type as the expanded_type. Not being the original implementer of this bit of ACA-Py, I can't speak to the motivations of that exact approach. At the same time, it seems a fair choice.

I think what we're seeing is a result of the Presentation Exchange Spec not having precise text for using presentation definitions to request JSON-LD based credentials. The schema[].uri, at least from the examples in the spec, seems to be intended for pointing to a JSON Schema uri, but the description of the attribute does not specify exactly what is expected. In later versions of the PEx spec, the schema[].uri input descriptor value is replaced by just a field descriptor for a credentialSchema.id with an exact match to a schema uri:

...
           "fields": [
            {
              "path": ["$.credentialSchema.id", "$.vc.credentialSchema.id"],
              "filter": {
                "type": "string",
                "const": "hub://did:foo:123/Collections/schema.us.gov/passport.json"
              }
            },
...

So I agree that this seems an odd process but it seems a technically valid way to use the PEx 1.0 spec with JSON-LD credentials. Notably, this is the way agents ACA-Py interops with (e.g. Credo) expect to have JSON-LD credentials requested so it aligns with how this is conventionally used. Modifying this behavior would constitute a breaking change that would extend beyond the sphere of ACA-Py.

dbluhm avatar Jan 14 '25 16:01 dbluhm

I'm curious if @PatStLouis has any additional insights

dbluhm avatar Jan 14 '25 16:01 dbluhm

Thanks a lot for the brief explanation @dbluhm .

Sshovon avatar Jan 14 '25 18:01 Sshovon