Verifiable Credential Issuance#
Curity Identity Server support for verifiable credential issuance is experimental and should not be used in production scenarios. The described capabilities, configuration model, and associated behavior may change between releases of the Curity Identity Server in a way that is not backward compatible.
Introduction#
The Curity Identity Server supports verifiable credential issuance (VCI), as defined by
OpenID for Verifiable Credential Issuance (draft 13 - Implementer’s Draft 1)
, henceforth identified as OpenID4VCI. For the time being, this support is being added to the Curity Identity Server for
experimentation and evaluation purposes only. By default the verifiable credential issuance functionality is disabled.
Run the Curity Identity Server with the se.curity.verifiable-credentials.enable system property set to true to enable it.
The verifiable credential issuance behavior is mostly configured in the verifiable-credentials setting, added to the Token Profile configuration.
It is comprised by two main child settings:
-
A list of
verifiable-credentialconfiguration items, where each item defines how a particular kind of verifiable credential (e.g. academic degree credential, driver’s license) should be issued. -
A set of shared settings that can be used by one or more verifiable credential types.
Each verifiable-credential entry contains both generic settings, applicable to all credential data models, as well as settings that are specific to the data model used by that credential type.
The following sections provide more information about this configuration model.
Formats and data models#
The OpenID for Verifiable Credential Issuance (draft 13 - Implementer’s Draft 1) specification aims to support multiple verifiable credential formats and associated data models. In the current version, the Curity Identity Server supports two formats:
- the
jwt_vc_jsonformat, where verifiable credentials follow the W3C Verifiable Credential Data Model 1.1 and are packaged inside signed JSON Web Tokens. - the
vc+sd-jwtformat, where verifiable credentials follow the SD-JWT-based Verifiable Credentials (SD-JWT VC) data model.
Future versions may add support for other signature packaging methods or different verifiable credential data models.
W3C data model#
In the W3C data model, “the type property is used to uniquely identify the type of the verifiable credential in which it appears, i.e., to indicate which set of claims the verifiable credential contains”.
The Curity Identity Server follows this guidance by having a configuration model where:
-
First, multiple W3C data model types can be configured using the
verifiable-credentials/w3c/typesetting. Each type includes references to claims or to scopes (as a set of claims). This directly or indirectly defines the claims to include on verifiable credentials of that type. -
Second, each
verifiable-credentials/verifiable-credentialentry, defining a particular kind of verifiable credential using the W3C data model, references one or more of the types previously defined.
SD-JWT VC data model#
In the SD-JWT VC data model, “A type is associated with rules defining which claims may or must appear in the Unsecured Payload of the SD-JWT VC and whether they may, must, or must not be selectively disclosable”.
The Curity Identity Server follows this guidance by having a configuration model where:
-
First, multiple SD-JWT VC data model types can be configured using the
verifiable-credentials/vc-sd-jwt/type. Each type includes references to one or more existing claims. -
Second, each
verifiable-credentials/verifiable-credentialentry, defining a particular kind of verifiable credential using the SD-JWT VC data model, references exactly one of the types previously defined.
Each claim referenced by an SD-JWT VC data model type has two extra configuration settings, defining:
- Whether the claim presence in the credential is mandatory or optional.
- Whether the claim can be selectively disclosable or not. A claim that is not selectively disclosable will always be included in the verifiable credential presentations.
Two different SD-JWT VC data model types may define different mandatory or selective disclosure settings for the same claim.
If a claim is configured as being selectively disclosable and the claim value is an object, then it is also possible to configure which inner properties are selectively disclosable.
As an example, consider an address claim, whose value is an object composed of the street_address and country properties.
-
If the
addressis not configured as selectively disclosable, then a credential presentation will always include an object with both properties. -
If the
addressis configured as selectively disclosable, then a credential presentation can choose if the claim should be included or not. If included, both properties will be there. -
However, it is also possible to configure both the
addressclaim and the innerstreet_addressproperty as selectively disclosable. This allows for three different options when presenting a verifiable credential issued with this configuration:- Do not disclose the
addressclaim. - Disclose the
addressclaim, but keep the innerstreet_addressclaim concealed, i.e., only include thecountryproperty. - Disclose the
addressclaim and all its inner properties.
- Do not disclose the
Endpoints#
The verifiable credential issuance functionality adds the oauth-verifiable-credential endpoint type.
Endpoints of this type are responsible for receiving credential requests and producing credential responses, containing the issued verifiable credentials, as defined by the OpenID4VC draft specification.
A Token Service profile can have zero or more verifiable credential endpoints, which are created, configured, and deployed like any other endpoint of the profile.
If enabled, the verifiable credential issuance functionality will expose the Credential Issuance Metadata in a subpath of the anonymous endpoint, namely in the well known path /.well-known/openid-credential-issuer.
The full path depends on the configuration details such as base URL, service role and anonymous endpoint.
Each entry in the credential_configurations_supported object of the Credential Issuer Metadata corresponds to a verifiable-credential configuration entry.
Token procedures#
Each oauth-verifiable-credential endpoint can be configured to use a token procedure, allowing the programmatic customization of credential responses, analogously to what is possible for other Token Service endpoints.
These procedures can be implemented by scripts or by SDK token procedure plugins.
Credential Request Handling#
The Curity Identity Server supports the generic credential request parameters format and proof, as defined by the
OpenID4VCI generic credential request
:
-
format(mandatory) - must have thejwt_vc_jsonvalue or thevc+sd-jwtvalue, which are currently the only formats supported by the Curity Identity Server. -
proof(mandatory) - must contain a proof of possession for the key material associated to the subject. The specified type must bejwt.
Both the proof JWT content and the remaining credential request parameters depend on the credential format.
jwt_vc_json format - W3C data model#
When using the jwt_vc_json format, the proof parameter must include a JWT with the following characteristics:
-
A mandatory
kidheader property, holding a DID URL pointing to the subject’s verification key. When issuance is successful, the issued verifiable credential will use the DID from this DID URL as the credential’s subject identifier. -
An optional
jwkheader property, containing the subject’s verification key. This property is only needed when the used DID method does not provide enough information to fully retrieve the key.
The jwt_vc_json format also defines the credential_definition mandatory credential endpoint request parameter, which is an object with two properties:
-
type(mandatory) - must contain the types of the issued credential, according to what is defined by the W3C data model. The request types must exactly match what is configured by a verifiable-credential configuration entry using a W3C data model, otherwise the issuance will be denied. The supported combination of types is present in the exposed metadata. -
credentialSubject(optional) - can contain the optional subject claims that also should be included in the issued verifiable credential. By default only the mandatory claims for the requested set of types are included in the issued verifiable credential. By using this parameter, the client/wallet can ask for the inclusion of additional optional claims. The claims for each set of types, as well if they are mandatory or optional, are described in the exposed metadata.
Subject and issuer DID methods#
The supported DID methods for subject identification are configured by the allowed-subject-did-methods setting.
It is expected that the Curity Identity Server in the future will support more DID methods for subject identification.
Any DID method is supported for issuer identification, as long as the key used by the token issuer has an external-id containing a DID URL.
vc+sd-jwt format - SD-JWT VC data model#
When using the vc+sd-jwt format, the proof parameter must include a JWT with the following characteristics:
- A mandatory
jwkheader property, containing the subject’s verification key, to which the issued credential will be bound.
The vc+sd-jwt format also defines the following specific credential endpoint request parameters:
-
vct(mandatory) - must contain the type of the issued credential, according to what is defined by the SD-JWT-based Verifiable Credentials specification. The requested type must exactly match what is configured by averifiable-credentialconfiguration entry using the SD-JWT VC data model, otherwise the issuance will be denied. The supported types are present in the exposed metadata. -
claims(optional) - can contain the optional subject claims that also should be included in the issued verifiable credential. By default only the mandatory claims for the requested type are included in the issued verifiable credential. By using this parameter, the client or wallet can request for the inclusion of additional optional claims. The claims for each type, as well if they are mandatory or optional, are described in the exposed metadata.
Token Issuers#
The signature and issuance of verifiable credentials with the jwt_vc_json format (i.e. the W3C data model) is done by custom token issuers with the verifiable-credential purpose and the jwt type.
The signature and issuance of verifiable credentials with the vc+sd-jwt format (i.e. SD-JWT VC data model) is done by custom token issuers with the verifiable-credential purpose and the sd-jwt type.
Each verifiable credential kind (i.e. each verifiable-credential entry) can use a distinct token issuer.
Authorization Requests#
A credential request needs to include an access token granting:
- Access to the verifiable credential issuance.
- Access to the claims that will be included in the issued verifiable credential.
A way for a client or wallet to obtain such an access token is by using the OAuth 2.0 authorization_code grant.
The authorization request, used to obtain that authorization code, needs to specify the above access token requirements by using scopes, as defined by OpenID4VCI.
For that, the scope parameter needs to:
- Include the special
openid_credentialscope. - Include the scopes that grant access to the required claims. Alternatively, the request can also use the OpenID Connect claims request parameter to specify the required claims.
It is also possible to use the authorization_details authorization request parameter, as defined by RFC 9396 - OAuth 2.0 Rich Authorization Requests specification.
Each authorization_details item should have the type property set to openid_credential.
The remaining properties are documented in OpenID4VCI usage of authorization_details and in the OpenID4VCI credential format profiles.
Configuration Model Summary#
This section contains a brief summary of the verifiable credential issuance configuration model.
-
verifiable-credentials
-
Root for the verifiable credentials issuance configuration.
-
name
- Name for the verifiable credential issuer, used on the issuer metadata.
-
expose-metadata
- Used to enable and configure the exposure of verifiable credential issuance metadata.
-
w3c
-
Root for the shared settings that are specific to the W3C VC data model.
type- Eachtypelist entry defines a W3C data model type, characterized by a simple name (e.g.UniversityDegreeCredential), a fully qualified name (e.g.https://example.org/examples#UniversityDegreeCredential) and the set of subject claims that should be added to verifiable credentials with this type, defined via references to claims or scopes.
-
-
vc-sd-jwt
-
Root for the shared settings that are specific to the SD-JWT VC data model.
type- Eachtypelist entry defines a SD-JWT VC data model type, characterized by the type identifier and the set of subject claims that should be added to verifiable credentials with this type, defined via references to claims.
-
-
verifiable-credential
-
Each
verifiable-credentiallist entry defines an issuance template for a kind of verifiable credential, i.e., defines how that credential kind should be created.-
credential-ttl- Defines the validity duration of the verifiable credential. -
data-model/w3c-vc- Contains configuration settings specific to verifiable credentials that follow the W3C verifiable credential data model.-
context- Defines the contents of the@contextverifiable credential property. -
schema- Defines the contents of thecredentialSchemaverifiable credential property. -
token-issuer- Defines the token issuer used to sign the verifiable credential. The token issuer purpose must beverifiable_credentialand its type defines how the verifiable credential is signed. Currently, the only supported type isjwt, meaning that the verifiable credential will be contained inside a JSON Web Token, i.e., have thejwt_vc_jsonformat. -
issuer- Defines the value of theissuerverifiable credential property, containing the issuer identifier, which can be:-
The same as the Token Service issuer.
-
An explicitly defined URI.
-
The URI inferred from the token issuer’s Key ID (KID) identifying the cryptographic key used to sign the verifiable credential, applicable when that KID is a DID URL. On the Curity Identity Server, this KID can be defined by using the key’s
external-id.
-
-
allowed-subject-did-methods- Defines the DID methods allowed for the subject identification.
-
-
data-model/vc-sd-jwt- Contains configuration settings specific to verifiable credentials that follow the SD-JWT VC data model.-
type- Defines the SD-JWT VC type to use for this verifiable credential. -
token-issuer- Defines the token issuer used to sign the verifiable credential. The token issuer purpose must beverifiable_credentialand its type must besd-jwt.
-
-
-
-
-
The access to the root verifiable-credentials configuration setting is hidden by default in the bin/idsh command
line interface tool, since the verifiable credential issuance feature is still experimental. Running the command
unhide verifiable-credentials on the bin/idsh shell will make the verifiable-credentials configuration setting
usable on that shell.
Configuration Example#
This section illustrates the verifiable credential issuance configuration model via a brief XML example, which:
- Creates the
signing-keyused to sign the verifiable credentials and assigns itsexternal-idwith a DID URL. - Creates a
jwtcustom token issuer, using the above key, with apurpose-typeofverifiable_credential. - Creates the set of claims that should be included as subject claims on the issued verifiable credentials. The way these claims are defined is not specific to verifiable credential issuance.
- Defines the special
openid_credentialscope required for an access token to grant access to the credential endpoint. - Defines a W3C data model type, including the claims that are associated to that type.
- Defines a
verifiable-credentialentry, with all the information necessary to issue a verifiable credential. Thisverifiable-credentialentry includes a reference to the W3C type created in the previous step.
<config xmlns="http://tail-f.com/ns/config/1.0">
<facilities xmlns="https://curity.se/ns/conf/base">
<crypto>
<signing-keys>
<!-- Defining the key used to sign the verifiable credential -->
<signing-key>
<id>esbi-1</id>
<keystore>...the key contents...</keystore>
<curve-name>P-256</curve-name>
<type>elliptic-curve</type>
<external-id>...the DID URL of the key...</external-id>
</signing-key>
</signing-keys>
</crypto>
</facilities>
<profiles xmlns="https://curity.se/ns/conf/base">
<profile>
<id>oauth-dev</id>
<type xmlns:as="https://curity.se/ns/conf/profile/oauth">as:oauth-service</type>
<token-issuers>
<!-- Defining the custom token issuer used to create and sign the verifiable credential -->
<custom-token-issuer>
<id>jwt-vc-issuer-1</id>
<issuer-type>jwt</issuer-type>
<purpose-type>verifiable_credential</purpose-type>
<jwt>
<algorithm>ES256</algorithm>
<!-- the ID of the key previously created -->
<signing-key-id>esbi-1</signing-key-id>
</jwt>
</custom-token-issuer>
</token-issuers>
<settings>
<authorization-server xmlns="https://curity.se/ns/conf/profile/oauth">
<!-- Defining the subject claims, using the normal way of defining claims in Curity Identity Server -->
<claims>
<claim>
<name>givenName</name>
...
</claim>
<claim>
<name>familyName</name>
...
</claim>
<claim>
<name>middleName</name>
...
</claim>
<claim>
<name>degreeSchool</name>
...
</claim>
<claim>
<name>degreeType</name>
...
</claim>
</claims>
<scopes>
<!-- Defining a scope as a group of claims -->
<scope>
<id>UniversityDegreeCredentialScope</id>
<time-to-live>3600</time-to-live>
<claims>givenName</claims>
<claims>middleName</claims>
<claims>familyName</claims>
<claims>degreeType</claims>
<claims>degreeSchool</claims>
</scope>
<scope>
<!-- This special scope needs to be created because it will be required on the credential endpoint -->
<id>openid_credential</id>
</scope>
</scopes>
<verifiable-credentials>
<name>Development Verifiable Credentials Issuer</name>
<w3c>
<!-- Defining a W3C type with the required claims -->
<type>
<id>https://example.org/examples#UniversityDegreeCredential</id>
<simple-name>UniversityDegreeCredential</simple-name>
<!-- Claims from the UniversityDegreeCredentialScope scope can included in a credential of this type but are not mandatory -->
<scope>UniversityDegreeCredentialScope</scope>
<!-- Claims from the address scope can included in a credential of this type but are not mandatory -->
<scope>address</scope>
<claim>
<name>givenName</name>
<mandatory>true</mandatory>
</claim>
<claim>
<name>familyName</name>
<mandatory>true</mandatory>
</claim>
<claim>
<name>degreeType</name>
<mandatory>true</mandatory>
</claim>
<claim>
<name>degreeSchool</name>
<mandatory>true</mandatory>
</claim>
<!-- claim middleName is included on UniversityDegreeCredentialScope but is not mandatory -->
</type>
</w3c>
<!-- Defining a particular kind of verifiable credential, by using the type defined above -->
<verifiable-credential>
<id>university-degree-credential</id>
<name>University Degree Credential</name>
<description>A verifiable credential with your degree completion information.</description>
<logo>...</logo>
<!-- Defining data specific to the W3C data model -->
<w3c-vc>
<context>
<id>W3C example</id>
<uri>https://www.w3.org/2018/credentials/examples/v1</uri>
</context>
<!-- the reference to the type created above-->
<type>https://example.org/examples#UniversityDegreeCredential</type>
<schema>
<!-- example taken from https://www.w3.org/TR/vc-data-model/#data-schemas -->
<id>https://example.org/examples/degree.json</id>
<type>JsonSchemaValidator2018</type>
</schema>
<token-issuer>jwt-vc-issuer-1</token-issuer>
<issuer>
<!-- the issuer ID should be inferred from the DID URL present in the signature key external-id -->
<infer-from-kid />
</issuer>
<allowed-subject-did-methods>
<method>ebsi</method>
</allowed-subject-did-methods>
</w3c-vc>
<credential-ttl>31536000</credential-ttl>
</verifiable-credential>
</verifiable-credentials>
<client-store>
<config-backed>
<client>
<!-- The client that will be requesting credentials -->
<id>client-one</id>
<scope>openid</scope>
<scope>profile</scope>
<scope>UniversityDegreeCredentialScope</scope>
<!-- Needs to have this special scope -->
<scope>openid_credential</scope>
</client>
</config-backed>
</client-store>
</authorization-server>
</settings>
</profile>
</profiles>
</config>