Validate National Identification Numbers
National identification numbers, also known as national IDs, are unique identification codes issued by governments to their citizens and residents. These codes are used for various purposes, such as taxation, healthcare, education, travel documentation, and account opening.
If you're building an API or application that accepts national IDs, it's essential to validate them accurately to maintain data quality and prevent fraudulent activities. This article outlines best practices for validating national IDs.
Check the number of digits
Most countries issue national IDs with a fixed number of digits, such as Brazil's CPF numbers with 11 digits or India's Aadhaar numbers with 12 digits. Validate that the input contains the exact number of digits for that country.
Verify the checksum to confirm the ID number is logically correct
Use checksum to verify (such as the Luhn algorithm) to validate the ID number. For example, the last two digits of an Indian Aadhaar number are check digits to validate the first 10 digits. Verify the checksum to confirm the ID number is logically correct.
Ensure the number passes country-specific validation
To conduct a comprehensive national ID validation, it's important to validate all country-specific requirements and thoroughly verify the ID. Many countries have additional validation checks for their IDs, including date ranges, location codes, prefixes, etc. For instance, South Korean citizen numbers issued before 2000 start with 1 or 2, while those issued after 2000 start with 6 or 7.
The following sections provide some country-specific validations.
American Samoa
Below is the National ID validation for American Samoa:
(^\d{3}-\d{2}-\d{4}$)|(^\d{4}$)|(^\d{9}$)
Argentina
Below is the Argentinian National ID validation:
(^\d{2}[.]?\d{3}[.]?\d{3}$)
OR
(^\d{7,8}[-]?\d$)
Australia
Below is the Australian National ID validation:
(^[A-Za-z\d]{8,11}$)Bangladesh
Below is the National ID validation for Bangladesh:
^\d{13}$
Belgium
Below is the Belgium National Registry Number validation:
^(?P<year>\d{2})(?P<month>\d{2})(?P<day>\d{2})(?P<seq>\d{3})(?P<check>\d)
(?P<year>(?:18|19)\d{2}|20\d{2})$
And here is the check digit validation logic:
# Validate check digit
check_digit = 89 - (year + month*2 + day*3 + int(groups['seq'])*7)
if check_digit % 11 != int(groups['check']):
print("Invalid ID")
return
# Ensure ID is in sorted order
prev_id = id_num[:9] + str(check_digit)
if prev_id >= id_num:
print("Invalid ID")
return
print("Valid ID")Brazil
Below is the Brazilian Cadastro de Pessoas Físicas (CPF) validation:
(^\d{3}\.\d{3}\.\d{3}\-\d{2}$)
OR
(^\d{11}$)
Canada
Below is the Canadian National Insurance Number validation:
(^\\d{3}[-\\s]?\\d{3}[-\\s]?\\d{3}$)
Chile
Below is the Rol Único Nacional (RUN) validation for Chile:
((^\d{1,2}[.]\d{3}[.]\d{3}[-][A-Za-z\d]$)
OR
(^\d{7,8}[-]?[A-Za-z\d]$)
China
Below is the the National ID validation for China:
^[a-zA-Z0-9]{18}$Colombia
Below is the the Colombian National ID validation:
(^[A-Za-z\d]{5,11}$)
Czech Republic
Below is the Czech Republic (Czechia) Rodné číslo National ID validation:
^([0-9]{2}[0-9]{2}(?:[0-5][0-9]|[68][0-9])(?:0[1-9]|[12][0-9]|3[01])|
([0-9]{4}[0-9]{2})[/][0-9]{2,4}$
And here is the checksum validation logic:
# Validate checksum
checksum = 0
for num in birth_date:
checksum += int(num)
if (checksum % 11) == 0 or 10:
multiplier = 1
elif (checksum % 11) == 1:
multiplier = 0
else:
multiplier = 11 - (checksum % 11)
expected = multiplier * sum(int(x) for x in national_id[-3:-1]) % 11
if int(national_id[-1]) == expected:
print("Valid ID")
else:
print("Invalid ID") Denmark
Below is the Danish National ID validation:
(^\d{6}[-]?\d{4}$)
Estonia
Below is the Estonian National ID validation:
(^\d\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12][0-9]|3[01])\d{3}\d$)
Finland
Below is the Finnish National ID validation:
(^(?:0[1-9]|[12][0-9]|3[01])(?:0[1-9]|1[0-2])\d{2}(?i:[-+ABCDEFUVWXY])\d{3}(?i)[\dA-FHJ-NPR-Y]$)
France
Below is the French INSEE validation:
^(?<dept_code>[01-8][0-9])(-(?<gender_code>[0-9][0-9])){2}(-(?<year_code>0[1-9]
|[1-9][0-9]))
(-(?<month_code>0[1-9]|1[0-2]))(-(?<day_code>[0-2][1-9]|[03][0-1]|10))
(-(?<serial>[0-9][0-9]))$
Germany
Below is the German Personalausweisnummer validation:
^(?:(?!000|474[0-7]|900[0-9])\d{9}|(?!000|474[0-7]|900[0-9])\d{10}(?=\d|X))$
Greece
Below is the Greek AMAT Identity Card Registration Number validation:
^(0[1-5][0-9])((([12][0-9])|(0[0-9]))([0-9]{6}|[0]{1,}[0-9]{5}))([0-9]{1}|[XxAa])$
And here is the check digit validation logic:
id = # input ID number as string
id_2digits = id[0:2] # first 2 digits
# Calculate check digit using modulus 11 for IDs before 2000
if id_2digits <= '31':
check_digit = 11 - sum([(int(id[i])*((i%2)+1)) for i in range(0,9)])%11
else:
# Calculate check digit using modulus 10 for IDs after 2000
check_digit = 10 - sum([(int(id[i])*(1 if i%2==0 else 2)) for i in range(0,9)])%10
if check_digit == id[-1]:
print("Valid ID")
else:
print("Invalid ID") Guam
Below is the National ID validation for Guam:
(^\d{3}-\d{2}-\d{4}$)|(^\d{4}$)|(^\d{9}$)
Hong Kong
Below is the National ID validation for Hong Kong:
(^[A-Za-z\d]{9}$)
India
Below is the Indian National ID validation:
(^[A-Za-z]{2}[-]\d{13}$)|(^[A-Za-z]{2}\d{2}[\s]?\d{11}$)Indonesia
Below is the Indonesian National ID validation:
(^\d{16}$)
Ireland
Below is the Irish National ID validation:
^\d{7}[A-Za-z]{1,2}$
Italy
Below is the Italian Codice Fiscal validation:
^[A-Z]{6}[0-9LMNPQRSTUV]{2}[A-Z][0-9LMNPQRSTUV]{2}[A-Z][0-9LMNPQRSTUV]{3}[A-Z]$
Japan
Below is the Japanese National ID validation:
(^\d{12}$)
Malaysia
Below is the Malaysian National ID validation:
(^\d{12}$)
Mexico
Below are the Mexican CURP and Mexican RFC validations:
(^[A-Za-z\d]{18}$)Netherlands
Below is the Dutch (Netherlands) Burgerservicenummer or BSN validation:
^(?!123[0-9]{6})(?!.*(000)$)(?=[0-9]{9}(?![0-9]{2})(?: (?!20)[0-9]{2})
{3}[0-9]{3})[0-9]{9}|[0-9]{2} [0-9]{7}[0-9]{3}(?(1)(?![0-9X])|(?(2)|
[0-9X]))(3[0-1]|[1-2][0-9]0|[1-9][0-9])^(0[1-9]|[1-4][0-9]|5[0-2])[0-9]{2}$
And here is the check digit validation logic:
def luhn_checksum(bsn):
"""Calculate Luhn checksum for Dutch BSN."""
sum = 0
length = len(bsn)
parity = length % 2
for i in range(length - 1, -1, -1):
digit = int(bsn[i])
if i % 2 == parity:
digit *= 2
if digit > 9:
digit -= 9
sum += digit
return sum * 9 % 11
def validate_bsn(bsn):
"""Validate Dutch BSN using Luhn checksum."""
checksum = luhn_checksum(bsn)
if checksum == int(bsn[-1]):
print("Valid ID")
else:
print("Invalid ID")New Zealand
Below is the National ID validation for New Zealand:
^[A-Za-z0-9]+$
Nigeria
Below is the Nigerian National ID validation:
(^\d{11}$)|(^\d{8}[-\s]?0001$)
Northern Mariana Islands
Below is the National ID validation for Northern Mariana Islands:
(^\d{3}-\d{2}-\d{4}$)|(^\d{4}$)|(^\d{9}$)
Norway
Below is the Norwegian National ID validation:
(^(?:0[1-9]|[12][0-9]|3[01])(?:0[1-9]|1[0-2])\d{2}\d{5}$)
Peru
Below is the Peruvian National ID validation:
^\d{8}$
Philippines
Below is the National ID validation for Philippines:
^\d{10}$Poland
Below is the Polish PESEL validation:
(^\\d{11}$)
Portugal
Below is the Portuguese Bilhete de Identidade (BI) National ID validation:
^([2-8][0-9A-Z]{2}|[3-8][0-9]{2})[0-9]{8}[0-9]{1}$
And here is the check digit validation logic:
# Extract components
region_code = id[0:2]
check_sum_digits = id[2:10]
check_digit = id[10:11]
# Double check Luhn checksum
checksum1 = calculate_luhn_checksum(check_sum_digits)
checksum2 = calculate_luhn_checksum(check_sum_digits[::-1])
if checksum1 != checksum2:
print("Invalid ID")
return False
# Validate check digit
control_digit = checksum1 % 10
if check_digit != str(control_digit):
print("Invalid ID")
return False
# Validate region code
valid_region_codes = [list of codes]
if region_code not in valid_region_codes:
print("Invalid ID")
return False
else:
print("Valid ID")
return True Puerto Rico
Below is the National ID validation for Puerto Rico:
(^\d{3}-\d{2}-\d{4}$)|(^\d{4}$)|(^\d{9}$)
Romania
Below is the Romanian CNP validation:
^(19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[0-1])(0[1-9]|[1-8][0-9])
(([1-9][0-9]{2})|([1-9][0-9])|(0[1-9]))((8|9|[2-3][0-9])($|[^0-9]))$
(0[1-9]|1[0-9]|2[0-9]|3[0-5]|4[0-8])[0-9]{3}$
Singapore
Below is the Singaporean National Registration Identity Card (NRIC) validation:
^[A-Za-z]\d{7}[A-Za-z]$
OR
^[A-Za-z0-9]{9}$
South Korea
Below is the National ID validation for South Korea:
(^\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12][0-9]|3[01])[-]?\d{7}$)
South Africa
Below is the National ID validation for South Africa:
(^\d{13}$)
Spain
Below is the Spanish DNI validation:
(^\\d{8}[-\\s]?[A-Za-z]$)
Sweden
Below is the Swiss (Sweden) Personnummer National ID validation:
(^\\d{10}$)
Thailand
Below is the National ID validation for Thailand:
(^\d{13}$)
Turkey
Below is the Turkish National ID validation:
(^\d{11}$)|(^\d{13}$)
Ukraine
Below is the Ukrainian National ID validation:
^(?:[12][01]|[321-7])[0-9]{9}$/&&id<99000000&&(id>10100000||id<21000000)
&&luhnChecksumIsValid(id)
&&((id>49999999&&id[2]<3)||regionCodes.includes(id.slice(0,3)))
&&((id[0]==1&&(id>10100000&&id<21000000))||((id<20000000||id>35000000)
&&birthYearValid(id[0])))
United Kingdom
Below are the United Kingdom National Insurance Number, National Health Service Number, and Community Health Index validations:
(^[A-Za-z]{2}\d{6}[A-Za-z]$)United States
Below are the United States Social Security Number (SSN), Individual Taxpayer Identification Number (ITIN), and Employer Identification Number (EIN) validations:
^
(?!219099999|078051120|111221111|409522002|229229229|101010101|111222333|267941100|
111100000|111222222|010101010|232323232|001010101|234567891|221221221|121121212|
333221111|721074426|261634666|454545454|111223344|333224444|001100001|234234234|
123121231|267941000|111100111|001010011|456789123|252525252|555121212|485520189|
212111111|031101169|555667777|111221212|101101010|321321321|583299230|123123456|
111222111|110011001|333445555|111444444|123345678|123445678|555665555|500507000|
524027657|721071426|112223333|112345678|111121234|111225555|111229999|222221111|
111221234|123321123|111122222|111221122|172321176|555443333|010101011|112121212|
485345454|456123789|545454545|111223334|220786897|100101001|123546789|090090909|
215643925|532801066|212561547|452541111|500222000|123121111|555123456|458026124|
543098765|011010101|123465789|111441111|123121212|239448855|111224444|111223456|
456456456|101010100|270349290|465846552|110011111|456789012|595125274|111123456|
555121234|123121233|065687510|112222222|555551111)
(?!000|666|9\d\d)\d{3}[- ]?(?!00)\d{2}[- ]?(?!0000)\d{4}$Vietnam
Below is the Vietnamese National ID validation:
^\d{9,12}$
Virgin Islands
Below is the National ID validation for Virgin Islands:
(^\d{3}-\d{2}-\d{4}$)|(^\d{4}$)|(^\d{9}$)
Check against government ID databases
Consider utilizing validation APIs government agencies offer to verify an ID against their records if available. This is the most reliable way to confirm the authenticity of a national ID number, and we highly recommend integrating with official validation APIs if they are available for your target countries.
Keep up-to-date with changes to ID formats
Governments may periodically update national ID formats, algorithms, and validation rules. It's important to stay informed about any announcements related to ID format changes and update your validators accordingly. Failure to keep up-to-date may result in incorrectly accepting or rejecting valid national IDs.
Updated 3 months ago
