Skip to main content

Credential schemas

Learn how to work with credential schemas.

A credential schema is like a template for credentials: it defines the structure and key components that make a credential a certain kind of credential. Whether you are issuing or verifying credentials you will create credential schemas. Here you will learn how to create and work with credential schemas.

Credential schemas in Procivis One

A credential schema represents a type of credential and includes components such as:

  • How the credential data is formatted and secured.
  • The method used for future suspension and revocation, if any.
  • The kind of claims asserted during issuance, in the form of keys such as Name or Birthdate and datatypes for validating the claims made.
  • Design and layout properties of the credential, so wallets know how to render the credential visually for the holder.
  • Issuer requests about the properties of the wallet, such as whether the wallet should use software- or hardware-based keys for signing the credential on issuance.

If you are issuing

Create a schema for each kind of credential you want to issue. With each issuance you assert claims about the subject and the system then ensures that each credential created from the schema matches the desired type.

If you are verifying

Create a schema for each kind of credential you want to request information from. Then you will later create proof schemas representing more precisely the information you want to request.

For example, if you want information from a Driver's License and from a Passport, you will create a credential schema for each. Then you will create a proof schema that specifies which attributes from which credential you want to make in your request.

Related guide: Proof schemas

If you are holding

You will consume schemas to gain information about how to display the credential in the wallet and what sort of keys to use to sign during issuance and presentation.

Create a credential schema

A credential schema consists of the following components:

  • Schema name
  • Credential format
  • Revocation method
  • Claims object
  • (Mandatory for certain credential formats)
    • Schema ID or "Document type"
  • (Optional)
    • Credential design
    • Wallet storage type
    • Allow suspension flag
    • External schema flag

Schema name

This should be something like:

  • "Driver License"
  • "Employment Authorization"
  • "Passport"
  • "Residence Permit"

Each name must be unique but you can create as many credential schemas as you need.

Credential format

The credential format determines how the data is bundled and secured. In most cases your choice of format will be driven by the ecosystem in which you operate:

  • eIDAS uses IETF SD-JWT VC and ISO mdoc
  • Swiss E-ID uses IETF SD-JWT VC
  • Some U.S. States are using ISO mdoc

Check the format object of your configuration for your options. When you create your schema, be sure to reference the instance name of your chosen format, rather than the type; multiple instances of a single credential format could be configured.

"format": {
"MDOC_MOD_1": { // Reference this
"type": "MDOC", // Not this
{{distinct params and capabilities}}
},
"MDOC_MOD_2": { // Reference this
"type": "MDOC", // Not this
{{distinct params and capabilities}}
},
}

For the complete list of natively supported credential formats, see the reference.

Revocation method

The revocation method determines the mechanism by which credentials issued using your schema can be revoked. Your chosen credential format, along with other configuration details, may dictate your choice of revocation method. Check the configuration of your chosen format for capabilities.revocationMethods for a list of all compatible revocation methods.

If you do not want a revocation method with your schema you must choose a configured instance of "type": "NONE". This is relevant if the credential you are issuing is either valid forever or if revocation is handled through some other means, such as having a claim with a specified expiration date.

Allow suspension flag

In addition to permanent revocation, some methods allow for temporary suspension. For your chosen revocation method, check the capabilities.operations for a complete list of supported operations.

If your method allows for suspension and you would like credentials issued with your schema to allow for suspension, pass "allowSuspension": true, during schema creation.

Claims object

A crucial part of your schema is the set of attributes about which you will be making assertions. These are all the fields typically seen on credentials such as:

  • Name
  • Age
  • Birthdate
  • Address
  • and so on...

When you create your schema you must specify all of the attributes about which claims will later be asserted. Here's an example claims object for a simple credential schema:

"claims": [
{
"array": false,
"claims": [],
"datatype": "STRING",
"key": "Name",
"required": true
},
{
"array": false,
"claims": [],
"datatype": "BIRTH_DATE",
"key": "Birthdate",
"required": false
},
{
"array": true,
"claims": [],
"datatype": "STRING",
"key": "Address",
"required": true
}
],

For each claim we assign:

  • Key, or claim name
  • Whether the claim is required
  • The datatype of the claim
  • Whether the claim allows an array to be passed for this claim during issuance
  • If the datatype of the claim is an OBJECT, the nested claims go in the claims array. Otherwise, leave this empty.

Claim key

Claim name restrictions

Some credential formats (JSON-LD, for example) disallow certain strings as keys for claims, to avoid collision with other fields of the credential.

When retrieving the configuration through the API, the forbiddenClaimNames capability of credential formats lists any restricted claim keys.

Required flag

If the claim is required and no value is passed during credential issuance the credential will fail to be created.

Datatypes

When creating a credential schema, you must specify a datatype for each claim in your claims object. These datatypes determine how the claim data will be validated during credential issuance and verification.

How datatypes work
  1. The system configuration defines specific datatype instances with validation rules. For example:

    • The EMAIL datatype instance might be a STRING with a specific regex pattern.
    • The MDL_PICTURE datatype instance might be a FILE that accepts only jpeg and uses encodeAsMdlPortrait to ensure correct encoding for an ISO Mobile Driving License.

  2. When creating a credential schema, reference these configured datatypes for each claim.

  3. During issuance, when an issuer makes claims about a subject, the claim values are validated against the rules defined in the corresponding datatype.

Suppose you retrieve the configuration and it includes the following for the datatype object:

"datatype": {
"BIRTH_DATE": {
"type": "DATE",
"display": "datatype.birth_date",
"order": 310,
"params": {
"min": "1900-01-01",
"max": "NOW",
"error": {
"de": "Bitte wählen Sie ein Datum zwischen 1900-1-1 und heute",
"en": "Please choose a date between 1900-1-1 and today"
}
}
},
"EMAIL": {
"type": "STRING",
"display": "datatype.email",
"order": 110,
"params": {
"autocomplete": true,
"placeholder": "abc@abc.com",
"pattern": "^[\\w\\-\\.]+@([\\w\\-]+\\.)+[\\w\\-]{2,4}$",
"error": {
"de": "Bitte geben Sie eine gültige E-Mail Adresse ein",
"en": "Please provide a valid email address"
}
}
},
"POSTAL_CODE": {
"type": "NUMBER",
"display": "datatype.postal_code",
"order": 200,
"params": {
"min": "5",
"max": "5",
}
},
"STRING": {
"type": "STRING",
"display": "datatype.string",
"order": 100
},
},

Using this hypothetical configuration, here's an example call that uses:

  • The BIRTH_DATE datatype that restricts valid dates to 1900-01-01 and after with a min param.
  • The EMAIL datatype that ensures the proper regex pattern.
  • The POSTAL_CODE datatype that restricts entries to numbers with exactly five digits.
"claims": [
{
"array": false,
"claims": [],
"datatype": "STRING",
"key": "Name",
"required": true
},
{
"array": false,
"claims": [],
"datatype": "EMAIL",
"key": "Email",
"required": true
},
{
"array": false,
"claims": [
{
"array": false,
"claims": [],
"datatype": "STRING",
"key": "Street",
"required": true
},
{
"array": false,
"claims": [],
"datatype": "STRING",
"key": "City",
"required": true
},
{
"array": false,
"claims": [],
"datatype": "POSTAL_CODE",
"key": "Postal code",
"required": true
}
],
"datatype": "OBJECT",
"key": "Address",
"required": true
},
{
"array": false,
"claims": [],
"datatype": "BIRTH_DATE",
"key": "Birthdate",
"required": true
}
],

Check the datatype object of the configuration for the supported datatypes. See the datatypes reference for details on available types and their parameters.

Nested claims

Use the OBJECT datatype to create nested claims (that is, claims within claims). A claim with type OBJECT must contain at least one other claim (of any data type) within it and can contain one or more objects. Otherwise, claims with type OBJECT behave as other claims: they have a name and they are either required or not. All claims within the object are placed within the claims array for that claim. For claims of other data types, the claims array is empty.

Consider the following structure:

  • Claim 1 (object)

    • Claim 2

    • Claim 3 (object)

      • Claim 4

Claim 1 is an object that contains all the other claims in the structure, including claim 3, which is itself an object containing claim 4.

The API call to create a credential schema with this structure:

{
"claims": [
{
"array": false,
"claims": [
{
"array": false,
"claims": [],
"datatype": "STRING",
"key": "Claim 2",
"required": true
},
{
"array": false,
"claims": [
{
"array": false,
"claims": [],
"datatype": "STRING",
"key": "Claim 4",
"required": true
}
],
"datatype": "OBJECT",
"key": "Claim 3",
"required": true
}
],
"datatype": "OBJECT",
"key": "Claim 1",
"required": true
}
],
"format": "SDJWT",
"layoutType": "CARD",
"name": "Nested claims example",
"revocationMethod": "BITSTRINGSTATUSLIST",
"walletStorageType": "SOFTWARE"
}

Arrays

Claims can be made into arrays so multiple values can be input for the same key during issuance.

In the following example, a credential schema makes a claim of a phone number and passes true for the optional array value.

"claims": [
{
"array": true,
"claims": [],
"datatype": "NUMBER",
"key": "Phone number(s)",
"required": true
},
]

When issuing a credential with this schema, the issuer can add multiple phone numbers within the same claim.

Schema ID or "Document type"

The schema ID transmits information about the schema of a credential. For some credential formats you must specify the schemaId during schema creation, while for other formats the system auto-generates a schema ID.

Check the configuration of your chosen credential format for capabilities.features: REQUIRES_SCHEMA_ID. For those formats requiring a schema ID, further guidance is provided below.

ISO mdoc

Use the schemaId field to specify the credential's DocType. To issue ISO standard mDLs, for example, pass org.iso.18013.5.1.mDL as the schema ID during schema creation.

For more on DocTypes, see the mdocs guide.

SD-JWT VC

Use schemaId to specify the vct. According to the SD-JWT-VC specification:

the vct value must be a case-sensitive StringOrURI (see [RFC7519]) value serving as an identifier for the type of the SD-JWT VC

In some deployments, a URN is used to denote ecosystem-specific credential types much like a "DocType" for ISO mdoc credentials. The system enables the specification of either a URL or a URN:

  • URL (default): what you specify for schemaId is used to create a URL and published so that type metadata can be retrieved by external consumers of the credential. The system constructs the URL as follows:
{{base_url_of_system}}/ssi/v1/vct/{{organizationId}}/{{schemaId}}
  • URN: use externalSchema: true during credential schema creation to prevent the system from creating a URL. In this case the system populates the vct field of the credential with the value you assign for schemaId with no modifications.

For example, the current implementation of the EUDI Testing Issuer uses URNs for their schemas. To issue a PID to a EUDI wallet, your API call to create the schema should include this URN:

{
"claims": [
{
"claims": ["example"],
"datatype": "string",
"key": "example",
"required": true
}
],
"externalSchema": true, // Enable an external schema
"format": "SD_JWT_VC",
"layoutType": "CARD",
"name": "PID",
"organisationId": "{{YOUR_ORG_ID}}",
"revocationMethod": "TOKENSTATUSLIST",
"schemaId": "urn:eu.europa.ec.eudi:pid:1" // Use the predefined vct
}

This helps the EUDI wallet parse the schema as it is built to consume a set of predefined vcts.

VC barcodes

For the verification of W3C VC Barcodes, the credential types are pre-defined by the draft specification:

  • UtopiaEmploymentDocument
  • UtopiaDrivingLicense
  • IdentityCard

Specify which type of credential is to be verified by passing one of the types as the schemaId during schema creation.

For more on verifying physical credentials, see the VC Barcodes guide.

All other formats

When creating a schema for credential formats which do not require a schema ID, the system generates a globally unique URI for each credential schema.

When receiving a credential, the system looks for the schema ID as defined by the issuer. If the system finds the schema ID, it uses it. If no schema ID is found, one is generated.

schemaType

Credential schemas are useful for defining the structure of the credential and providing verifiers with a means to check that the data of a credential conforms to the schema published by the issuer.

To that end, the system assigns a schema type for all created credential schemas, described below.

ISO mdoc

Whether creating a schema or receiving credentials, all mdoc credentials are assigned schema type mdoc.

All other formats

When creating a schema, the system assigns ProcivisOneSchema2024 as the schema type.

When receiving a credential, the system looks for the schema type as defined by the issuer. If the system finds the schema type, it uses it. In cases where the system is unable to find the schema type, it assigns FallbackSchema2024.

Credential design

When creating credential schemas, use layoutType and layoutProperties to design the visual appearance of the resulting credentials.

The design properties are embedded into the credential itself. The following specifies where the design properties are found within the credential itself:

  • W3C VCs - in the metadata of the credential.
  • ISO mdocs - embedded in their own namespace, ch.procivis.mdoc_layout.1.
  • SD-JWT VCs - the system supports the simple render method, including background color and text color; all other supported design elements are found in the layout properties at the root level. The SVG template rendering method is not supported.

For any given credential format, credential design must be enabled in the configuration or the design properties will not be passable. The embedLayoutProperties param of credential formats defaults to false.

Creating a credential design is optional; if no design values are passed, a design of type card is auto-generated from the credential name. The credential schema of issued credentials, including this design information, is published and the resulting URL is available in the credentialSchema field of the credential. This allows for digital wallets to obtain and display the credential with the desired appearance.

Layout type

The layout type determines both the structure of how the credential will appear and the options available in layoutProperties for further customization.

Supported layout types:

  • CARD - Default layout type if no value is passed; credentials with this layout type resemble a physical credential one would find in a physical wallet.

  • DOCUMENT* - Credentials with this layout type resemble a paper document with structured text fields and list elements.

  • SINGLE_ATTRIBUTE* - Credentials with this layout type display a credential name and a single attribute in a simple tab.

* (in development)

Layout properties - Card

  • background - Choose one of:

    • color - Choose a solid color for the background of the credential; accepts any HTML value (hex, predefined, or rbga format).

    • image - Choose an image for the background of the credential; accepts .jpg or .png. Optimized size: 722x440 px.

  • logo - Choose one of:

    • backgroundColor and fontColor - Choose a solid color for the background of the logo and a font color for the logo text; accepts any HTML value (hex, predefined, or rbga format). Logo text is an auto-generated shortened version of the credential name.

    • image - Choose an image for the square logo of the credential; accepts .jpg or .png. Optimized size: 88x88 px.

  • primaryAttribute - Specify a primary attribute for the credential. The primary attribute is displayed directly underneath the credential name in both credential list and credential detail views.

  • secondaryAttribute - Specify a second attribute from the credential to be shown alongside the primary attribute.

  • pictureAttribute - Display a picture from the credential. Specify the attribute of the picture.

  • code - Display a scannable code from the credential. Specify the attribute to encode and the type of code to display. Note that this encoding is not verifiable, but can still be useful for some implementations such as bridging legacy systems.

    • Supported code types: [BARCODE, MRZ, QR_CODE]

Request a wallet storage type

As an issuer, you can request that the holder's wallet use a key stored with a particular technology to sign the credential during issuance.

The type of key storage used by the holder's wallet influences the security of the credential and the assurance the verifier has that the credential being presented is securely bound to the person presenting it. It also impacts user convenience.

Use the walletStorageType param to specify which type of storage the wallet should use.

Wallet behavior

For wallets supporting this feature:

  • If no value is passed, the wallet is free to choose a key to sign the issuance.

  • If a value is passed, the wallet will only accept and sign the issuance with the specified wallet storage type. If the specified type is not enabled in the wallet then the credential issuance will fail. This could be because the holder's device is not equipped with the needed hardware or because the storage type is not enabled in the wallet's configuration.

Options

You can request:

  • SOFTWARE
    • Keys are stored and managed by the wallet software, and protected by standard encryption.
    • Easy to deploy and manage. Keys can be backed up, recovered, and transferred to new devices.
    • Vulnerable to software attacks, and to physical attacks if attacker has access to the device.
  • HARDWARE
    • Keys are stored on and protected by tamper-resistant hardware on the holder's device.
    • Resistant to software attacks.
    • Keys are bound to one device. The verifier can be assured the credential was issued to the same device that is presenting it.
    • If the holder loses their device or upgrades to a new device, the credentials must be reissued to the new device.
  • REMOTE_SECURE_ELEMENT
    • Keys are stored on and protected by tamper-resistant hardware in a data center.
    • A secure link is established between the holder's device and the HSM. The user must input a PIN code or use biometrics each time they use a key.
    • If the holder loses their device or upgrades to a new device, the data is still protected in the HSM and a link to a new device can be established, recovering the holder's data.

Consider the required level of security and assurance needed for the use case, and balance against cost and convenience.

Limitations

  • This feature is not part of a standard protocol and is not necessarily enforced by other wallets. Wallets from other vendors could ignore the requirement for a certain key type.
  • During proof schema creation, the system does not allow combining credentials which use different key storage types. This is because the holder's wallet signs the presentation with one key and that key must match the key used to sign the credential during issuance. For proof requests with multiple credentials, all credentials must have the same walletStorageType. See the proof schemas guide for more information.

Import credential schemas to mobile verifiers

Credential schemas can be imported to mobile verifiers, enabling mobile verifiers to create their own proof schemas.

Call the Share credential schema endpoint (for Core or Desk) to generate a URL. The mobile verifier then makes an HTTP request to preview the credential schema. Call the Import credential schema (for Core) to import the credential schema.

Proof schemas can also be imported directly by mobile verifiers. See the importing proof schemas guide.