8000 [OID4VCI] Documentation for integration with Lissi wallet by mposolda · Pull Request #51689 · keycloak/keycloak · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ image::images/oid4vci/screenshot-realm-verifiable-credentials.png[Enabling Verif

This enables the OID4VCI functionality for the realm. Once enabled, the **OID4VC Issuer Metadata** link appears in the *Endpoints* section of the General tab, and an **OID4VCI Attributes** section appears in the *Tokens* tab.

[[_oid4vci_key_management]]
==== Key Management Configuration

Credentials are signed with a realm signing key. For SD-JWT VCs, the selected key must also provide an X.509 certificate chain that satisfies the https://openid.net/specs/openid4vc-high-assurance-interoperability-profile-1_0-final.html#section-6.1.1[HAIP issuer key resolution requirements]:
Expand Down Expand Up @@ -316,6 +317,7 @@ How normalization is applied during issuance:
* For JWT-VC, the credential `issuanceDate` is normalized at issuance; the JWT `nbf` is derived from the normalized value. If a mapper sets a VC `expirationDate`, it is normalized and emitted as JWT `exp`.
* For SD-JWT VCs, time-related claims (`iat`, `nbf`, `exp`) are typically set using protocol mappers such as the Issued At Time Claim Mapper. Values are automatically normalized according to the realm strategy.

[[_oid4vci_user_setup]]
=== Creating a User Account

A test user is required to simulate credential issuance and verify the setup.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
[[_oid4vci_valera_wallet_integration]]
=== Testing with Valera Wallet
=== Testing with third-party wallets

This section describes how to setup {project_name} for the integration with some third-party wallets.

[NOTE]
====
This section describes a manual interoperability test with Valera Wallet. It is not an automated compatibility test, and this integration is not officially supported. Wallet behavior can change between wallet versions, and results should be verified again when upgrading either the wallet or {project_name}.
This section describes a manual interoperability test with third-party wallets. It is not an automated compatibility test, and this integration is not officially supported. Third-party wallet behavior can change between wallet versions, and results should be verified again when upgrading either the wallet or {project_name}.
====

[[_oid4vci_valera_wallet_integration]]
==== Testing with Valera Wallet

Valera Wallet by A-SIT Plus is a demo wallet that can be used to test OpenID4VCI credential issuance. The test below was performed with a locally running {project_name} server exposed to the mobile wallet through an HTTPS tunnel. A production deployment is not required for this manual test, but the wallet must be able to reach the issuer through an HTTPS URL.

==== Tested Environment
===== Tested Environment

[cols="1,2", options="header"]
|===
Expand All @@ -34,7 +38,8 @@ Valera Wallet by A-SIT Plus is a demo wallet that can be used to test OpenID4VCI
| Both flows completed successfully and returned the issued credential to the wallet
|===

==== Exposing Local {project_name} to the Wallet
[[_oid4vci_valera_wallet_server_setup]]
===== Exposing Local {project_name} to the Wallet

For local testing, {project_name} can run on the development machine as described in the previous OID4VCI setup sections. Because the wallet runs on a phone and needs an HTTPS issuer URL, expose the local {project_name} endpoint through an HTTPS tunnel, for example with `ngrok` or a similar tool.

Expand All @@ -52,7 +57,8 @@ Use the public HTTPS tunnel hostname consistently for the credential offer and t
The HTTPS tunnel is used to make the local issuer reachable by the real mobile wallet. This setup is intended for manual interoperability testing. For a production issuer, follow the normal {project_name} production deployment guidance.
====

==== Configure the Valera Wallet Client
[[_oid4vci_valera_wallet_client_setup]]
===== Configure the Valera Wallet Client

Valera uses a fixed OAuth 2.0 client identifier and application callback URI. Create a public OpenID Connect client for the wallet before generating credential offers for it.

Expand Down Expand Up @@ -122,7 +128,13 @@ If you create the client through the Admin REST API, the representation should c
The credential offer must target the same client id that the wallet uses during the OAuth flow. If the wallet sends a pushed authorization request with a client id that is not registered in the realm, {project_name} rejects the request with `client_not_found`.
====

==== Create a Credential Offer for Valera Wallet
===== Create a Credential Offer for Valera Wallet

[NOTE]
====
Instead of REST credential-offer, it is recommended to use AIA for creating credential offer. That is easier and does not need feature `oid4vc-vci-rest-credential-offer` to be enabled.
Follow <<_oid4vci_lissi_wallet_authz_code_flow,Lissi wallet Authorization code section>> or <<_oid4vci_lissi_wallet_preauthz_flow,Lissi wallet Pre-authorized code section>> for the details.
====

The examples in the flow sections below use the REST credential-offer endpoint. The bearer token must be issued to the Valera client for the user who creates the offer. When creating an offer for a different target user, that issuing user must have permission to create credential offers.

Expand Down Expand Up @@ -159,7 +171,7 @@ curl -G "$ISSUER_BASE/protocol/oid4vc/create-credential-offer" \
The JSON response contains an `issuer`, a `nonce`, and a `qr_code` data URL. Display the `qr_code` value as an image for the wallet to scan, or use the returned issuer and nonce with your offer display component to create a deep link.

[[_oid4vci_valera_wallet_claim_credential]]
==== Claim the Credential in Valera Wallet
===== Claim the Credential in Valera Wallet

After {project_name} displays the credential offer as a QR code or deep link, the remaining wallet interaction is the same for both tested flows.

@@ -198,7 +210,7 @@ image::images/oid4vci/valera-cred.webp[Valera Wallet credential list, width=320]
.Valera Wallet credential details
image::images/oid4vci/valera-cred-details.webp[Valera Wallet credential details, width=320]

==== Authorization Code Flow Test
===== Authorization Code Flow Test

Use this flow when the holder should authenticate with {project_name} and approve issuance interactively.

Expand All @@ -224,7 +236,7 @@ The test succeeded with Valera Wallet 5.8.0. The final credential request used t
}
----

==== Pre-Authorized Code Flow Test
===== Pre-Authorized Code Flow Test

Use this flow when the user has already been authenticated by the issuer and the wallet can redeem a pre-authorized credential offer without starting an interactive login flow on the phone.

Expand All @@ -240,7 +252,7 @@ This flow requires the dedicated experimental `oid4vc-vci-preauth-code` feature

The test succeeded with Valera Wallet 5.8.0. Earlier testing with Valera Wallet 5.7.6 failed because the JWT proof issuer claim did not match the client id used for the token request. This was no longer reproducible with the tested 5.8.0 version.

==== Test Result
===== Test Result

[cols="1,1,2", options="header"]
|===
Expand All @@ -257,8 +269,161 @@ The test succeeded with Valera Wallet 5.8.0. Earlier testing with Valera Wallet
| Valera exchanged the pre-authorized code and requested the credential with `credential_identifier` set to `IdentityCredential`.
|===

==== Troubleshooting
[[_oid4vci_valera_troubleshooting]]
===== Troubleshooting

* In case of troubles, it can be good to enable user events as mentioned in the <<auditing-user-events,User events section>> and check the admin console events as well as server.log if there are any interesting details
* If {project_name} logs `client_not_found` during PAR, verify that the Valera client id `+https://wallet.a-sit.at/app+` exists in the realm.
* If {project_name} logs `invalid_redirect_uri`, verify that the Valera callback `asitplus-wallet://wallet.a-sit.plus/app/callback/provisioning` is listed as a valid redirect URI for the Valera client.
* If the final credential request fails with an `invalid_credential_request` about credential identifiers, verify that the wallet requests the credential with the `credential_identifier` returned in the token response `authorization_details`.

[[_oid4vci_lissi_wallet_integration]]
==== Testing with Lissi Wallet

Lissi wallet is another demo wallet that can be used to test OpenID4VCI credential issuance. The test below was performed with a locally running {project_name} server exposed to the mobile wallet through an HTTPS tunnel. A production deployment is not required for this manual test, but the wallet must be able to reach the issuer through an HTTPS URL.

[[_oid4vci_lissi_wallet_tested_environment]]
===== Tested Environment

[cols="1,2", options="header"]
|===
| Component
| Value

| Wallet
| Lissi ID-Wallet

| Wallet version
| 3.1.5 (18743) on Android 17

| Credential configuration
| `IdentityCredential`

| Credential format
| `dc+sd-jwt`

| Flows tested
| Authorization Code Flow and Pre-Authorized Code Flow

| Result
| Both flows completed successfully and returned the issued credential to the wallet
|===

[[_oid4vci_lissi_wallet_server_setup]]
===== Exposing Local {project_name} to the Wallet

For local testing, {project_name} can run on the development machine as described in the previous OID4VCI setup sections. It is assumed that {project_name} is served over HTTPS
and is accessible from the mobile application. Similar setup as described in the <<_oid4vci_valera_wallet_server_setup,Valera wallet server setup>> can be used.

[[_oid4vci_lissi_wallet_client_setup]]
===== Configure the Lissi Wallet Client

The assumption is that in your realm, you create OID4VCI client scope as `IdentityCredential` configured in the same way as described in the <<_oid4vci_valera_wallet_client_setup,Valera wallet client setup>>.
It is recommended that in the **Mappers** tab of this client scope, there are pre-defined protocol mappers added (for basic claims like `username`, `email` etc).
Also it is needed to have ES256 realm key properly set in your realm based on the requirements described in the <<_oid4vci_key_management,Key Management section>>. For troubleshooting,
it is recommended to <<auditing-user-events,Enable user events>>.
Comment thread
mposolda marked this conversation as resolved.
Resolved

Similarly like Valera wallet, the Lissi wallet also uses a fixed OAuth 2.0 client identifier and application callback URI. Due to that, it is needed to create a public OpenID Connect client for the wallet before generating credential offers for it with the options like this.

[cols="1,2", options="header"]
|===
| Setting
| Value

| Client ID
| `9c481dc3-2ad0-4fe0-881d-c32ad02fe0fc`

| Client type
| Public client

| Standard flow
| Enabled

| Direct access grants
| Disabled

| Valid redirect URI
| `+https://oob.lissi.io/vci-cb+`

| OID4VCI
| Enabled in the client Advanced settings

| Credential client scope
| Add the credential client scope, for example `IdentityCredential`, as an optional client scope
|===

The `IdentityCredential` client scope used in this test is configured as an OID4VCI credential scope and assigned to the Lissi client as an optional client scope. For the general client scope setup, see <<_oid4vci_client_scope,Create Client Scopes with Mappers>>.

===== User setup

Create a user (for example, `john`) and set a password. In Admin Console → **Users** → … → **Verifiable credentials**, add
the `IdentityCredential` credential to the user. More about user setup in the <<_oid4vci_user_setup,User setup section above>>.

[[_oid4vci_lissi_wallet_authz_code_flow]]
===== Authorization Code Flow Test

This flow requires {project_name} running with the feature `oid4vc-vci`

. Open URL similar to `+https://<<kc_server>>/realms/<<kc_realm>>/account+` with browser on your laptop

. Fill username/password `john` / password and login to the {project_name} account console

. After login to the account console, go to the tab **Verifiable credentials** and find the **Identity credential**. Credential should be available as long as administrator created the credential for the user as described above.

. Click to **Issue to wallet**. The page with credential offer should be displayed as on the picture below and user can scan the QR code to his Lissi wallet now.
+
.Lissi wallet credential offer
image::images/oid4vci/lissi-credential-offer.png[Lissi wallet credential offer, width=320]

. Install Lissi ID Wallet app on the mobile phone. Tested with the version mentioned <<_oid4vci_lissi_wallet_tested_environment,above>>. Needed to setup PIN and biometrics in the application.

. In the wallet application, click on the right bottom picture (blue circle) on the below screen to scan the QR code with credential offer from above
+
.Lissi wallet welcome screen
image::images/oid4vci/lissi1-welcome.png[Lissi wallet welcome screen, width=320]

. Once scanned, you may need to authenticate user on the mobile phone as this is authorization_code grant and user is supposed to authenticate on target device as well. You also need to confirm in the Lissi wallet application whether to accept the credential as in the screenshot below:
+
.Lissi wallet confirmation screen
image::images/oid4vci/lissi2-adding-credential.png[Lissi wallet confirmation screen, width=320]

. After accepting the credential, the credential should be available in your wallet. You can inspect it then.
+
.Lissi wallet - credential
image::images/oid4vci/lissi3-credential.png[Lissi wallet - credential, width=320]

[[_oid4vci_lissi_wallet_preauthz_flow]]
===== Pre-Authorized Code Flow Test

This flow requires {project_name} running with the features `oid4vc-vci` and `oid4vc-vci-preauth-code`

. Logout from account console on your laptop (from previous step) and make sure that login screen is displayed.
It should display `client_id=account-console` in the browser URL (among many other parameters).

. Add this parameter to the end of the browser URL and refresh the browser URL:
+
```
&kc_action=verifiable_credential_offer:eyJjcmVkZW50aWFsQ29uZmlndXJhdGlvbklkIjoiSWRlbnRpdHlDcmVkZW50aWFsIiwiY2xpZW50SWQiOiI5YzQ4MWRjMy0yYWQwLTRmZTAtODgxZC1jMzJhZDAyZmUwZmMiLCJwcmVBdXRob3JpemVkIjp0cnVlfQ==
```
+
[NOTE]
====
The `kc_action` parameter above is parameterized AIA for displaying credential-offer. Parameter may need to be added manually as {project_name} account console does not yet support pre-authorized credential offers out of the box.
The parameter is base64Url-encoded value of the credential-offer config, which looks like this (decoded from Base64Url and formatted for visibility):
====
+
```
{
"credentialConfigurationId":"IdentityCredential",
"clientId":"9c481dc3-2ad0-4fe0-881d-c32ad02fe0fc",
"preAuthorized":true
}
```

. Additional steps are the same as for <<_oid4vci_lissi_wallet_authz_code_flow,Authorization code flow>>. With the exception, that with the pre-authorized code flow, the mobile
application does not request login from the user as it is assumed that user was "pre-authorized" in some other way - which in this use-case was done in fact by user authentication on the laptop to the {project_name} account console.

[[_oid4vci_lissi_troubleshooting]]
===== Troubleshooting

* Follow the <<_oid4vci_valera_troubleshooting,Valera wallet troubleshooting section>> as some tips might be similar
Loading
0