Issue ISO 23220-4 Photo ID as mDoc
A Photo ID is a digital identity credential that carries a holder’s core identity data together with a portrait, serving as a general-purpose mobile identity document (rather than a sector-specific one such as a driving licence). It follows the ISO/IEC TS 23220-4 Photo ID profile, which defines the doctype org.iso.23220.photoid.1 and reuses the generic eID building blocks from ISO/IEC TS 23220-2, issued here in the mdoc format.
Creating issuer root X509 certificate
Before you can create the credential template for Photo ID issuance, you need to set up an issuer root x509 certificate with a P-256 key.
The certificates guide contains detailed guidance on creating a certificate. We recommend creating your initial certificate through the dashboard.
Alternatively, if your issuer certificate needs to be signed by an external certificate authority, you can create a certificate signing request and import the externally signed certificate into Paradym.
Creating the credential template
We recommend creating this template through the API, as it allows you to exactly copy the payload as defined below. See Interacting with the API, the API reference for Create mDoc credential template , or the Issue credentials guide for more information on creating credential templates.
The Photo ID profile organises data across three namespaces:
org.iso.23220.1— generic eID data elements defined in ISO/IEC TS 23220-2 (Table C.1), plus theHBCHVholder-binding element (Table C.7).org.iso.23220.photoid.1— data elements specifically defined for Photo ID (Table C.2).org.iso.23220.datagroups.1— ICAO 9303 part 10 data groups (Table C.3). When used, each value shall be identical to the byte value of the corresponding eMRTD data group.
The type (doctype) is org.iso.23220.photoid.1. The version suffix 1 distinguishes the first version of the Photo ID credential from any future version. Issuers may add national, state/territory or sectoral namespaces (for example org.iso.23220.photoid.US-IA.1); those are out of scope of this base template.
{
"name": "Photo ID",
"description": "Photo ID credential compliant with the ISO/IEC TS 23220-4 Photo ID profile (Annex C)",
"issuer": {
"signer": "certificate",
"keyType": "P-256"
},
"background": {
"color": "#F1F2F0"
},
"text": {
"color": "#2F3544"
},
"validUntil": {
"start": "issuance",
"future": {
"years": 1
}
},
"type": "org.iso.23220.photoid.1",
"attributes": {
"org.iso.23220.1": {
"type": "object",
"properties": {
"family_name": {
"type": "string",
"name": "Family Name",
"description": "Last name, surname, or primary identifier of the Photo ID holder",
"required": true
},
"given_name": {
"type": "string",
"name": "Given Name",
"description": "First name(s), other name(s), or secondary identifier of the Photo ID holder",
"required": true
},
"family_name_viz": {
"type": "string",
"name": "Family Name (VIZ)",
"description": "Family name as defined for the visual inspection zone (VIZ) in ICAO 9303",
"required": false
},
"given_name_viz": {
"type": "string",
"name": "Given Name (VIZ)",
"description": "Given name as defined for the visual inspection zone (VIZ) in ICAO 9303",
"required": false
},
"birth_date": {
"type": "date",
"name": "Date of Birth",
"description": "Day, month and year on which the Photo ID holder was born (full-date format)",
"required": true
},
"portrait": {
"type": "binary",
"name": "Portrait of Photo ID Holder",
"description": "A reproduction of the Photo ID holder's portrait (binary image data)",
"required": true
},
"enrolment_portrait_image": {
"type": "binary",
"name": "Enrolment Portrait Image",
"description": "Portrait image captured at enrolment of the Photo ID holder",
"required": false
},
"issue_date": {
"type": "date",
"name": "Date of Issue",
"description": "Date when the Photo ID was issued",
"required": true
},
"expiry_date": {
"type": "date",
"name": "Date of Expiry",
"description": "Date when the Photo ID expires",
"required": true
},
"issuing_authority": {
"type": "string",
"name": "Issuing Authority",
"description": "Name of the issuing authority",
"required": true
},
"issuing_country": {
"type": "string",
"name": "Issuing Country",
"description": "Alpha-2 country code of the issuing authority's country or territory",
"required": true
},
"age_over_18": {
"type": "boolean",
"name": "Age Over 18",
"description": "Whether the Photo ID holder is 18 years old or older",
"required": true
},
"age_in_years": {
"type": "number",
"name": "Age in Years",
"description": "The age of the Photo ID holder in years (recommended)",
"required": false
},
"age_birth_year": {
"type": "number",
"name": "Year of Birth",
"description": "The year when the Photo ID holder was born (recommended)",
"required": false
},
"age_over_13": {
"type": "boolean",
"name": "Age Over 13",
"description": "Instance of age_over_NN: whether the holder is 13 years old or older",
"required": false
},
"age_over_16": {
"type": "boolean",
"name": "Age Over 16",
"description": "Instance of age_over_NN: whether the holder is 16 years old or older",
"required": false
},
"age_over_21": {
"type": "boolean",
"name": "Age Over 21",
"description": "Instance of age_over_NN: whether the holder is 21 years old or older",
"required": false
},
"age_over_65": {
"type": "boolean",
"name": "Age Over 65",
"description": "Instance of age_over_NN: whether the holder is 65 years old or older",
"required": false
},
"portrait_capture_date": {
"type": "date",
"name": "Portrait Image Timestamp",
"description": "Date when the portrait image was captured",
"required": false
},
"birthplace": {
"type": "string",
"name": "Place of Birth",
"description": "Place where the Photo ID holder was born",
"required": false
},
"name_at_birth": {
"type": "string",
"name": "Name at Birth",
"description": "Name of the Photo ID holder at birth",
"required": false
},
"resident_address": {
"type": "string",
"name": "Resident Address",
"description": "The place where the Photo ID holder resides and/or may be contacted",
"required": false
},
"resident_city": {
"type": "string",
"name": "Resident City",
"description": "The city where the Photo ID holder lives",
"required": false
},
"resident_postal_code": {
"type": "string",
"name": "Resident Postal Code",
"description": "The postal code where the Photo ID holder lives",
"required": false
},
"resident_country": {
"type": "string",
"name": "Resident Country",
"description": "The country where the Photo ID holder lives as a two letter country code",
"required": false
},
"resident_city_latin1": {
"type": "string",
"name": "Resident City (latin1)",
"description": "The city where the Photo ID holder lives, using the latin1 character set",
"required": false
},
"sex": {
"type": "number",
"name": "Sex",
"description": "Photo ID holder's sex using values as defined in ISO/IEC 5218. Value 9 shall be used for X",
"required": false
},
"nationality": {
"type": "string",
"name": "Nationality",
"description": "Nationality of the Photo ID holder as a two letter country code (alpha-2 code)",
"required": false
},
"document_number": {
"type": "string",
"name": "Document Number",
"description": "The document number assigned by the issuing authority",
"required": false
},
"issuing_subdivision": {
"type": "string",
"name": "Issuing Subdivision",
"description": "Country subdivision code of the jurisdiction that issued the Photo ID (ISO 3166-2)",
"required": false
},
"family_name_latin1": {
"type": "string",
"name": "Family Name (latin1)",
"description": "The family name of the Photo ID holder using the latin1 character set",
"required": false
},
"given_name_latin1": {
"type": "string",
"name": "Given Name (latin1)",
"description": "The given name of the Photo ID holder using the latin1 character set",
"required": false
},
"HBCHV": {
"type": "number",
"name": "Holder-Bound Credential Holder Verification",
"description": "Credential holder verification with biometric match over a reference authorized by the issuing authority. Only include when the IA elects to and the biometric subsystem requirements from the Photo ID profile (max FAR 1 in 10000, IAPAR < 0.15) can be met. The value is the key identifier used to verify the response",
"required": false
}
}
},
"org.iso.23220.photoid.1": {
"type": "object",
"properties": {
"person_id": {
"type": "string",
"name": "Person Identifier",
"description": "Person identifier of the Photo ID holder",
"required": false
},
"birth_country": {
"type": "string",
"name": "Country of Birth",
"description": "The country where the Photo ID holder was born, as an alpha-2 country code per ISO 3166-1",
"required": false
},
"birth_state": {
"type": "string",
"name": "State of Birth",
"description": "The state, province, district or local area where the Photo ID holder was born",
"required": false
},
"birth_city": {
"type": "string",
"name": "City of Birth",
"description": "The municipality, city, town or village where the Photo ID holder was born",
"required": false
},
"administrative_number": {
"type": "string",
"name": "Administrative Number",
"description": "A number assigned by the issuer for audit control or other purposes",
"required": false
},
"resident_street": {
"type": "string",
"name": "Resident Street",
"description": "The name of the street where the Photo ID holder currently resides",
"required": false
},
"resident_house_number": {
"type": "string",
"name": "Resident House Number",
"description": "The house number where the Photo ID holder currently resides, including any affix or suffix",
"required": false
},
"travel_document_type": {
"type": "string",
"name": "Travel Document Type",
"description": "Identifier of the type of source document if associated to or derived from a travel document (e.g. the two MRZ letters per ICAO 9303). Conditional: shall be present if dg1 in org.iso.23220.datagroups.1 exists, optional otherwise",
"required": false
},
"travel_document_number": {
"type": "string",
"name": "Travel Document Number",
"description": "The number of the travel document to which the Photo ID is associated (if associated or derived from a travel document)",
"required": false
},
"resident_state": {
"type": "string",
"name": "Resident State/Province/District",
"description": "The state/province/district where the holder lives. Uses the latin1 character set, maximum length 150 characters",
"required": false
},
"travel_document_mrz": {
"type": "string",
"name": "Travel Document MRZ",
"description": "Machine readable zone as the text printed on the physical document. Conditional: shall be present if dg1 in org.iso.23220.datagroups.1 exists, optional otherwise",
"required": false
}
}
},
"org.iso.23220.datagroups.1": {
"type": "object",
"properties": {
"version": {
"type": "string",
"name": "Version",
"description": "Version of the data groups namespace",
"required": false
},
"dg1": {
"type": "binary",
"name": "Data Group 1",
"description": "Biographic data recorded in the MRZ. Conditional: shall be present when this namespace is used",
"required": false
},
"dg2": {
"type": "binary",
"name": "Data Group 2",
"description": "Reference portrait (encoded face). Conditional: shall be present when this namespace is used",
"required": false
},
"dg3": {
"type": "binary",
"name": "Data Group 3",
"description": "Encoded fingers",
"required": false
},
"dg4": {
"type": "binary",
"name": "Data Group 4",
"description": "Encoded eye(s)",
"required": false
},
"dg5": {
"type": "binary",
"name": "Data Group 5",
"description": "Displayed portrait",
"required": false
},
"dg6": {
"type": "binary",
"name": "Data Group 6",
"description": "Reserved for future use",
"required": false
},
"dg7": {
"type": "binary",
"name": "Data Group 7",
"description": "Displayed signature or usual mark",
"required": false
},
"dg8": {
"type": "binary",
"name": "Data Group 8",
"description": "Data feature(s)",
"required": false
},
"dg9": {
"type": "binary",
"name": "Data Group 9",
"description": "Structure feature(s)",
"required": false
},
"dg10": {
"type": "binary",
"name": "Data Group 10",
"description": "Substance feature(s)",
"required": false
},
"dg11": {
"type": "binary",
"name": "Data Group 11",
"description": "Additional personal detail(s)",
"required": false
},
"dg12": {
"type": "binary",
"name": "Data Group 12",
"description": "Additional document detail(s)",
"required": false
},
"dg13": {
"type": "binary",
"name": "Data Group 13",
"description": "Optional detail(s)",
"required": false
},
"dg14": {
"type": "binary",
"name": "Data Group 14",
"description": "Security options",
"required": false
},
"dg15": {
"type": "binary",
"name": "Data Group 15",
"description": "Active authentication public key info",
"required": false
},
"dg16": {
"type": "binary",
"name": "Data Group 16",
"description": "Person(s) to notify",
"required": false
},
"sod": {
"type": "binary",
"name": "Security Object Data",
"description": "Security Object Data. Conditional: shall be present when this namespace is used",
"required": false
}
}
}
}
}Issuing a sample credential
Once you have created the template, you can test the issuance with a sample credential. The creation of the credential template should have returned an id, make sure to set the value of credentialTemplateId to this id in the payload.
The portrait value below is a base64-encoded JPEG of a sample portrait that you can use directly to test issuance. In practice this is a base64-encoded JPEG (or JPEG2000) of the holder’s portrait, exactly as for an mDL portrait. The ICAO data group namespace (org.iso.23220.datagroups.1) is omitted from this sample for readability; populate it only when issuing from an eMRTD, using the byte values of the corresponding data groups.
You can issue the credential using the Create OpenID4VC credential offer endpoint. You can read more on using a credential template in the issue credentials guide.
To receive the credential, you can use the Paradym Wallet (see Integrating with a Holder Wallet).
{
"credentials": [
{
"credentialTemplateId": "<CREDENTIAL_TEMPLATE_ID>",
"attributes": {
"org.iso.23220.1": {
"family_name": "van der Berg",
"given_name": "Emma Charlotte",
"family_name_viz": "VAN DER BERG",
"given_name_viz": "EMMA CHARLOTTE",
"birth_date": "1995-03-15",
"portrait": "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",
"issue_date": "2024-09-01",
"expiry_date": "2029-09-01",
"issuing_authority": "Gemeente Amsterdam (Demo)",
"issuing_country": "NL",
"age_over_18": true,
"age_in_years": 30,
"age_birth_year": 1995,
"age_over_16": true,
"age_over_21": true,
"age_over_65": false,
"portrait_capture_date": "2024-08-30",
"birthplace": "Amsterdam, Netherlands",
"resident_address": "Prinsengracht 263, 1016 GV Amsterdam",
"resident_city": "Amsterdam",
"resident_postal_code": "1016 GV",
"resident_country": "NL",
"sex": 2,
"nationality": "NL",
"document_number": "NL-PHOTOID-987654321",
"issuing_subdivision": "NL-NH"
},
"org.iso.23220.photoid.1": {
"person_id": "NL-PERSON-123456789",
"birth_country": "NL",
"birth_state": "Noord-Holland",
"birth_city": "Amsterdam",
"administrative_number": "ADM2024090012345",
"resident_street": "Prinsengracht",
"resident_house_number": "263",
"resident_state": "Noord-Holland"
}
}
}
]
}Presentation template
If you want to verify a Photo ID credential, use the presentation template payload, or select it as a pre-made template in the dashboard.