Skip to main content

Iranian National ID Validation

The verifyIranianNationalId utility validates Iranian national identification numbers using the official checksum algorithm and format requirements.

Basic Usage

import { verifyIranianNationalId } from '@persian-tools/persian-tools';

Simple Validation

verifyIranianNationalId("0499370899"); // true
verifyIranianNationalId("0684159415"); // true
verifyIranianNationalId("1234567890"); // false
verifyIranianNationalId("0000000000"); // false

Validation Rules

The function validates Iranian national IDs based on:
  • Must be exactly 10 digits
  • Cannot be all the same digit (e.g., 1111111111)
  • Must contain only numeric characters
  • Uses modulo-11 checksum validation - Last digit serves as check digit - Implements official Iranian algorithm
  • All zeros: 0000000000
  • All same digits: 1111111111, 2222222222, etc.
  • Sequential patterns in some cases

Input Format Support

The function accepts various input formats:
// Standard numeric string
verifyIranianNationalId("0499370899"); // true

// With Persian digits
verifyIranianNationalId("۰۴۹۹۳۷۰۸۹۹"); // true

// With Arabic digits
verifyIranianNationalId("٠٤٩٩٣٧٠٨٩٩"); // true

// Number input
verifyIranianNationalId(499370899); // true (auto-padded to 10 digits)

Advanced Examples

Form Validation

interface UserForm {
	nationalId: string;
	name: string;
	phone: string;
}

function validateUserForm(form: UserForm) {
	const errors: string[] = [];

	// Validate National ID
	if (!verifyIranianNationalId(form.nationalId)) {
		errors.push("کد ملی معتبر نیست");
	}

	return {
		isValid: errors.length === 0,
		errors,
		normalizedNationalId: digitsFaToEn(digitsArToEn(form.nationalId)),
	};
}

Batch Validation

function validateNationalIdBatch(ids: string[]) {
	return ids.map((id) => ({
		original: id,
		normalized: digitsFaToEn(digitsArToEn(id)),
		isValid: verifyIranianNationalId(id),
		location: verifyIranianNationalId(id) ? getPlaceByIranNationalId(id) : null,
	}));
}

const results = validateNationalIdBatch(["0499370899", "۰۶۸۴۱۵۹۴۱۵", "1234567890"]);

Database Integration

class UserService {
	async createUser(userData: { nationalId: string; name: string }) {
		// Normalize and validate National ID
		const normalizedId = digitsFaToEn(digitsArToEn(userData.nationalId));

		if (!verifyIranianNationalId(normalizedId)) {
			throw new Error("کد ملی معتبر نیست");
		}

		// Check for existing user
		const existingUser = await this.findByNationalId(normalizedId);
		if (existingUser) {
			throw new Error("کاربر با این کد ملی قبلاً ثبت‌نام کرده است");
		}

		// Create user with normalized ID
		return this.save({
			...userData,
			nationalId: normalizedId,
		});
	}
}

Valid National ID Examples

Here are some valid Iranian national IDs for testing:
const validIds = [
	"0499370899", // خمین
	"0684159415", // شیراز
	"0076229645", // تهران
	"0013542419", // تهران
	"0012016467", // تهران
	"0010859657", // تهران
];

validIds.forEach((id) => {
	console.log(`${id}: ${verifyIranianNationalId(id)}`); // all true
});

Edge Cases

Invalid Formats

verifyIranianNationalId(""); // false
verifyIranianNationalId("123"); // false (too short)
verifyIranianNationalId("12345678901"); // false (too long)
verifyIranianNationalId("abcd123456"); // false (contains letters)
verifyIranianNationalId(null); // false
verifyIranianNationalId(undefined); // false

Special Invalid Patterns

verifyIranianNationalId("0000000000"); // false (all zeros)
verifyIranianNationalId("1111111111"); // false (all same digit)
verifyIranianNationalId("2222222222"); // false (all same digit)
verifyIranianNationalId("9999999999"); // false (all same digit)

Checksum Failures

verifyIranianNationalId("1234567890"); // false (invalid checksum)
verifyIranianNationalId("0123456789"); // false (invalid checksum)
verifyIranianNationalId("9876543210"); // false (invalid checksum)

Algorithm Details

The validation follows these steps:
  1. Format Check: Ensure exactly 10 digits
  2. Pattern Check: Reject all-same-digit patterns
  3. Checksum Calculation: Apply modulo-11 algorithm
  4. Check Digit Verification: Compare with last digit
// Simplified algorithm illustration
function nationalIdChecksum(id: string): boolean {
	const digits = id.split("").map(Number);
	const checkDigit = digits[9];

	let sum = 0;
	for (let i = 0; i < 9; i++) {
		sum += digits[i] * (10 - i);
	}

	const remainder = sum % 11;
	const expectedCheck = remainder < 2 ? remainder : 11 - remainder;

	return checkDigit === expectedCheck;
}

Performance

  • Average execution: ~0.05ms
  • Batch validation: Linear scaling
  • Memory usage: Minimal (no caching needed)
  • CPU overhead: Very low
  • 1,000 validations: ~50ms
  • 10,000 validations: ~500ms
  • 100,000 validations: ~5s

TypeScript Support

import { verifyIranianNationalId } from "persian-tools";

// Type-safe validation
const isValid: boolean = verifyIranianNationalId("0499370899");

// Custom validation function with typing
function validateNationalId(id: string | number): {
	isValid: boolean;
	normalized: string;
} {
	const normalized = digitsFaToEn(digitsArToEn(id.toString()));
	return {
		isValid: verifyIranianNationalId(normalized),
		normalized,
	};
}

Integration Patterns

React Hook

import { useState, useEffect } from "react";

function useNationalIdValidation(id: string) {
	const [validation, setValidation] = useState({
		isValid: false,
		isChecking: false,
		error: null,
	});

	useEffect(() => {
		if (!id) {
			setValidation({ isValid: false, isChecking: false, error: null });
			return;
		}

		setValidation((prev) => ({ ...prev, isChecking: true }));

		const timeoutId = setTimeout(() => {
			const isValid = verifyIranianNationalId(id);
			setValidation({
				isValid,
				isChecking: false,
				error: isValid ? null : "کد ملی معتبر نیست",
			});
		}, 300); // Debounce

		return () => clearTimeout(timeoutId);
	}, [id]);

	return validation;
}

Express.js Middleware

import { Request, Response, NextFunction } from "express";

function validateNationalId(req: Request, res: Response, next: NextFunction) {
	const { nationalId } = req.body;

	if (!nationalId) {
		return res.status(400).json({ error: "کد ملی الزامی است" });
	}

	if (!verifyIranianNationalId(nationalId)) {
		return res.status(400).json({ error: "کد ملی معتبر نیست" });
	}

	// Normalize and attach to request
	req.body.nationalId = digitsFaToEn(digitsArToEn(nationalId));
	next();
}

Security Considerations

National ID validation should be used alongside other verification methods. A valid checksum doesn’t guarantee the ID belongs to the person claiming it.
// Good practice: Combined validation
interface UserVerification {
	nationalId: string;
	phone: string;
	name: string;
}

function verifyUser(data: UserVerification): boolean {
	return (
		verifyIranianNationalId(data.nationalId) &&
		verifyIranianNationalId(data.phone) && // additional checks
		data.name.length > 0
	);
}