How to Issue Mobile Driver's Licenses (ISO/IEC 18013-5 mDLs) via OID4VCI with walt.id Enterprise
This guide provides a comprehensive walkthrough for issuing an mDL credential based on the ISO/IEC 18103-5 standard using the walt.id Enterprise Issuer API. The issuance process will utilize the OID4VCI protocol.
Enterprise Service Dependencies
To issue a credential, you need to have the following enterprise services setup:
- Issuer Service - Have a running issuer service. Setup instructions can be found here.
- KMS Service - Have a running KMS service. Setup instructions can be found here.
Preparing for Issuance: Key Components
The mobile driver's license (mDL) ecosystem builds on established PKI principles that employ X.509 digital certificates, while introducing domain-specific roles and data models. Its main components are:
- IACA — Issuing Authority Certification Authority: This is an authority that serves as the root of trust vouching for authorized credential issuers and is represented by a self-signed X.509 digital certificate that is published to verifiers.
- DS — Document Signer (Credential Issuer): This is the entity that issues and cryptographically signs mDL credential(s). It holds a private key and an X.509 digital certificate issued by an IACA. Typically, DS certificates are short-lived and are rotated periodically.
- The mDL Claims: The mDL is a verifiable credential that contains claims about the subject (holder), such as
name, birthdate and driving privileges. The ISO/IEC 18103-5 standard document
defines a set of mandatory fields (e.g.,
family_name
,birth_date
) that must be included in every mDL, as well as a set of optional fields (e.g.,age_over_NN
attestations,height
,weight
,sex
).
Example mDL Credential in JSON format:
{
"family_name": "Doe",
"given_name": "John",
"birth_date": "1986-03-22",
"issue_date": "2019-10-20",
"expiry_date": "2024-10-20",
"issuing_country": "AT",
"issuing_authority": "AT DMV",
"document_number": "123456789",
"portrait": [ 141, 12 ],
"driving_privileges": [
{
"vehicle_category_code": "A",
"issue_date": "2018-08-09",
"expiry_date": "2024-10-20"
},
{
"vehicle_category_code": "B",
"issue_date": "2017-02-23",
"expiry_date": "2024-10-20"
}
],
"un_distinguishing_sign": "AT"
}
Note: mDLs are encoded in CBOR, which is a binary format and is shown in JSON representation above for readability
purposes. Claims values that are encoded as JSON integer arrays, e.g., the portrait
claim's value, represent byte
arrays.
Issuing an mDL
In this section, we'll walk through the steps required to successfully issue an mDL using the Enterprise Stack Issuer API.
Note: At the moment, you can only use secp256r1
keys to issue mDLs.
Prerequisites
Before issuing mDLs, you need to have:
- IACA and Document Signer Certificates: The Enterprise Stack does not provide onboarding endpoints for IACA and Document Signer certificates. You need to obtain these certificates through external means or use the Community Stack onboarding functionality.
For IACA and Document Signer onboarding, you can:- Use the Community Stack mDL onboarding guide to generate the required certificates
- Import existing certificates into your Enterprise Stack key management system
- Use external PKI services to generate the required certificates
- Issuer Service Configuration: Ensure your issuer service is properly configured with the required mDL signing keys.
Step 1: Configure mDL Credential Type
First, ensure your issuer service supports the mDL credential type. When creating an issuer service, include the mDL configuration:
{
"type": "issuer",
"baseUrl": "https://your-issuer.example.com",
"kms": "your-kms-service",
"tokenKeyId": "your-signing-key",
"supportedCredentialTypes": {
"org.iso.18013.5.1.mDL": {
"format": "mso_mdoc",
"credentialDefinition": {
"type": ["org.iso.18013.5.1.mDL"]
},
"docType": "org.iso.18013.5.1.mDL"
}
}
}
Step 2: Issue an mDL Credential
Use the Enterprise Stack credential issuance endpoint to issue mDL credentials:
Endpoint: /v1/{target}/issuer-service-api/credentials/issue
| API Reference
Example Request
curl -X 'POST' \
'https://{orgID}.enterprise-sandbox.waltid.dev/v1/{target}/issuer-service-api/credentials/issue' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer {yourToken}' \
-d '{
"issuerKeyId": "your-signing-key-id",
"credentialConfigurationId": "org.iso.18013.5.1.mDL",
"credentialData": {
"issuerKeyId": "waltid.tenant2.kms1.secp-r1",
"credentialConfigurationId": "org.iso.18013.5.1.mDL",
"credentialData": {
"org.iso.18013.5.1": {
"family_name": "Doe",
"given_name": "John",
"birth_date": "1986-03-22",
"issue_date": "2019-10-20",
"expiry_date": "2024-10-20",
"issuing_country": "AT",
"issuing_authority": "AT DMV",
"document_number": "123456789",
"portrait": [
141,
182,
121,
111,
238,
50,
120,
94,
54,
111,
113,
13,
241,
12,
12
],
"driving_privileges": [
{
"vehicle_category_code": "A",
"issue_date": "2018-08-09",
"expiry_date": "2024-10-20"
},
{
"vehicle_category_code": "B",
"issue_date": "2017-02-23",
"expiry_date": "2024-10-20"
}
],
"un_distinguishing_sign": "AT"
}
},
"x5Chain": [
"-----BEGIN CERTIFICATE-----\nMIICCDCCAa2gAwIBAgIUDo8kr194t6sttt6KL3YcnMtcaYYwCgYIKoZIzj0EAwIwJDELMAkGA1UEBhMCVVMxFTATBgNVBAMMDEV4YW1wbGUgSUFDQTAeFw0yNTA1MjkwNzE4MzlaFw0yNjA4MjkwNzE4MzlaMCIxCzAJBgNVBAYTAlVTMRMwEQYDVQQDDApFeGFtcGxlIERTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEGWKpdL3jPoPJ5wKgSA+jxS2jgp+ZUDE6sIQbeB86vF0XfEDAf3r/FVyJXuYVCyVT95FCA/7mlJmI1/xuMygZ+qOBvjCBuzAfBgNVHSMEGDAWgBSMIxGx+iVN4rkOzoyo5aPk3HTUFDAdBgNVHQ4EFgQU7S49LSeg/e0onfT44FVbL/rSKnswDgYDVR0PAQH/BAQDAgeAMCMGA1UdEgQcMBqGGGh0dHBzOi8vaWFjYS5leGFtcGxlLmNvbTAVBgNVHSUBAf8ECzAJBgcogYxdBQECMC0GA1UdHwQmMCQwIqAgoB6GHGh0dHBzOi8vaWFjYS5leGFtcGxlLmNvbS9jcmwwCgYIKoZIzj0EAwIDSQAwRgIhAMuSq75BPBXXBWGtIMd57fhRqpKf3Yzl3ldDdoQsK2xEAiEA/dmWLMLiJPV3UzmQS5MUHtn611z0VlL/k3YAdaVJ51c=\n-----END CERTIFICATE-----\n"
]
}'
Path Parameters
orgID
: - When performing operations within an organization, it is essential to use the organization's Base URL or another valid host alias. For example, if your organization is namedtest
, your default Base URL will betest.enterprise-sandbox.walt.dev
when using the sandbox environment.target
: resourceIdentifier - The target indicates the organization + tenant + issuer service with which to execute the credential issuance ({organizationID}.{tenantID}.{issuerServiceID}
), e.g.waltid.tenant1.issuer1
Body
{
"issuerKeyId": "your-signing-key-id",
"credentialConfigurationId": "org.iso.18013.5.1.mDL",
"credentialData": {
"org.iso.18013.5.1": {
"family_name": "Doe",
"given_name": "John",
"birth_date": "1986-03-22",
"issue_date": "2019-10-20",
"expiry_date": "2024-10-20",
"issuing_country": "AT",
"issuing_authority": "AT DMV",
"document_number": "123456789",
"portrait": [
141,
182,
121,
111,
238,
50,
120,
94,
54,
111,
113,
13,
241,
12,
12
],
"driving_privileges": [
{
"vehicle_category_code": "A",
"issue_date": "2018-08-09",
"expiry_date": "2024-10-20"
},
{
"vehicle_category_code": "B",
"issue_date": "2017-02-23",
"expiry_date": "2024-10-20"
}
],
"un_distinguishing_sign": "AT"
}
},
"x5Chain": [
"-----BEGIN CERTIFICATE-----\nMIICCDCCAa2gAwIBAgIUDo8kr194t6sttt6KL3YcnMtcaYYwCgYIKoZIzj0EAwIwJDELMAkGA1UEBhMCVVMxFTATBgNVBAMMDEV4YW1wbGUgSUFDQTAeFw0yNTA1MjkwNzE4MzlaFw0yNjA4MjkwNzE4MzlaMCIxCzAJBgNVBAYTAlVTMRMwEQYDVQQDDApFeGFtcGxlIERTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEGWKpdL3jPoPJ5wKgSA+jxS2jgp+ZUDE6sIQbeB86vF0XfEDAf3r/FVyJXuYVCyVT95FCA/7mlJmI1/xuMygZ+qOBvjCBuzAfBgNVHSMEGDAWgBSMIxGx+iVN4rkOzoyo5aPk3HTUFDAdBgNVHQ4EFgQU7S49LSeg/e0onfT44FVbL/rSKnswDgYDVR0PAQH/BAQDAgeAMCMGA1UdEgQcMBqGGGh0dHBzOi8vaWFjYS5leGFtcGxlLmNvbTAVBgNVHSUBAf8ECzAJBgcogYxdBQECMC0GA1UdHwQmMCQwIqAgoB6GHGh0dHBzOi8vaWFjYS5leGFtcGxlLmNvbS9jcmwwCgYIKoZIzj0EAwIDSQAwRgIhAMuSq75BPBXXBWGtIMd57fhRqpKf3Yzl3ldDdoQsK2xEAiEA/dmWLMLiJPV3UzmQS5MUHtn611z0VlL/k3YAdaVJ51c=\n-----END CERTIFICATE-----\n"
]
}
Body Parameters
issuerKeyId
: String - The ID of the signing key to use for credential issuancecredentialConfigurationId
: String - Must be"org.iso.18013.5.1.mDL"
for mDL credentialscredentialData
: JSON - The mDL credential data containing all required and optional fieldsauthenticationMethod
: String - Authentication method for the issuance session (default:"PRE_AUTHORIZED"
)expiresInSeconds
: Number - Session expiration time in seconds (default: 300)x5Chain
: Array of Strings - Array of Strings - The X.509 certificate chain for the Document Signer, starting with the DS certificate.
Example Response
The issuance endpoint will return a credential offer URL that can be used to complete the issuance process:
openid-credential-offer://waltid.enterprise.test.waltid.cloud/?credential_offer_uri=https%3A%2F%2Fwaltid.enterprise.test.waltid.cloud%2Fv1%2Fwaltid.tenant2.issuer-mdl%2Fissuer-service-api%2Fopenid4vc%2Fdraft13%2Fcredential-offer%3Fid%3D38672f8b-bed0-4e29-b6db-c0e2580a7fa0
Step 4: Receive the Credential Offer
The created credential offer can now be embedded into a QR code for users to scan with their mobile wallet or pasted manually into the credential offer field of our web wallet.
Try It Out: Use our web wallet for a practical demonstration. After logging in, click the 'request credential' button and paste the received Offer URL into the text field below the camera.
🎉 Congratulations, you've issued a mDL using OID4VCI! 🎉