# Wallet - Credential Issuance # Sequence Diagram :warning: **WIP. NOT COMPLETE** ```mermaid sequenceDiagram autonumber participant WP as Web Page actor A as Alice participant BG as Wallet participant UI as Wallet UI WP->>WP: Render "Apply for X" button/link A->>WP: Click button WP->>BG: web5.credentials.apply(manifest_link) BG->>UI: { cmd: CRED_APP, data: manifest_link } UI->>UI: fetch CM using manifest_link UI->>UI: process CM ``` # Rendering a Credential Application Form ![example-vc-app-form](https://i.imgur.com/RFJIxmg.png) :warning: **NOTE: This section is incomplete** :warning: **TODO**: Get answers to [these questions](https://hackmd.io/EBTNW-42Q_2bjSldeFvzEA?view#Credential-Manifest) in order to finish this section ## Context No one has verifiable credentials yet so we're dealing with a cold start. This means that we'll need to support the ability to present a user with a form that they fill out in order to apply for a credential. The user provided-input will be used to generate a self-issued verifiable credential. This verifiable credential is then added to a [Credential Application](https://identity.foundation/credential-manifest/#credential-application) (in addition to the other required fields like `presentation_submission`) and shipped off to the issuer. ## Required Steps - Use`presentation_definition.input_descriptors[*].fields` to render a form that is presented to the user to fill out - _User fills out form and hits submit_ - Use user-provided input to generate a self-issued verifiable credential by following these steps: - Create an empty object, VC - Populate it with any static VC fields (e.g. `@context`) - Use the user's selected DID to populate `issuer` and `credentialSubject.id` - Use `$.presentation_definition.input_descriptors[*].fields[*].path` to place user-provided input into the expected locations within the VC - Make the VC verifiable by constructing a `vc-jwt` - include appropriate `kid` in JWT header - set appropriate `alg` in JWT header based on the key being used to sign - set `sub` and `iss` to the user's selected DID - Sign the JWT using the key associated to the user's selected DID identified by the `kid` set in the JWT header - Construct a [Credential Application](https://identity.foundation/credential-manifest/#credential-application) object - set `spec_version` to `https://identity.foundation/credential-manifest/spec/v1.0.0/` - set `id` to some rando uuid - set `manifest_id` to the id of the credential manifest used to render the form - set `format` to an acceptable format - :warning: highly considering limiting `format` to just `vc-jwt` / `EdDSA` for steel thread - create `presentation_submission` object - set `id` to some rando uuid - set `definition_id` to the id of the appropriate `presentation_definition` object used to render the form - create `descriptor_map` object - set `id` to id of the appropriate `input_descriptor`object used to render the form - set `path` to `$.verifiableCredential[0]` - :warning: **NOTE**: hardcoding to `$.verifiableCredential[0]` because i'm limiting scope to a single credential for the steel thread. supporting additional credentials will be a stretch goal that i won't hit - create a `verifiableCredential` array - add JWT'ified VC - Ship Credential Application to Issuer # Credential Manifest Example KYC Example ```json= { "id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d", "spec_version": "https://identity.foundation/credential-manifest/spec/v1.0.0/", "output_descriptors": [ { "id": "kyc_credential", "schema": "https://compliance-is-kewl.com/json-schemas/kyc.json" } ], "presentation_definition": { "id": "32f54163-7166-48f1-93d8-ff217bdb0653", "name": "KYC Requirements", "purpose": "TBD. i donno rn", "format": { "jwt": { "alg": [ "EdDSA" ] } }, "input_descriptors": [ { "id": "kyc1", "name": "Personal Info", "constraints": { "subject_is_issuer": "required" "fields": [ { "id": "kycSchema", "path": [ "$.vc.credentialSchema.id" ], "filter": { "type": "string", "const": "https://compliance-is-kewl.com/json-schemas/kyc.json" } }, { "name": "First Name" "id": "givenName", "path": [ "$.vc.credentialSubject.givenName" ], "filter": { "type": "string", "pattern": "[a-zA-Z \\-\\.].+" } }, { "id": "additionalName", "path": [ "$.vc.credentialSubject.additionalName" ], "filter": { "type": "string", "pattern": "[a-zA-Z \\-\\.].+" } }, { "id": "familyName", "path": [ "$.vc.credentialSubject.familyName" ], "filter": { "type": "string", "pattern": "[a-zA-Z \\-\\.].+" } }, { "id": "birthDate", "path": [ "$.vc.credentialSubject.birthDate" ], "filter": { "type": "string", "format": "date" } }, { "id": "postalAddress", "path": [ "$.vc.credentialSubject.postalAddress" ], "filter": { "type": "string" } }, { "id": "taxID", "path": [ "$.vc.credentialSubject.taxID" ], "filter": { "type": "string" } } ] } } ] } } ``` # Credential Application Example ```json= { "id": "c0c6e312-ad44-4f18-935e-a6efaad91612", "spec_version": "https://identity.foundation/credential-manifest/spec/v1.0.0/", "manifest_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d", "format": { "jwt_vc": { "alg": [ "EdDSA" ] } }, "presentation_submission": { "id": "00239c16-3e64-4438-8dda-641e963fa853", "definition_id": "32f54163-7166-48f1-93d8-ff217bdb0653", "descriptor_map": [ { "id": "kyc1", "format": "vc-jwt", "path": "$.verifiableCredential[0]" } ] }, "verifiableCredential": [ "eyJraWQiOiJkaWQ6amFua3k6YWxpY2UjZGlkOmphbmt5OmFsaWNlIiwiYWxnIjoiRWREU0EifQ.eyJpc3MiOiJkaWQ6amFua3k6YWxpY2UiLCJzdWIiOiJkaWQ6amFua3k6YWxpY2UiLCJ2YyI6eyJAY29udGV4dCI6WyJodHRwczpcL1wvd3d3LnczLm9yZ1wvMjAxOFwvY3JlZGVudGlhbHNcL3YxIl0sInR5cGUiOlsiS3ljQ3JlZGVudGlhbCJdLCJpc3N1ZXIiOiJkaWQ6amFua3k6YWxpY2UiLCJpc3N1YW5jZURhdGUiOiIyMDIyLTA5LTI5VDAwOjAwOjAwWiIsImNyZWRlbnRpYWxTY2hlbWEiOnsiaWQiOiJodHRwczpcL1wvY29tcGxpYW5jZS1pcy1rZXdsLmNvbVwvanNvbi1zY2hlbWFzXC9reWMuanNvbiIsInR5cGUiOiJKc29uU2NoZW1hVmFsaWRhdG9yMjAxOCJ9LCJjcmVkZW50aWFsU3ViamVjdCI6eyJpZCI6ImRpZDpqYW5reTphbGljZSIsImdpdmVuTmFtZSI6IlJhbmR5IiwiYWRkaXRpb25hbE5hbWUiOiJOXC9BIiwiZmFtaWx5TmFtZSI6Ik1jSmFua3kiLCJiaXJ0aERhdGUiOiIxOTg4LTAzLTI4IiwicG9zdGFsQWRkcmVzcyI6eyJhZGRyZXNzQ291bnRyeSI6IlVTQSIsImFkZHJlc3NMb2NhbGl0eSI6IkF1c3RpbiIsImFkZHJlc3NSZWdpb24iOiJUWCIsInBvc3RhbENvZGUiOiI3ODcyNCIsInN0cmVldEFkZHJlc3MiOiIxMjMgSmFua3RvcGlhIEF2ZS4ifSwidGF4SUQiOiIxMjMtNDUtNjc4OSJ9fX0.OIga_ix7x4Tk4fEThfu_akXCVuI0aZ770CSSztSJ1NkBiGm4V_NOSQRk0EOo3heh6F6LiK9g9sa_527rNH_wCw" ] } ``` ## Decoded Verifiable Credential the VC in the example above (1st element of the `verifiableCredential`) property is a JWT (specifically `vc-jwt`). Head over to [jwt.io](https://jwt.io/) and copy paste the long ugly string. the output should match the JSON object below ```json= { "vc": { "@context": ["https://www.w3.org/2018/credentials/v1"], "type": ["KycCredential"], "issuer": "did:janky:alice", "issuanceDate": "2022-09-29T00:00:00Z", "credentialSchema": { "id": "https://compliance-is-kewl.com/json-schemas/kyc.json", "type": "JsonSchemaValidator2018" }, "credentialSubject": { "id": "did:janky:alice", "givenName": "Randy", "additionalName": "N/A", "familyName": "McJanky", "birthDate": "1988-03-28", "postalAddress": { "addressCountry": "USA", "addressLocality": "Austin", "addressRegion": "TX", "postalCode": "78724", "streetAddress": "7405 Janktopia Ave." }, "taxID": "123-45-6789" } }, "iss": "did:janky:alice", "sub": "did:janky:alice" } ``` # Questions ## Credential Manifest is [`is_holder`](https://identity.foundation/presentation-exchange/#relational-constraint-feature) required in `constraints` if we have to generate a credential? - na bruvv. not needed --- is [`same_subject`](https://identity.foundation/presentation-exchange/#relational-constraint-feature) required in `constraints` if we have to generate a credential? - na bruvv. not needed --- does `$.presentation_definition[*].input_descriptors[*].filter` support `type: object`? For example, how do I target `postalAddress.addressLocality` in the example below? ```json= { "vc": { "@context": ["https://www.w3.org/2018/credentials/v1"], "type": ["KycCredential"], "issuer": "did:janky:alice", "issuanceDate": "2022-09-29T00:00:00Z", "credentialSchema": { "id": "https://compliance-is-kewl.com/json-schemas/kyc.json", "type": "JsonSchemaValidator2018" }, "credentialSubject": { "id": "did:janky:alice", "givenName": "Randy", "additionalName": "N/A", "familyName": "McJanky", "birthDate": "1988-03-28", "postalAddress": { "addressCountry": "USA", "addressLocality": "Austin", "addressRegion": "TX", "postalCode": "78724", "streetAddress": "7405 Janktopia Ave." }, "taxID": "123-45-6789" } }, "iss": "did:janky:alice", "sub": "did:janky:alice" } ``` can `filter` be like... ```json= { "type": "object", "properties": { "addressCountry": { "type": "string" }, "addressLocality": { "type": "string" }, "addressRegion": { "type": "string" }, "postalCode": { "type": "string" }, "streetAddress": { "type": "string" } }, "required": [ "addressCountry", "addressLocality", "addressRegion", "postalCode", "streetAddress" ] } ``` --- Is there any way other than using `submission_requirements` to support an optional field? e.g. `middleName`. Include it if you have it. It'd be really annoying if optional fields aren't supported in a way aside from using `submission_requirements` wherein two `input_descriptor` objects are provided for the same group and only 1 must be satisfied. 1 `input_descriptor` would include the optional field in its `fields` array and one would exclude it.. thus creating support for optional fields (albeit in the worst way possible) --- # Notes - [`subject_is_issuer`](https://identity.foundation/presentation-exchange/#note-2)