A JavaScript library that simplifies requesting mobile IDs built on top of the new W3C Digital Credentials API. See it in action here, and consider sponsoring this project or least giving it a shoutout if you feel it's helped in any way ⭐
- Cross-platform: Works in both browser and Node.js environments
- Protocol Support: Supports OpenID4VP and ISO mDoc protocols
- Document Types: Supports multiple document types including Mobile Driver's License, Photo ID, EU Personal ID, and Japan My Number Card
- Security: Includes nonce generation, timeouts, and trusted issuer verification
npm install id-verifierimport {
Verifier,
generateNonce,
generateJWK,
DocumentType,
Claim
} from 'id-verifier';
try {
const verifier = new Verifier();
// Generate security parameters
const nonce = generateNonce();
const jwk = await generateJWK();
// Create credentials request
const requestParams = verifier.createCredentialsRequest({
documentTypes: [DocumentType.MOBILE_DRIVERS_LICENSE],
claims: [
Claim.GIVEN_NAME,
Claim.FAMILY_NAME,
Claim.AGE_OVER_21
],
nonce,
jwk
});
// Request credentials
const credentials = await verifier.requestCredentials(requestParams);
// Process and verify the credentials
const result = await verifier.processCredentials(credentials, {
nonce,
jwk,
origin: window.location.origin
});
console.log('Credentials processed successfully!');
console.log('Available claims:', result.claims);
console.log('Trusted:', result.trusted);
console.log('Valid:', result.valid);
} catch (error) {
console.error('Credential request failed:', error.message);
}While this example does run on the frontend, it is strongly encouraged to create the credentials request and process the credentials response on your backend. The generated security nonce and jwk should stay on your backend
Supported document types:
MOBILE_DRIVERS_LICENSE- Mobile Driver's License (ISO 18013-5 mDL)PHOTO_ID- Photo ID (ISO 23220)EU_PERSONAL_ID- EU Personal ID (European Digital Identity)JAPAN_MY_NUMBER_CARD- Japan My Number Card
Supported claim fields that can be requested:
GIVEN_NAME- Given nameFAMILY_NAME- Family nameBIRTH_DATE- Birth dateBIRTH_YEAR- Birth yearAGE- AgeAGE_OVER_18- Age over 18 verificationAGE_OVER_21- Age over 21 verificationSEX- Sex/GenderHEIGHT- HeightWEIGHT- WeightEYE_COLOR- Eye colorHAIR_COLOR- Hair colorADDRESS- AddressCITY- CitySTATE- State/ProvincePOSTAL_CODE- Postal codeCOUNTRY- CountryNATIONALITY- NationalityPLACE_OF_BIRTH- Place of birthDOCUMENT_NUMBER- Document numberISSUING_AUTHORITY- Issuing authorityISSUING_COUNTRY- Issuing countryISSUING_JURISDICTION- Issuing jurisdictionISSUE_DATE- Issue dateEXPIRY_DATE- Expiry dateDRIVING_PRIVILEGES- Driving privilegesPORTRAIT- Portrait photoSIGNATURE- Signature
Stable string constants for processedDocuments[].invalidReasons, used when a document fails cryptographic or data-integrity verification.
| Constant | Value |
|---|---|
InvalidReason.MSO_NOT_YET_VALID |
MSO is not yet valid |
InvalidReason.MSO_EXPIRED |
MSO is expired |
InvalidReason.ISSUER_AUTH_SIGNATURE_INVALID |
IssuerAuth signature verification failed |
InvalidReason.DOCUMENT_SIGNER_CERTIFICATE_MISSING |
Document signer certificate is missing from IssuerAuth x5chain |
InvalidReason.DEVICE_AUTH_FAILED |
Failed to verify device authentication |
InvalidReason.CLAIM_DIGEST_MISMATCH |
Claim digest does not match IssuerAuth value digest |
Stable string constants for processedDocuments[].untrustedReasons, used when issuer trust evaluation fails.
| Constant | Value |
|---|---|
UntrustedReason.DOCUMENT_SIGNER_CERTIFICATE_MISSING |
Document signer certificate is required to determine issuer trust |
UntrustedReason.DOCUMENT_SIGNER_CERTIFICATE_AKI_MISSING |
Document signer certificate does not contain an Authority Key Identifier |
UntrustedReason.ISSUER_FETCH_FAILED |
Unable to retrieve issuer from trusted issuer registry |
UntrustedReason.ISSUER_CERTIFICATE_NOT_FOUND |
No trusted issuer certificate found to validate the document signer certificate |
UntrustedReason.ISSUER_CERTIFICATE_NOT_IN_TRUST_LISTS |
Issuer certificate is not trusted by the requested trust lists |
UntrustedReason.DOCUMENT_SIGNER_CERTIFICATE_REVOKED |
Document signer certificate has been revoked by CRL |
Creates an ID verifier with optional verification configuration.
Constructor options:
registry(Object): trusted-issuer-registry configurationenabled(boolean): Whether to use the issuer registry for trust evaluation (default: true)trustLists(Array): Names of registry trust lists to use for determining trust (default: all available)
issuerCertificates(Array): Issuer certificates supplied directly by the verifier (accepted for future use, not used yet)crl(Object): CRL checking configurationenabled(boolean): Whether to check document signer certificate CRLs for certificate revocation (default: false)timeout(number): CRL request timeout in milliseconds (default: 5000)cache(Object): CRL cache configurationenabled(boolean): Whether to cache CRL fetch results in memory by URL (default: true)ttl(number): CRL cache TTL in milliseconds (default: 86400000)
Registry trust lists are sourced from the trusted-issuer-registry. Current values are aamva_dts and uv at the time of writing.
CRL checking affects whether a digital credential is trusted and is performed on a best-effort basis. CRLs that cannot be fetched or processed do not throw an error and do not impact trust.
Example:
const verifier = new Verifier({
registry: {
enabled: true,
trustLists: ['uv']
},
issuerCertificates: [],
crl: {
enabled: true,
timeout: 5000,
cache: {
enabled: true,
ttl: 86400000
}
}
});Generates a cryptographically secure nonce for request security. Meant for backend use
Returns: String - Hex string with 128 bits of entropy
Example:
const nonce = generateNonce();Generates a JSON Web Key using the P-256 curve for encryption. Meant for backend use
Returns: Promise - Promise that resolves to the JWK
Example:
const jwk = await generateJWK();Creates request parameters for digital credential verification. Meant for backend use
Parameters:
options(Object):documentTypes(Array): Type(s) of documents to request (default:[DocumentType.MOBILE_DRIVERS_LICENSE])claims(Array): Array of claim fields fromClaimto request (default:[])nonce(string): Security nonce (required)jwk(Object): JSON Web Key for encryption (required)
Returns: Object compatible with Digital Credentials API
Example:
const params = verifier.createCredentialsRequest({
documentTypes: [DocumentType.MOBILE_DRIVERS_LICENSE, DocumentType.PHOTO_ID],
claims: [
Claim.GIVEN_NAME,
Claim.FAMILY_NAME,
Claim.AGE_OVER_21,
Claim.ADDRESS
],
nonce: nonce,
jwk: jwk
});Requests digital credentials from the user (browser-only)
Parameters:
requestParams(Object): Request parameters fromverifier.createCredentialsRequestoptions(Object):timeout(number): Request timeout in milliseconds (default: 300000)
Returns: Promise that resolves to credential data
Example:
const credentials = await verifier.requestCredentials(requestParams, {
timeout: 600000 // 10 minutes
});Processes and verifies a digital credential response. Meant for backend use
Parameters:
credentials(Object): The credentials response fromverifier.requestCredentialsparams(Object):nonce(string): The nonce from the original request (required)jwk(Object): The JWK used to encrypt the request (required)origin(string): The origin of the request (required)
Returns: Promise that resolves to verification result
Example:
const result = await verifier.processCredentials(credentials, {
nonce,
jwk,
origin: window.location.origin
});The verifier.processCredentials function returns an object with the following structure:
Success Response:
{
"claims": {
"given_name": "Erika",
"family_name": "Mustermann",
"age_over_21": true
},
"valid": true,
"trusted": true,
"processedDocuments": [
{
"claims": {
"given_name": "Erika",
"family_name": "Mustermann",
"age_over_21": true
},
"valid": true,
"trusted": true,
"document": "...", // Full document data
"issuer": {
"issuer_id": "x509_aki:q2Ub4FbCkFPx3X9s5Ie-aN5gyfU",
"entity_type": "government",
"entity_metadata": {
"country": "US",
"region": "VA",
"government_level": "state",
"official_name": "Multipaz"
},
"display": {
"name": "Multipaz IACA Test",
"logo": "https://avatars.githubusercontent.com/u/131064301",
"description": "Official issuer of mobile driver's licenses and proof of age credentials in Multipaz."
},
"signature": "MEUCIQDrmlcELKPJHKiwlb/90zNPoiweAry0tF+j/LA21wxlWAIgNIeWgJc3dijrwrjRmMjJwecxif4hMi87zD55k7DOLLM=",
"certificate": {
"data": "-----BEGIN CERTIFICATE-----\n...",
"format": "pem",
"trust_lists": ["uv"]
}
}
}
],
"sessionTranscript": "..." // Session transcript data
}Response Fields:
claims(Object): Combined claims from all processed documentsvalid(Boolean): Whether all documents are validtrusted(Boolean): Whether all documents are from trusted issuersprocessedDocuments(Array): Array of individual processed documentsclaims(Object): Claims extracted from this specific documentvalid(Boolean): Whether this document is validtrusted(Boolean): Whether this document's issuer is trusted by one of the given trust listsinvalidReasons(Array): Reasons this document is invalid, present only whenvalidis falseuntrustedReasons(Array): Reasons this document is untrusted, present only whentrustedis falsedocument(Object): Full unencrypted document dataissuer(Object): Issuer information sourced from the trusted-issuer-registry,nullwhen no trusted issuer certificate is available
sessionTranscript(Object): Session transcript that was used for decryption/verification
This library requires browsers that support the Digital Credentials API. Currently, this is an experimental API and may not be available in all browsers.
- Have an android device handy or run an android emulator
- Download a wallet that allows you to create test credentials. Here is one option
- Go to chrome://flags in your browser
- Enable DigitalCredentials
- Go to our demo page
- Tap on "Request Credentials"
- Have an iPhone or simulator running iOS 26 or later
- If using a real iphone, make sure you've added your ID to your wallet if supported
- If your ID is not currently supported or you don't have an iphone, the simulator has test credentials preinstalled
- Go to the device's Settings -> Apps -> Safari -> Advanced -> Feature Flags
- Enabled the Digital Credentials API
- Go to our demo page
- Tap on "Request Credentials"
Test credentials won't present issuer information, however the demo page includes a "Use Test Issuer Registry" option that uses trusted-issuer-registry's test issuer dataset instead of its normal issuer dataset. Test wallet providers are more than welcome to add their public certificates to the repo's test data. In the near future we will allow you to supply your own list of trusted credentials to the library, but until then, c'est la vie
Contributions are welcome! Please feel free to submit a Pull Request (submit an issue first please)
To help others find this repo, please consider giving us a star ⭐
This project is licensed under the Mozilla Public License 2.0