mirror of
https://github.com/mosip/inji-wallet.git
synced 2026-01-09 13:38:01 -05:00
[INJIMOB-3494] add credential-offer and sd-jwt design docs (#2052)
Signed-off-by: Abhishek Paul <paul.apaul.abhishek.ap@gmail.com>
This commit is contained in:
292
docs/credential-offer-support.md
Normal file
292
docs/credential-offer-support.md
Normal file
@@ -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<br/>(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<br/>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<br/>(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<br/>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": "<base-64-url-encoded-cbor-data>"
|
||||
}
|
||||
```
|
||||
214
docs/ietf-sd-jwt-vc-support.md
Normal file
214
docs/ietf-sd-jwt-vc-support.md
Normal file
@@ -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.
|
||||
Reference in New Issue
Block a user