Experimental

Verifiable Credential Issuance

Caution

The 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.

The Curity Identity Server supports verifiable credential issuance (VCI), as defined by OpenID for Verifiable Credential Issuance (draft 11), henceforth identified as OpenID4VCI. For the moment 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 Service profile configuration. It is comprised by two main child settings:

  • A list of verifiable-credentials/verifiable-credential configuration items, where each item defines how a 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 kinds.

Each verifiable-credentials/verifiable-credential contains both generic settings, applicable to all credential formats, as well as settings that are specific to the format used by that credential kind.

The following sections provide more information about this configuration model.

Formats and data models

The OpenID for Verifiable Credential Issuance (draft 11) specification aims to support multiple verifiable credential formats and associated data models. In the current version, the Curity Identity Server supports the jwt_vc_json format, where verifiable credentials follow the W3C Verifiable Credential Data Model 1.1 and are packaged inside signed JSON Web Tokens. Future versions may add support for other signature packaging methods or different verifiable credential data models.

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 types can be configured using the verifiable-credentials/w3c/type setting. Each type includes references to claims or to scopes (as set of claims). This directly or indirectly defines the claims to include on verifiable credentials of that type.
  • Second, each verifiable-credentials/verifiable-credential entry, defining a particular kind of verifiable credential, references one or more of the types previously defined.

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 (see verifiable-credentials/expose-metadata). The full path depends on the configuration details such as base URL, service role and anonymous endpoint. See verifiable-credentials/expose-metadata for more information. Each entry in the credentials_supported array of the Credential Issuer Metadata corresponds to a verifiable-credentials/verifiable-credential 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. In addition, it also supports the format-specific parameters types and credentialSubject, as defined by the OpenID4VCI jwt_vc_json credential request:

  • format (mandatory) - must have the value jwt_vc_json, which is currently the only format supported by the Curity Identity Server.

  • proof (mandatory) - must contain a proof of possession for the key material associated to the subject DID (Decentralized Identifier). The specified type must be jwt. Currently, the issued verifiable credentials need to have a DID as the credential subject identifier. The credential request needs to prove that the requester does hold the private key material associated to that DID. Consequently, the proof parameter must include a JWT with the following properties:

    • A mandatory kid header 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 jwk header 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 (e.g. EBSI Natural Person DID).
  • types (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, 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 is 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 verifiable-credentials/verifiable-credential/w3c-vc/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 a external-id containing a DID URL.

Token Issuers

The signature and issuance of verifiable credentials with the jwt_vc_json format is done by custom token issuers with the verifiable-credential purpose, which is currently only allowed for token issuers with the jwt type. Each verifiable credential kind (i.e. each verifiable-credentials/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/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 partially defined by OpenID4VCI. For that, the scope parameter needs to:

  • Include the special openid_credential scope.
  • 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.

Configuration Model Summary

This section contains a brief summary of the verifiable 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-metada - 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 - Each type list 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.
    • verifiable-credential - Each verifiable-credential list 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 @context verifiable credential property.

        • schema - Defines the contents of the credentialSchema verifiable credential property.

        • token-issuer - Defines the token issuer used to sign the verifiable credential. The token issuer purpose must be verifiable_credential and its type defines how the verifiable credential is signed. Currently, the only supported type is jwt, meaning that the verifiable credential will be contained inside a JSON Web Token, i.e., have the jwt_vc_json format.

        • issuer - Defines the value of the issuer verifiable credential property, containing the issuer identifier, which can be:

          • The same as the Token Service issuer.
          • An explicitly defined URI.
          • The URI infered from the token issuer’s Key ID (KID) identifiying 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.

Note

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 example, which:

  • Creates the signing-key used to sign the verifiable credentials and assigns its external-id with a DID URL.
  • Creates a jwt custom token issuer, using the above key, with a purpose-type of verifiable_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_credential scope 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-credential entry, with all the information necessary to issue a verifiable credential. This verifiable-credential entry includes a reference to the W3C type created in the previous step.
Listing 165 Example configuration for verifiable credential issuance.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
<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 creared 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 infered 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>