A JavaScript library that simplifies requesting and verifying mobile IDs. See it in action here, and consider sponsoring this project or at 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, EU Age Verification, 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.createWebCredentialsRequest({
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)EU_AGE_VERIFICATION- EU Age VerificationJAPAN_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
Document types omit unsupported claims from requests. See the claim mappings for the claims supported by each document type.
Supported trust lists that can be used in trustLists:
UV- Issuers trusted by Universal VerifyAAMVA_DTS- Issuers trusted by the American Association of Motor Vehicle Administrators
Controls document signer certificate revocation checks through CRLs:
SKIP- Skip revocation checks (default)BEST_EFFORT- Reject confirmed revocation; allow undetermined statusREQUIRED- Reject confirmed revocation and undetermined status
Failure codes for processedDocuments[].invalidReasons, used when a document fails cryptographic or data-integrity verification.
MSO_NOT_YET_VALID- MSO is not yet validMSO_EXPIRED- MSO is expiredISSUER_AUTH_SIGNATURE_INVALID- IssuerAuth signature verification failedDOCUMENT_SIGNER_CERTIFICATE_MISSING- Document signer certificate is missing from IssuerAuth x5chainDEVICE_AUTH_FAILED- Failed to verify device authenticationCLAIM_DIGEST_MISMATCH- Claim digest does not match IssuerAuth value digest
Trust failure codes from trusted-issuer-registry, used in processedDocuments[].untrustedReasons and processedDocuments[].issuer.certificates[].untrustedReasons.
CERTIFICATE_MISSING- Document signer certificate is required to determine issuer trustCERTIFICATE_AKI_MISSING- Document signer certificate does not contain an Authority Key IdentifierCERTIFICATE_NOT_YET_VALID- Document signer certificate is not yet validCERTIFICATE_EXPIRED- Document signer certificate is expiredCERTIFICATE_REVOKED- Document signer certificate has been revoked by CRLREVOCATION_STATUS_UNDETERMINED- Unable to determine document signer certificate revocation statusISSUER_FETCH_FAILED- Unable to retrieve issuer from trusted issuer registryISSUER_CERTIFICATE_NOT_FOUND- No trusted issuer certificate found to validate the document signer certificateCERTIFICATE_SIGNATURE_VERIFICATION_FAILED- Document signer certificate signature could not be verified with the issuer certificateISSUER_CERTIFICATE_NOT_YET_VALID- Issuer certificate is not yet validISSUER_CERTIFICATE_EXPIRED- Issuer certificate is expiredISSUER_CERTIFICATE_NOT_IN_TRUST_LISTS- Issuer certificate is not trusted by the requested trust listsISSUER_MISSING_REQUIRED_TRUST_SCOPE- Issuer is not authorized for government-issued identity documents
Creates an ID verifier with optional verification configuration.
Constructor options:
trustLists(Array<string>): Registry trust lists to use for determining trust (default:TrustList.UVandTrustList.AAMVA_DTS). An empty array skips registry lookups and only looks at user providedtrustedIssuerCertificatestrustedIssuerRegistry(Object): Issuer certificate, revocation, and network configurationtrustedIssuerCertificates(Array<string|Object>): PEM-encoded X.509 issuer certificates trusted directly by the verifier for government-issued identity documents. Use this when you want to trust issuers not listed in the trusted-issuer-registry. Entries can also be objects with adataPEM string and optionalformat,entity_type,entity_metadata, anddisplayfields, as described in the registry constructor documentation.revocationCheckMode(string): CRL checking mode fromRevocationCheckMode(default:RevocationCheckMode.SKIP)timeout(number): Timeout in milliseconds for each issuer, deprecation, or CRL request, including reading its response body (default: 10000)cacheEnabled(boolean): Whether to cache issuer, deprecation, and CRL responses in memory per verifier (default: true)cacheTTL(number): Cache lifetime 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.
Certificates passed through trustedIssuerRegistry.trustedIssuerCertificates will not be filtered out by trustLists. Their returned certificate metadata uses trust_lists: ['user_provided'].
Issuer trust always requires the government_issued_id scope. This scope is automatically added to user-provided certificates, preserving any existing scopes.
Example:
import { Verifier, TrustList, RevocationCheckMode } from 'id-verifier';
const verifier = new Verifier({
trustLists: [TrustList.UV],
trustedIssuerRegistry: {
trustedIssuerCertificates: [
'-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----',
// or pass in issuer objects
{
data: '-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----',
entity_type: 'government',
entity_metadata: { country: 'CA', region: 'QC' },
display: { name: 'Québec SAAQ' }
}
],
revocationCheckMode: RevocationCheckMode.BEST_EFFORT,
timeout: 10000,
cacheEnabled: true,
cacheTTL: 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<Object> - 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<string>): Type(s) of documents to request (default:[DocumentType.MOBILE_DRIVERS_LICENSE])claims(Array<string>): 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.createWebCredentialsRequest({
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.createWebCredentialsRequestoptions(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"
},
"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."
},
"trust_scopes": ["government_issued_id"],
"certificates": [
{
"data": "-----BEGIN CERTIFICATE-----\n...",
"format": "pem",
"trust_lists": ["uv"],
"trusted": true,
"revocationStatus": "not_checked"
}
]
}
}
],
"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 the document signer and at least one issuer certificate pass the requested trust checksinvalidReasons(Array<string>): Reasons this document is invalid, present only whenvalidis falseuntrustedReasons(Array<string>): Reasons this document is untrusted, present only whentrustedis falsedocument(Object): Full unencrypted document dataissuer(Object): Issuer metadata merged from user-provided certificates and the trusted-issuer-registry,nullwhen no issuer is foundtrust_scopes(Array<string>): Supported issuer scopescertificates(Array<Object>): All issuer certificates, each withdata,format,trust_lists,trusted, andrevocationStatus(not_checked,not_revoked, orrevoked). Untrusted certificates also includeuntrustedReasons
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
- If your ID is not currently supported in Google Wallet or you're using the emulator, download a wallet that allows you to create test credentials. Here is one option
- 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 Apple Wallet if supported
- If your ID is not currently supported in Apple Wallet or you don't have an iphone, the simulator has test credentials preinstalled
- Go to our demo page
- Tap on "Request Credentials"
Test credentials may use issuer certificates that are not in the trusted issuer registry. The demo page lets you paste PEM-encoded issuer certificates so you can trust those issuers directly while testing.
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