# aca-py & OpenID for Verifiable Presentations
**Example for verifier-initiated cross device flow (SIOP)**
```plantuml
@startuml
'https://plantuml.com/sequence-diagram
skinparam BoxPadding 10
autonumber
actor User
participant Controller
participant "aca-py" as HolderAgent
participant "OIDC\nRelying Party" as RP
== Holder receives auth request ==
RP -> Controller : auth request w/ request_uri [see note A]
activate Controller
Controller -> Controller : derive invitation from auth request [see note B]
Controller -> HolderAgent : receive-invitation
activate HolderAgent
HolderAgent -> HolderAgent : create conn record
Controller <-- HolderAgent : conn record
== Agent fetches request object ==
opt without auto-accept
Controller -> User : accept invitation?
activate User
User --> Controller : OK
deactivate User
Controller -> HolderAgent : accept-invitation
deactivate Controller
end
HolderAgent -> RP : GET request_uri [see note C]
activate RP
RP -> RP : create request object
HolderAgent <-- RP : 200 OK : request object
deactivate RP
HolderAgent -> HolderAgent : update conn record
deactivate Controller
HolderAgent -> HolderAgent : create pres ex record & oid4vp record
HolderAgent ->> Controller : Event(pres ex record)
deactivate HolderAgent
activate Controller
== Holder creates Verifiable Presentation with W3C credentials ==
User <- Controller : send presentation?
deactivate Controller
activate User
User --> Controller : OK
deactivate User
activate Controller
Controller -> HolderAgent : get matching credentials
activate HolderAgent
Controller <-- HolderAgent : credentials
deactivate HolderAgent
opt
User <- Controller : choose credentials
deactivate Controller
activate User
User --> Controller : credentials
deactivate User
activate Controller
end
Controller -> Controller : create presentationSpec
Controller -> HolderAgent : send-presentation(presentationSpec)
activate HolderAgent
HolderAgent -> HolderAgent : create vp_token, presentation_submission
HolderAgent -> RP : POST redirect_uri (vp_token, presentation_submission) [see Note D]
note right : session information is conveyed via ""nonce"".
activate RP
HolderAgent -> HolderAgent : update pres ex record
Controller <-- HolderAgent : pres ex record
deactivate HolderAgent
deactivate Controller
== RP verifies presentation ==
RP -> RP : verify token
deactivate RP
deactivate Controller
@enduml
```
## Note A
**Auth Request**
```
https://wallet.example.org?
client_id=https%3A%2F%2Fclient.example.org%2Fcb
&request_uri=https%3A%2F%2Fclient.example.org%2F567545564
```
See https://openid.net/specs/openid-4-verifiable-presentations-1_0.html
for a format specification of a deferred authentication request with request-uri
:::info
:bulb: **Note**
the non-normative authentication request example given in https://openid.net/specs/openid-4-verifiable-presentations-1_0.html#section-7.2 lacks compliance with OIDC core 1.0, because the required parameter "scope" is missing.
:::
To allow for on-device and cross-device scenarios, the login page of the web service presents both a QR code (cross-device) and an app link / universal link (on-device).
## Note B
**OOB Invitation Message Derived From Auth Request** ([InvitationMessage](https://github.com/hyperledger/aries-cloudagent-python/blob/main/aries_cloudagent/protocols/out_of_band/v1_0/messages/invitation.py))
[Aries RFC 0434 Out-of-Band Protocol 1.1](https://github.com/hyperledger/aries-rfcs/tree/main/features/0434-outofband)
```json
{
"@id": "ba80c9a4-a087-42f3-97df-2612b21ba446", // UUID generated by controller
"@type": "https://didcomm.org/out-of-band/1.0/invitation",
"label": "Auth Request by https://client.example.org",
"handshake_protocols": [
"https://example.org/oid4vp-handshake/0.1" // non-didcomm protocol
],
"services": [
{
"id": "https://client.example.org",
"serviceEndpoint": "https://client.example.org/567545564", // request_uri
"type": "oid_request_uri" // custom type
}
]
}
```
:::info
:bulb: **Note**
This approach assumes that there are no parameters in the auth request which are not also included in the request object, apart from `request_uri`. If the auth request contains parameters which must be considered, the invitation message could possibly be derived by including the auth request as an attachment. (see [Aries RFC 0434](https://github.com/hyperledger/aries-rfcs/tree/main/features/0434-outofband#messages))
:::
## Note C
**Request Object**
```json
{
"client_id": "https://client.example.org/post",
"redirect_uri": "https://client.example.org/post",
"response_type": "vp_token",
"response_mode": "post",
"presentation_definition": {...},
"nonce": "9391b6c3-e77d-4fec-a4d0-8bb1af85139b" // aca-py: challenge must be UUID4
}
```
<!--
The following presentation definition inside an authentication request (such as in **Note A** requests selected claims from the citizenship credential according to https://openid.net/specs/openid-4-verifiable-presentations-1_0.html#name-verifier-initiated-cross-de
The holder is defined by the `id` of `credentialSubject`.
The holder must prove control of the private key belonging to the holder did when presenting the proof to the verifier.
**Presentation Definition**
```json
{
"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"
}
```
-->
**Presentation Exchange Record** ([V20PresExRecord](https://github.com/hyperledger/aries-cloudagent-python/blob/main/aries_cloudagent/protocols/present_proof/v2_0/models/pres_exchange.py))
[Aries RFC 0454 Present Proof Protocol 2.0](https://github.com/hyperledger/aries-rfcs/tree/main/features/0454-present-proof-v2)
```json
{
"updated_at": "2022-10-18T12:19:30.040123Z",
"pres_ex_id": "12ae5042-38b5-41c7-8b5c-9fcaef25bb65",
"connection_id": "991c4caa-45e2-4caf-8c7e-4fd6786522f4",
"thread_id": "f2b497bc-b2b0-463a-86a9-d832df3adca9",
"trace": false,
"state": "request-received",
"initiator": "external",
"pres_request": {
"@type": "https://didcomm.org/present-proof/2.0/request-presentation",
"@id": "f2b497bc-b2b0-463a-86a9-d832df3adca9",
"formats": [
{
"attach_id": "auth_request",
"format": "dif/presentation-exchange/definitions@v1.0" // use DIF format
}
],
"comment": "auto-created pres request from auth request",
"will_confirm": false,
"request_presentations~attach": [
{
"@id": "auth_request",
"mime-type": "application/json",
"data": {
"json": {
"options": {
"challenge": "9391b6c3-e77d-4fec-a4d0-8bb1af85139b", // nonce goes here
"domain": "https://client.example.org/post" // client_id
},
"presentation_definition": {...}
}
}
}
]
},
"by_format": {...},
"role": "prover",
"created_at": "2022-10-18T12:19:30.040123Z",
"auto_verify": false,
"oid4vp_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6" // additional parameter
}
```
**OID4VP Record**
```json
{
"oid4vp_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"connection_id": "991c4caa-45e2-4caf-8c7e-4fd6786522f4",
"client_id": "https://client.example.org/post",
"redirect_uri": "https://client.example.org/post",
"request_uri": "https://client.example.org/567545564",
"response_type": "vp_token",
"response_mode": "post",
"nonce": "9391b6c3-e77d-4fec-a4d0-8bb1af85139b",
"presentation_definition_uri": null,
"pres_ex_id": "12ae5042-38b5-41c7-8b5c-9fcaef25bb65",
"state": "request-received" // [initial, request-received, done]
}
```
:::info
:bulb: **Note**
`presentation_definition` objects are not stored in the oid4vp record as they are included in the presentation exchange record anyway.
:::
**Presentation Submission**
```json
{
"id": "cf54ec54-cf04-404d-b1dc-bbe8b6afcd92",
"definition_id": "6728ee4f-ba17-4a02-8989-ed48eb51d73f",
"descriptor_map": [
{
"id": "citizenship",
"format": "ldp_vp",
"path": "$",
"path_nested": {
"id": "citizenship",
"format": "ldp_vc",
"path": "$.verifiableCredential[0]"
}
}
]
}
```
## Note D
**POST presentation**
```
POST /post HTTP/1.1
Host: client.example.org
Content-Type: application/x-www-form-urlencoded
presentation_submission=...&
vp_token=...
```
## References
- https://developer.android.com/training/app-links/
- https://developer.apple.com/ios/universal-links
- https://github.com/hyperledger/aries-rfcs/tree/main/features/0434-outofband
- https://openid.net/specs/openid-connect-core-1_0.html#RequestUriParameter
- https://openid.net/specs/openid-connect-core-1_0.html#RequestObject
- https://openid.net/specs/openid-4-verifiable-presentations-1_0.html
- https://openid.net/specs/openid-connect-self-issued-v2-1_0.html
- https://www.w3.org/TR/did-core/#services
- https://www.w3.org/TR/did-spec-registries/#service-types