From 0a7c9e3477d1995a1a58bc04e72970f6bcbad723 Mon Sep 17 00:00:00 2001 From: abhip2565 Date: Wed, 13 Aug 2025 12:56:39 +0530 Subject: [PATCH] [INJIMOB-3494] add credential-offer and sd-jwt design docs (#2052) Signed-off-by: Abhishek Paul --- docs/credential-offer-support.md | 292 +++++++++++++++++++++++++++++++ docs/ietf-sd-jwt-vc-support.md | 214 ++++++++++++++++++++++ 2 files changed, 506 insertions(+) create mode 100644 docs/credential-offer-support.md create mode 100644 docs/ietf-sd-jwt-vc-support.md diff --git a/docs/credential-offer-support.md b/docs/credential-offer-support.md new file mode 100644 index 00000000..93b1ceed --- /dev/null +++ b/docs/credential-offer-support.md @@ -0,0 +1,292 @@ +## Support of credential offer + +This document provides a comprehensive overview of downloading the credential issued from Issuing Authority through credential offer. + +### Authorization Support +1. Authorization Code Flow +2. Pre-Authorized Code Flow + +### Out of scope +1. Batch credential download + +### Actors involved +1. Inji Wallet +2. _inji-vci-client_ (Library for downloading credential) +3. Issuing authority + + +### Sequence diagram - download credential issued through credential offer for pre-authorized code flow and authorization code flow + +```mermaid +sequenceDiagram + participant U as User + participant W as Inji Wallet (Mobile App) + participant VCI as VCI Client Library + participant Certify as Issuing Authority + participant AS as Authorization Server + + Note over Certify: Generate QR code to issue credential + W->>Certify: 1. Scan QR code + W->>VCI: 2. Pass scanned credential offer info + Note over VCI: Process credential offer by uri or object + VCI->>Certify: 3. Fetch Issuer metadata
(GET /.well-known/openid-credential-issuer) + Certify-->>VCI: 4. Receive Issuer metadata + Note over VCI: Issuer Metadata is temporarily cached + Note over VCI: Identify the flow type based on the credential offer + Certify->>Certify: 5. Identify the flow type based on the credential offer + alt 5.1 If pre-authorized code flow + VCI->>VCI: 5.1.1 Auth server discovery + alt Requires tx_code + VCI-->>W: 5.1.2 Request for tx_code + U->>W: 5.1.3 User provides tx_code + W->>VCI: 5.1.4 Return tx_code + Note over VCI: Create token request with tx_code + else No tx_code + Note over VCI: Create token request without tx_code + end + else 5.2 If authorization code flow + VCI->>VCI: 5.2.1 Auth server discovery + Note over VCI: create authorization url + VCI-->>W: 5.2.2 Request authorization code + W->>AS: 5.2.3 Redirect to Authorization Server + U->>AS: 5.2.4 User authentication and authorization + AS-->>W: 5.2.5 Redirect back to Wallet with authorization code + W->>VCI: 5.2.5 Return authorization code + Note over VCI: Create token request + end + VCI-->>W: 6. Request for access token
getTokenResponse(tokenRequest) + W->>AS: 7. Request access token + AS-->>W: 8. Return access token with cNonce + W->>VCI: 9. Return access token with cNonce + Note over VCI: Construct the request body for credential request + VCI->>Certify: 10. Credential Request + Certify-->>VCI: 11. Return credential response + VCI-->>W: 12. Return credential response +``` + + +### Steps involved + +**Prerequisite -** Generate QR code to issue credential + +#### 1. Scan QR code + +Wallet scans QR code generated by issuer + +```` +{ + "credential_issuer": "https://example.com/issuer", + "credential_configuration_ids": [ + "credential-config-id" + ], + "grants": { + "urn:ietf:params:oauth:grant-type:pre-authorized_code": { + "pre-authorized_code": "412350404962811318869516", + "authorization_server": "https://example.com/authserver" + } + } +} +```` +#### 2. Pass scanned credential offer info + +After scanning the QR code, pass credential offer info _inji-vci-client_. + +```` +VCIClient.requestCredentialByCredentialOffer( + credentialOffer, + clientMetadata, + getTxCode, + authorizeUser: () -> authcode, + getTokenResponse: () -> tokenResponse, + getProofJwt: () -> proof, + onCheckIssuerTrust: () -> boolean, +) + +Note: +- credentialOffer is credential offer data or uri received from issuer. +- clientMetadata, If it is authorization code flow for client authentication - client-id and redirect-uri +- getTxCode is a callback function to get the tx_code from the user if required. +- authorizeUser is a callback function to authorize the user for the credential request and return authorization code. +- getTokenResponse is a callback function to get the token response from the authorization server. +- getProofJwt is a callback function to create the proof JWT for the credential request. +- onCheckIssuerTrust is a callback function to check if the issuer is trusted or not. + +```` +#### 3. Fetch Issuer metadata
(GET /.well-known/openid-credential-issuer) +The _inji-vci-client_ fetches the Issuer metadata from the issuing authority to understand the capabilities and requirements for credential issuance. + +```` +GET credentialIssuer/.well-known/openid-credential-issuer +```` + +#### 4. Receive Issuer metadata +inji-vci-client receives Issuer's metadata response. + +``` +{ + "credential_issuer": "https://example.com/issuer", + "credential_endpoint": "https://example.com/issuer/credential", + "credential_configurations_supported": { + "credential-config-id": { + "format": "ldp_vc", + "scope": "vc_scope", + "credential_definition": { + "credentialSubject": { + "cliam1": { + "display": [ + { + "name": "Claim 1", + "locale": "en" + } + ] + }, + "claim2": { + "display": [ + { + "name": "Claim 1", + "locale": "en" + } + ] + } + } + } + } + } +} +``` + +#### 5. Identify the flow type based on the credential offer + +##### 5.1 pre-authorized code flow +If credential offer is created with pre-authorized code + +###### 5.1.1 Auth server discovery +The _inji-vci-client_ performs an authorization server discovery to determine the authorization server's endpoint. + +``` +GET authserver/.well-known/oauth-authorization-server + +{ + "issuer": "https://example.com/issuer", + "authorization_endpoint": "https://example.com/authserver/authorize", + "token_endpoint": "https://example.com/authserver/token", + "grant_types_supported": [ + "authorization_code" + ], + "response_types_supported": [ + "code" + ] +} +``` + +###### 5.1.2 Request for tx_code if required +_inji-vci-client_ requests a transaction code (tx_code) from the Wallet through getTxCode callback. + + +###### 5.1.3 User provides tx_code +Wallet prompts screen to accept transaction code. User enters the tx_code received from the issuing authority. + +``` +{ + "tx_code": "412350404962811318869516" +} +``` + +###### 5.1.4 Return tx_code +Wallet returns the tx_code to the _inji-vci-client_. After receiving tx_code, _inji-vci-client_ creates token request + +##### 5.2 authorization code flow +If credential offer is created with authorization code flow + +###### 5.2.1 Auth server discovery +The _inji-vci-client_ performs an authorization server discovery to determine the authorization server's endpoint. + +``` +GET authserver/.well-known/oauth-authorization-server + +{ + "issuer": "https://example.com/issuer", + "authorization_endpoint": "https://example.com/authserver/authorize", + "token_endpoint": "https://example.com/authserver/token", + "grant_types_supported": [ + "authorization_code" + ], + "response_types_supported": [ + "code" + ] +} +``` + +###### 5.2.2 Request authorization code +The _inji-vci-client_ creates an authorization URL and requests the Wallet to redirect the user to the authorization server. + +```` +{ + "response_type": "code", + "client_id": "your-client-id", + "redirect_uri": "https://your-redirect-uri.com", + "scope": "openid vc_scope", + "state": "random_state_value" + "code_verifier": "random string" + "code-challenge": "random string" +} +```` + +###### 5.2.3 Redirect to Authorization Server +The Wallet redirects the user to the authorization server with the authorization URL. + +###### 5.2.4 User authentication and authorization +The user provide details for authenticates & authorization + +###### 5.2.5 Redirect back to Wallet with authorization code +User is redirected back to the Wallet with the authorization code. + +``` +{ + "code": "authorization_code_value" +} +``` + +#### 6. Request for access token
getTokenResponse(tokenRequest) +The _inji-vci-client_ requests an access token from the authorization server through Wallet by using getTokenResponse callback + +#### 7. Request access token +The Wallet sends a request to the authorization server to obtain an access token. + +#### 8. Return access token with cNonce +The authorization server returns the access token along with a cNonce (client nonce) to the Wallet. + +``` +{ + "access_token": "access_token_value", + "c_nonce": "c_nonce_value" +} +``` + +#### 9. Return access token with cNonce +The wallet returns the access token along with a cNonce (client nonce) to the _inji-vci-client_. + +#### 10. Credential Request +The _inji-vci-client_ constructs the request body for the credential request using the access token and cNonce. +It then sends the credential request to the issuing authority. + +Request is constructed based on credential format - ldp_vc, mso_mdoc. + +#### 11. Return credential response +The issuing authority processes the credential request and returns the credential response to the _inji-vci-client_. +Credential response is json if credential format is ldp_vc, and it's base64 url encoded CBOR data if credential format is mso_mdoc. + +``` +{ + "credential": "....." +} +``` + +#### 12. Return credential response +The _inji-vci-client_ returns the credential response to the Wallet. + +``` +{ + "credential": "" +} +``` \ No newline at end of file diff --git a/docs/ietf-sd-jwt-vc-support.md b/docs/ietf-sd-jwt-vc-support.md new file mode 100644 index 00000000..3e6d64f5 --- /dev/null +++ b/docs/ietf-sd-jwt-vc-support.md @@ -0,0 +1,214 @@ +## Support of credential format vc+sd-jwt/dc+sd-jwt in Inji Wallet + +This document provides a comprehensive overview of the process for downloading and rendering an IETF SD-JWT VC, adhering to the OpenID4VCI specification. + +### Scope +- SD-JWT VC download, verification, and rendering in Inji Wallet. +- vc+sd-jwt/dc+sd-jwt credential format for SD-JWT. All non-normative examples are referred for `vc+sd-jwt` format. +- Cryptographic Key Binding - JWK is being used for cryptographic key binding in SD-JWT VC. + + +### Actors involved +1. Inji Wallet +2. Issuing authority +3. _inji-vci-client_ (Library for downloading credential) +4. _vc-verifier_ (library for verification of downloaded VC) + +### Sequence diagram - download & view vc+sd-jwt credential format VC for Wallet Initiated Flow + +```mermaid +sequenceDiagram + participant W as Inji Wallet (Mobile App) + participant VCI_Lib as Inji VCI Client (Library) + participant Issuer as Issuing Authority + participant VCVerifier as VC Verifier (Library) + + W ->> VCI_Lib: 1. Get Issuer Metadata for given credential issuer + VCI_Lib ->> Issuer: 2. Fetch Issuer Metadata (GET /.well-known/openid-credential-issuer) + Issuer -->> VCI_Lib: 3. Return Issuer well-known metadata + Note over VCI_Lib: Issuer Metadata is temporarily cached + VCI_Lib -->> W: 4. Return Issuer well-known metadata + Note over W: Cache the Issuer Metadata for future use + Note over W: User selects one of the supported credentials + W ->> VCI_Lib: 5. Request Credential from Issuer + VCI_Lib -->> W: 6. Authorize user for credential request and get authorization code and access token + W ->> VCI_Lib: 7. Provide authorization code and access token + Note over VCI_Lib: Construct the request body for credential request + VCI_Lib ->> Issuer: 8. Credential Request + Issuer -->> VCI_Lib: 9. Return vc+sd-jwt format specific Credential response + VCI_Lib -->> W: 10. Return vc+sd-jwt Credential + W ->> VCVerifier: 11. Verify sd-jwt Credential + VCVerifier -->> W: 12. Return Verification Result + Note over W: If verification is successful, proceed to save the credential + Note over W: Use cached Issuer Metadata for rendering + + +``` + +#### Steps involved +##### 1. Get Issuer Metadata + +Establish communication with the _inji-vci-client_ +Fetch Issuer Metadata + +```` +VCIClient.getIssuerMetadata(credentialIssuer) + +Note: credentialIssuer is Credential Issuer Uri received from trusted issuers list. +```` + +##### 2. Fetch Issuer Metadata +The _inji-vci-client_ fetch issuer's metadata from issuing authority. + +```` +GET credentialIssuer/.well-known/openid-credential-issuer +```` + + +##### 3. Receive Issuer Metadata Response +_inji-vci-client_ receives Issuer's metadata response. + +```` +{ + "credential_issuer": "https://example.com/issuer", + "credential_endpoint": "https://example.com/issuer/credential", + "credential_configurations_supported": + { + "SD_JWT_VC_example_in_OpenID4VCI": { + "format": "vc+sd-jwt", + "scope": "vc_scope", + "claims": { + "cliam1": { + "display": [ + { + "name": "Claim 1", + "locale": "en" + } + ] + }, + "claim2": { + "display": [ + { + "name": "Claim 1", + "locale": "en" + } + ] + } + }, + "vct": "SD_JWT_VC_example_in_OpenID4VCI", + } + } +} +```` + +##### 4. Return Issuer Metadata Response +Once the response is received in _inji-vci-client_, it is returned to the Wallet. + +##### 5. Request Credential from Issuer + +```` +VCIClient.requestCredentialFromTrustedIssuer( + credentialIssuer, + credentialConfigurationId, + clientMetadata, + authorizeUser: () -> authcode, + getTokenResponse: () -> tokenResponse, + getProofJwt: () -> proof +) + +Note: +- credentialIssuer is Credential Issuer Uri received from trusted issuers list. +- credentialConfigurationId is one of the supported credential configuration id user has selected. +- clientMetadata for client authentication - client-id and redirect-uri +- authorizeUser is a callback function to authorize the user for the credential request and return authorization code. +- getTokenResponse is a callback function to get the token response from the authorization server. +- getProofJwt is a callback function to create the proof JWT for the credential request. +```` + + +##### 6. Authorize user for credential request and get authorization code and access token +_inji-vci-client_ uses `authorizeUser` callback function to authorize the user for the credential request. +This typically involves redirecting the user to an authorization server where they can log in and grant permission +for the credential request. +Once authorization code is received, _inji-vci-client_ uses `getTokenResponse` callback function to exchange the +authorization code for an access token. +For more details check [VCI Client Library](https://github.com/mosip/inji-vci-client/blob/master/kotlin/README.md) + +##### 7. Provide authorization code and access token +When the user has successfully authorized the request, the _inji-vci-client_ will receive an authorization code and access token. + + +##### 8. Create Credential Request and send to Issuing Authority +_inji-vci-client_ will use `CredentialRequestFactory` and create `SdJwtCredentialRequest` request with following body: + +```` +{ + "format": "vc+sd-jwt", + "vct": "SD_JWT_VC_example_in_OpenID4VCI" + "proof": { + "proof_type": "jwt", + "jwt": "eyJraWQiOiJkaWQ6ZXhhbXBsZ...KPxgihac0aW9EkL1nOzM" + } +} + +```` +and send it to the issuing authority. + +##### 9. Receive the Credential Response +The _inji-vci-client_ receives the credential response as jwt string + +``` +"eyJraWQiOiJkaWQ6ZXhhbXBsZ.eyJpc3N1YW5jZURhdGUiOiIyM.KPxgihac0aW9EkL1nOzM~disclousure1~disclousure1~" +``` + +##### 10. Return the Credential Response +Once the response is received in _inji-vci-client_, it is returned to the Wallet. + +```` +{ + "credential": "eyJraWQiOiJkaWQ6ZXhhbXBsZ.eyJpc3N1YW5jZURhdGUiOiIyM.KPxgihac0aW9EkL1nOzM~disclousure1~disclousure1~", + "credentialIssuer": "https://example.com/issuer", + "credentialConfigurationId": "SD_JWT_VC_example_in_OpenID4VCI" +} +```` + +##### 11. Perform vc verification +After obtaining the credential from the issuing authority through the _inji-vci-client_ library, a verification process ensures that the issued Verifiable Credential (VC) remains unaltered through _vc-verifier_ library. + +_vc-verifier_ will use `CredentialVerifierFactory` and create `SdJwtVerifiableCredential` to perform validation and verification of the credential. + +1. [x] Confirm the credential is not tampered. (Cryptographic Signature Verification) +2. [x] Disclosure Verification to confirm sd claims are not tampered. (Cryptographic Hash Verification) + +```` +VCVerifier.verify( + credential: "eyJraWQiOiJkaWQ6ZXhhbXBsZ.eyJpc3N1YW5jZURhdGUiOiIyM.KPxgihac0aW9EkL1nOzM~disclousure1~disclousure1~", + credentialFormat: "vc+sd-jwt" +) +```` + +##### 12. Return VC verification Result +After verifying the VC, return verification result + +```` +{ + "verificationStatus": true, + "verificationMessage": "", + "verificationErrorCode": null +} + +```` + +- ##### VC Rendering: + - Field Labels: + The labels displayed for each field are derived from the Credential Issuer's metadata claims under the display attribute. + Reference: OpenID4VCI Spec - Credential Issuer Metadata. + - Field Ordering: + - As per OpenID4VCI Draft 13, the order property in the issuer’s well-known configuration defines the order of fields to be displayed. + +This structured approach ensures that the credential is rendered accurately and efficiently while maintaining a lightweight storage and transmission footprint. + + +### Out of scope +- Revocation - Inji Wallet doesn't support revocation for any credential format. So this document does not cover revocation of IETF SD-JWT VC. +- SVG Rendering - Inji Wallet does not support SVG rendering for any credential format. So this document does not cover SVG rendering of IETF SD-JWT VC.