aries-cloudagent-python
aries-cloudagent-python copied to clipboard
DIF Presentation Issue: Credential Not Identified Despite Matching Schema Context
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.
@PatStLouis @dbluhm — can either of you help here?
@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..
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, 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"
}
]
}
}
]
}
}
}
}
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.
I'm curious if @PatStLouis has any additional insights
Thanks a lot for the brief explanation @dbluhm .