mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-09 23:12:06 -03:30
fixes #39527 Signed-off-by: Pascal Knüppel <pascal.knueppel@governikus.de> Signed-off-by: Captain-P-Goldfish <captain.p.goldfish@gmx.de>
475 lines
18 KiB
Plaintext
475 lines
18 KiB
Plaintext
[[_oid4vci]]
|
||
== Configuring {project_name} as a Verifiable Credential Issuer
|
||
|
||
[IMPORTANT]
|
||
====
|
||
This is an experimental feature and should not be used in production. Backward compatibility is not guaranteed, and future updates may introduce breaking changes.
|
||
====
|
||
|
||
{project_name} provides experimental support for https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html[OpenID for Verifiable Credential Issuance].
|
||
|
||
=== Introduction
|
||
|
||
This chapter provides step-by-step instructions for configuring {project_name} as a Verifiable Credential Issuer using the OpenID for Verifiable Credential Issuance (OID4VCI) protocol. It outlines the process for setting up a {project_name} instance to securely issue and manage Verifiable Credentials (VCs), supporting decentralized identity solutions.
|
||
|
||
=== What are Verifiable Credentials (VCs)?
|
||
|
||
Verifiable Credentials (VCs) are cryptographically signed, tamper-evident data structures that represent claims about an entity, such as a person, organization, or device. They are foundational to decentralized identity systems, allowing secure and privacy-preserving identity verification without reliance on centralized authorities. VCs support advanced features like selective disclosure and zero-knowledge proofs, enhancing user privacy and security.
|
||
|
||
=== What is OID4VCI?
|
||
|
||
OpenID for Verifiable Credential Issuance (OID4VCI) is an extension of the OpenID Connect (OIDC) protocol. It defines a standardized, interoperable framework for credential issuers to deliver VCs to holders, who can then present them to verifiers. OID4VCI leverages {project_name}'s existing authentication and authorization capabilities to streamline VC issuance.
|
||
|
||
=== Scope of This Chapter
|
||
|
||
This chapter covers the following technical configurations:
|
||
|
||
- Creating a dedicated realm for VC issuance.
|
||
- Setting up a test user for credential testing.
|
||
- Configuring custom cryptographic keys for signing and encrypting VCs.
|
||
- Defining realm attributes to specify VC metadata.
|
||
- Establishing client scopes and mappers to include user attributes in VCs.
|
||
- Registering a client to handle VC requests.
|
||
- Verifying the configuration using the issuer metadata endpoint.
|
||
|
||
=== Prerequisites
|
||
|
||
Ensure the following requirements are met before configuring {project_name} as a Verifiable Credential Issuer:
|
||
|
||
=== {project_name} Instance
|
||
|
||
A running {project_name} server with the OID4VCI feature enabled.
|
||
|
||
To enable the feature, add the following flag to the startup command:
|
||
|
||
[source,bash]
|
||
----
|
||
--features=oid4vc-vci
|
||
----
|
||
|
||
Verify activation by checking the server logs for the `OID4VC_VCI` initialization message.
|
||
|
||
=== Configuring Credential Issuance in Keycloak
|
||
|
||
In {project_name}, Verifiable Credentials are managed through *ClientScopes*, with each ClientScope representing a single Verifiable Credential type. To enable the issuance of a credential, the corresponding ClientScope must be assigned to an OpenID Connect client - ideally as *optional*.
|
||
|
||
During the OAuth2 authorization process, the credential-specific scope can be requested by including the ClientScope's name in the `scope` parameter of the authorization request. Once the user has successfully authenticated, the resulting Access Token *MUST* include the requested ClientScope in its `scope` claim. To ensure this, make sure the ClientScope option *Include in token scope* is enabled.
|
||
|
||
With this Access Token, the Verifiable Credential can be issued at the Credential Endpoint.
|
||
|
||
=== Authentication
|
||
|
||
An access token is required to authenticate API requests.
|
||
|
||
Refer to the following {project_name} documentation sections for detailed steps on:
|
||
|
||
- <<proc-creating-oidc-client_{context},Creating a Client>>
|
||
- <<_oidc-auth-flows-direct, Obtaining an Access Token>>
|
||
|
||
=== Configuration Steps
|
||
|
||
Follow these steps to configure {project_name} as a Verifiable Credential Issuer. Each section is detailed with procedures, explanations, and examples where applicable.
|
||
|
||
=== Creating a Realm
|
||
|
||
A realm in {project_name} is a logical container that manages users, clients, roles, and authentication flows.
|
||
For Verifiable Credential (VC) issuance, create a dedicated realm to ensure isolation and maintain a clear separation of functionality.
|
||
|
||
[NOTE]
|
||
====
|
||
For detailed instructions on creating a realm, refer to the {project_name} documentation:
|
||
<<proc-creating-a-realm_{context},Creating a Realm>>.
|
||
====
|
||
|
||
=== Creating a User Account
|
||
|
||
A test user is required to simulate credential issuance and verify the setup.
|
||
|
||
[NOTE]
|
||
====
|
||
For step-by-step instructions on creating a user, refer to the {project_name} documentation:
|
||
<<assembly-managing-users_{context},Creating a User>>.
|
||
====
|
||
|
||
Ensure that the user has a valid username, email, and password. If the password should not be reset upon first login, disable the "Temporary" toggle during password configuration.
|
||
|
||
=== Key Management Configuration
|
||
|
||
{project_name} uses cryptographic keys for signing and encrypting Verifiable Credentials (VCs). To ensure secure and standards-compliant issuance, configure **ECDSA (ES256) for signing**, **RSA (RS256) for signing**, and **RSA-OAEP for encryption** using a keystore.
|
||
|
||
[NOTE]
|
||
====
|
||
For a detailed guide on configuring realm keys, refer to the {project_name} documentation:
|
||
<<realm_keys,Managing Realm Keys>>.
|
||
====
|
||
|
||
==== Configuring Key Providers
|
||
|
||
To enable cryptographic operations for VC issuance:
|
||
|
||
- **ECDSA (ES256) Key**: Used for signing VCs with the ES256 algorithm.
|
||
- **RSA (RS256) Key**: Alternative signing mechanism using RS256.
|
||
- **RSA-OAEP Key**: Used for encrypting sensitive data in VCs.
|
||
|
||
Each key must be registered as a **java-keystore provider** within the **Realm Settings** > **Keys** section, ensuring:
|
||
- The keystore file is correctly specified and securely stored.
|
||
- The appropriate algorithm (ES256, RS256, or RSA-OAEP) is selected.
|
||
- The key is active, enabled, and configured with the correct usage (signing or encryption).
|
||
- Priority values are set to define precedence among keys.
|
||
|
||
[WARNING]
|
||
====
|
||
Ensure the keystore file is **securely stored** and accessible to the {project_name} server. Use **strong passwords** to protect both the keystore and the private keys.
|
||
====
|
||
|
||
=== Registering Realm Attributes
|
||
|
||
Realm attributes define metadata for Verifiable Credentials (VCs), such as **expiration times, supported formats, and scope definitions**. These attributes allow {project_name} to issue VCs with predefined settings.
|
||
|
||
Since the **{project_name} Admin Console does not support direct attribute creation**, use the **{project_name} Admin REST API** to configure these attributes.
|
||
|
||
==== Define Realm Attributes
|
||
|
||
Create a JSON file (e.g., `realm-attributes.json`) with the following content:
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"realm": "oid4vc-vci",
|
||
"enabled": true,
|
||
"attributes": {
|
||
"preAuthorizedCodeLifespanS": 120
|
||
}
|
||
}
|
||
----
|
||
|
||
==== Attribute Breakdown
|
||
|
||
The attributes section contains issuer-specific metadata:
|
||
- **preAuthorizedCodeLifespanS** – Defines how long pre-authorized codes remain valid (in seconds).
|
||
|
||
==== Import Realm Attributes
|
||
|
||
Use the following `curl` command to import the attributes into {project_name}:
|
||
|
||
[source,bash]
|
||
----
|
||
curl -X PUT "https://localhost:8443/admin/realms/oid4vc-vci" \
|
||
-H "Authorization: Bearer $ACCESS_TOKEN" \
|
||
-H "Content-Type: application/json" \
|
||
-d @realm-attributes.json
|
||
----
|
||
|
||
[NOTE]
|
||
====
|
||
- Replace `$ACCESS_TOKEN` with a valid **{project_name} Admin API access token**.
|
||
- **Avoid using `-k` in production**; instead, configure a **trusted TLS certificate**.
|
||
====
|
||
|
||
=== Create Client Scopes with Mappers
|
||
|
||
Client scopes define **which user attributes** are included in Verifiable Credentials (VCs). Therefore, they are considered the Verifiable Credential configuration itself. These scopes use **protocol mappers** to map specific claims into VCs and the protocol mappers will also contain the corresponding metadata for claims that is displayed at the Credential Issuer Metadata Endpoint.
|
||
|
||
You can create the ClientScopes using the {project_name} web Administration Console, but the web Administration Console does not yet support adding metadata configuration. For metadata configuration, you will need to use the Admin REST API.
|
||
|
||
==== Define a Client Scope with a Mapper
|
||
|
||
Create a JSON file (e.g., `client-scopes.json`) with the following content:
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"name": "vc-scope-mapping",
|
||
"protocol": "oid4vc",
|
||
"attributes": {
|
||
"include.in.token.scope": "true",
|
||
"vc.issuer_did": "did:web:vc.example.com",
|
||
"vc.credential_configuration_id": "my-credential-configuration-id",
|
||
"vc.credential_identifier": "my-credential-identifier",
|
||
"vc.format": "jwt_vc",
|
||
"vc.expiry_in_seconds": 31536000,
|
||
"vc.verifiable_credential_type": "my-vct",
|
||
"vc.supported_credential_types": "credential-type-1,credential-type-2",
|
||
"vc.credential_contexts": "context-1,context-2",
|
||
"vc.proof_signing_alg_values_supported": "ES256",
|
||
"vc.cryptographic_binding_methods_supported": "jwk",
|
||
"vc.signing_key_id": "key-id-123456",
|
||
"vc.display": "[{\"name\": \"IdentityCredential\", \"logo\": {\"uri\": \"https://university.example.edu/public/logo.png\", \"alt_text\": \"a square logo of a university\"}, \"locale\": \"en-US\", \"background_color\": \"#12107c\", \"text_color\": \"#FFFFFF\"}]",
|
||
"vc.sd_jwt.number_of_decoys": "2",
|
||
"vc.credential_build_config.sd_jwt.visible_claims": "iat,jti,nbf,exp,given_name",
|
||
"vc.credential_build_config.hash_algorithm": "SHA-256",
|
||
"vc.credential_build_config.token_jws_type": "JWS",
|
||
"vc.include_in_metadata": "true"
|
||
},
|
||
"protocolMappers": [
|
||
{
|
||
"name": "academic_title-mapper-bsk",
|
||
"protocol": "oid4vc",
|
||
"protocolMapper": "oid4vc-static-claim-mapper",
|
||
"config": {
|
||
"claim.name": "academic_title",
|
||
"staticValue": "N/A"
|
||
}
|
||
},
|
||
{
|
||
"name": "givenName",
|
||
"protocol": "oid4vc",
|
||
"protocolMapper": "oid4vc-user-attribute-mapper",
|
||
"config": {
|
||
"claim.name": "given_name",
|
||
"userAttribute": "firstName",
|
||
"vc.mandatory": "false",
|
||
"vc.display": "[{\"name\": \"الاسم الشخصي\", \"locale\": \"ar-SA\"}, {\"name\": \"Vorname\", \"locale\": \"de-DE\"}, {\"name\": \"Given Name\", \"locale\": \"en-US\"}, {\"name\": \"Nombre\", \"locale\": \"es-ES\"}, {\"name\": \"نام\", \"locale\": \"fa-IR\"}, {\"name\": \"Etunimi\", \"locale\": \"fi-FI\"}, {\"name\": \"Prénom\", \"locale\": \"fr-FR\"}, {\"name\": \"पहचानी गई नाम\", \"locale\": \"hi-IN\"}, {\"name\": \"Nome\", \"locale\": \"it-IT\"}, {\"name\": \"名\", \"locale\": \"ja-JP\"}, {\"name\": \"Овог нэр\", \"locale\": \"mn-MN\"}, {\"name\": \"Voornaam\", \"locale\": \"nl-NL\"}, {\"name\": \"Nome Próprio\", \"locale\": \"pt-PT\"}, {\"name\": \"Förnamn\", \"locale\": \"sv-SE\"}, {\"name\": \"مسلمان نام\", \"locale\": \"ur-PK\"}]"
|
||
}
|
||
}
|
||
]
|
||
}
|
||
----
|
||
|
||
[NOTE]
|
||
====
|
||
This is a **sample configuration**.
|
||
You can define **additional protocol mappers** to support different claim mappings, such as:
|
||
|
||
- Dynamic attribute values instead of static ones.
|
||
- Mapping multiple attributes per credential type.
|
||
- Alternative supported credential types.
|
||
====
|
||
|
||
From the example above:
|
||
|
||
- It is important to set `include.in.token.scope=true`, see <<include.in.token.scope, Attribute table: include.in.token.scope>>.
|
||
- Most of the named attributes above are optional. See below: <<client-scope-attribute-breakdown,Attribute Breakdown>>.
|
||
- You can determine the appropriate `protocolMapper` names by first creating them through the Web Administration Console and then retrieving their definitions via the Admin REST API.
|
||
|
||
==== Attribute Breakdown - ClientScope [[client-scope-attribute-breakdown]]
|
||
|
||
[cols="1,1,2", options="header"]
|
||
|===
|
||
| Property
|
||
| Required
|
||
| Description / Default
|
||
|
||
| `name`
|
||
| required
|
||
| Name of the client scope.
|
||
|
||
| `protocol`
|
||
| required
|
||
| Protocol used by the client scope. Use `oid4vc` for OpenID for Verifiable Credential Issuance, which is an OAuth2 extension (like `openid-connect`).
|
||
|
||
| `include.in.token.scope`
|
||
| required
|
||
| [[include.in.token.scope]] This value MUST be `true`. It ensures that the scope’s name is included in the `scope` claim of the issued Access Token.
|
||
|
||
| `protocolMappers`
|
||
| optional
|
||
| Defines how claims are mapped into the credential and how metadata is exposed via the issuer’s metadata endpoint.
|
||
|
||
| `vc.issuer_did`
|
||
| optional
|
||
| The Decentralized Identifier (DID) of the issuer. +
|
||
_Default_: `$\{name}`
|
||
|
||
| `vc.credential_configuration_id`
|
||
| optional
|
||
| The credentials configuration ID. +
|
||
_Default_: `$\{name}+`
|
||
|
||
| `vc.credential_identifier`
|
||
| optional
|
||
| The credentials identifier. +
|
||
_Default_: `$\{name}+`
|
||
|
||
| `vc.format`
|
||
| optional
|
||
| Defines the VC format (e.g., `jwt_vc`). +
|
||
_Default_: `vc+sd-jwt`
|
||
|
||
| `vc.verifiable_credential_type`
|
||
| optional
|
||
| The Verifiable Credential Type (VCT). +
|
||
_Default_: `$\{name}+`
|
||
|
||
| `vc.supported_credential_types`
|
||
| optional
|
||
| The type values of the Verifiable Credential Type. +
|
||
_Default_: `$\{name}+`
|
||
|
||
| `vc.credential_contexts`
|
||
| optional
|
||
| The context values of the Verifiable Credential Type. +
|
||
_Default_: `$\{name}+`
|
||
|
||
| `vc.proof_signing_alg_values_supported`
|
||
| optional
|
||
| Supported signature algorithms for this credential. +
|
||
_Default_: All present keys supporting JWS algorithms in the realm.
|
||
|
||
| `vc.cryptographic_binding_methods_supported`
|
||
| optional
|
||
| Supported cryptographic methods (if applicable). +
|
||
_Default_: `jwk`
|
||
|
||
| `vc.signing_key_id`
|
||
| optional
|
||
| The ID of the key to sign this credential. +
|
||
_Default_: _none_
|
||
|
||
| `vc.display`
|
||
| optional
|
||
| Display information shown in the user's wallet about the issued credential. +
|
||
_Default_: _none_
|
||
|
||
| `vc.sd_jwt.number_of_decoys`
|
||
| optional
|
||
| Used only with format `vc+sd-jwt`. Number of decoy hashes in the SD-JWT. +
|
||
_Default_: `10`
|
||
|
||
| `vc.credential_build_config.sd_jwt.visible_claims`
|
||
| optional
|
||
| Used only with format `vc+sd-jwt`. Claims always disclosed in the SD-JWT body. +
|
||
_Default_: `id,iat,nbf,exp,jti`
|
||
|
||
| `vc.credential_build_config.hash_algorithm`
|
||
| optional
|
||
| Hash algorithm used before signing the credential. +
|
||
_Default_: `SHA-256`
|
||
|
||
| `vc.credential_build_config.token_jws_type`
|
||
| optional
|
||
| JWT type written into the `typ` header of the token. +
|
||
_Default_: `JWS`
|
||
|
||
| `vc.expiry_in_s`
|
||
| optional
|
||
| Credential expiration time in seconds. +
|
||
_Default_: `31536000` (one year)
|
||
|
||
| `vc.include_in_metadata`
|
||
| optional
|
||
| If this claim should be listed in the credentials metadata. +
|
||
_Default_: `true` but depends on the mapper-type. Claims like `jti`, `nbf`, `exp`, etc. are set to `false` by default.
|
||
|===
|
||
|
||
==== Attribute Breakdown - ProtocolMappers
|
||
|
||
- **name** – Mapper identifier.
|
||
- **protocol** – Must be `oid4vc` for Verifiable Credentials.
|
||
- **protocolMapper** – Specifies the claim mapping strategy (e.g., `oid4vc-static-claim-mapper`).
|
||
- **config**: contains the protocol-mappers specific attributes.
|
||
|
||
Most claims are dependent on the `protocolMapper`-value, but there are also commonly used claims available for all ProtocolMappers:
|
||
|
||
[cols="1,1,2", options="header"]
|
||
|===
|
||
| Property
|
||
| Required
|
||
| Description / Default
|
||
|
||
| `claim.name`
|
||
| required
|
||
| The name of the attribute that will be added into the Verifiable Credential. +
|
||
_Default_: _none_
|
||
|
||
| `userAttribute`
|
||
| required
|
||
| The name of the users-attribute that will be used to map the value into the `claim.name` of the Verifiable Credential. +
|
||
_Default_: _none_
|
||
|
||
| `vc.mandatory`
|
||
| optional
|
||
| If the credential must be issued with this claim. +
|
||
_Default_: `false`
|
||
|
||
| `vc.display`
|
||
| optional
|
||
| Metadata information that is displayed at the credential-issuer metadata-endpoint. +
|
||
_Default_: _none_
|
||
|===
|
||
|
||
==== Import the Client Scope
|
||
|
||
Use the following `curl` command to import the client scope into {project_name}:
|
||
|
||
[source,bash]
|
||
----
|
||
curl -X POST "https://localhost:8443/admin/realms/oid4vc-vci/client-scopes" \
|
||
-H "Authorization: Bearer $ACCESS_TOKEN" \
|
||
-H "Content-Type: application/json" \
|
||
-d @client-scopes.json
|
||
----
|
||
|
||
[NOTE]
|
||
====
|
||
- Replace `$ACCESS_TOKEN` with a valid **{project_name} Admin API access token**.
|
||
- **Avoid using `-k` in production**; instead, configure a **trusted TLS certificate**.
|
||
- If updating an existing scope, use `PUT` instead of `POST`.
|
||
====
|
||
|
||
=== Create the Client
|
||
|
||
Set up a client to handle Verifiable Credential (VC) requests and assign the necessary scopes.
|
||
The client does not differ from regular OpenID Connect clients — with one exception: it must have the appropriate **optional ClientScopes** assigned that define the Verifiable Credentials it is allowed to issue.
|
||
|
||
. Create a JSON file (e.g., `oid4vc-rest-api-client.json`) with the following content:
|
||
+
|
||
[source,json]
|
||
----
|
||
{
|
||
"clientId": "oid4vc-rest-api",
|
||
"enabled": true,
|
||
"protocol": "openid-connect",
|
||
"publicClient": false,
|
||
"serviceAccountsEnabled": true,
|
||
"clientAuthenticatorType": "client-secret",
|
||
"redirectUris": ["http://localhost:8080/*"],
|
||
"directAccessGrantsEnabled": true,
|
||
"defaultClientScopes": ["profile"],
|
||
"optionalClientScopes": ["vc-scope-mapping"],
|
||
"attributes": {
|
||
"client.secret.creation.time": "1719785014",
|
||
"client.introspection.response.allow.jwt.claim.enabled": "false",
|
||
"login_theme": "keycloak",
|
||
"post.logout.redirect.uris": "http://localhost:8080"
|
||
}
|
||
}
|
||
----
|
||
+
|
||
- **clientId**: Unique identifier for the client.
|
||
- **optionalClientScopes**: Links the `vc-scope-mapping` scope for VC requests.
|
||
|
||
. Import the client using the following `curl` command:
|
||
+
|
||
[source,bash]
|
||
----
|
||
curl -k -X POST "https://localhost:8443/admin/realms/oid4vc-vci/clients" \
|
||
-H "Authorization: Bearer $ACCESS_TOKEN" \
|
||
-H "Content-Type: application/json" \
|
||
-d @oid4vc-rest-api-client.json
|
||
----
|
||
|
||
=== Verify the Configuration
|
||
|
||
Validate the setup by accessing the **issuer metadata endpoint**:
|
||
|
||
. Open a browser or use a tool like `curl` to visit:
|
||
+
|
||
[source,bash]
|
||
----
|
||
https://localhost:8443/realms/oid4vc-vci/.well-known/openid-credential-issuer
|
||
----
|
||
|
||
A successful response returns a JSON object containing details such as:
|
||
- **Supported claims**
|
||
- **Credential formats**
|
||
- **Issuer metadata**
|
||
|
||
=== Conclusion
|
||
|
||
You have successfully configured **{project_name} as a Verifiable Credential Issuer** using the **OID4VCI protocol**.
|
||
This setup leverages {project_name}'s robust **identity management capabilities** to issue secure, **standards-compliant VCs**.
|
||
|
||
For a **complete reference implementation**, see the sample project:
|
||
https://github.com/adorsys/{project_name}-ssi-deployment/tree/main[{project_name} SSI Deployment^].
|