Social Security Number
SSN Validation
US SSN Check
Identity Verification
US Social Security

How can I validate US Social Security Number?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

US Social Security Number validation is usually about checking formatting and known invalid ranges, not proving ownership of an identity. A value can pass local checks and still be fraudulent or belong to someone else. This guide explains practical validation logic, safe handling patterns, and backend code you can run today.

What Local Validation Can and Cannot Do

Local validation can confirm that input follows expected SSN structure and basic issuance constraints. It cannot prove that the number belongs to the person submitting it.

Use this distinction in system design:

  • local validation for input quality and typo detection
  • external identity workflow for ownership verification
  • strict privacy controls for storage and logging

Treat SSN as high-risk personal data in every environment.

Input Normalization First

Users enter SSNs in different formats, such as 123-45-6789, 123456789, or with spaces. Normalize before validating so your rules stay simple and consistent.

python
1def normalize_ssn(raw: str) -> str:
2    digits = "".join(ch for ch in raw if ch.isdigit())
3    if len(digits) != 9:
4        return ""
5    return f"{digits[0:3]}-{digits[3:5]}-{digits[5:9]}"
6
7
8print(normalize_ssn("123 45 6789"))
9print(normalize_ssn("123-45-6789"))
10print(normalize_ssn("12-345"))

Returning an empty string for invalid length keeps failure handling straightforward.

Rule-Based Validation in Python

After normalization, validate both format and segment rules. A regular expression confirms shape, then explicit checks enforce disallowed ranges.

python
1import re
2
3SSN_PATTERN = re.compile(r"^(\d{3})-(\d{2})-(\d{4})$")
4
5
6def is_valid_ssn(normalized: str) -> bool:
7    match = SSN_PATTERN.match(normalized)
8    if not match:
9        return False
10
11    area, group, serial = match.groups()
12
13    # Commonly rejected values
14    if area == "000" or area == "666":
15        return False
16    if 900 <= int(area) <= 999:
17        return False
18    if group == "00":
19        return False
20    if serial == "0000":
21        return False
22
23    return True
24
25
26examples = ["123-45-6789", "000-12-3456", "987-65-4321", "219-00-1234"]
27for value in examples:
28    print(value, is_valid_ssn(value))

Keep rules explicit rather than burying everything in one complex regular expression. It is easier to review and maintain.

End-to-End API Example

A backend endpoint should normalize input, validate, and return a normalized representation. Avoid returning sensitive detail in error messages.

python
1from fastapi import FastAPI, HTTPException
2
3app = FastAPI()
4
5
6@app.post("/ssn/validate")
7def validate_ssn(payload: dict):
8    raw = str(payload.get("ssn", ""))
9    normalized = normalize_ssn(raw)
10
11    if not normalized:
12        raise HTTPException(status_code=400, detail="SSN must contain 9 digits")
13
14    if not is_valid_ssn(normalized):
15        raise HTTPException(status_code=400, detail="Invalid SSN format")
16
17    return {"valid": True, "normalized": normalized}

This pattern keeps frontend and backend behavior aligned.

Secure Storage and Display Practices

Validation is only one part of safe SSN handling. Operational controls matter just as much.

Use these minimum safeguards:

  • never log full SSN values
  • mask display to last four digits
  • encrypt at rest and in transit
  • restrict access by role
  • keep retention periods minimal

Masking utility:

python
1def mask_ssn(normalized: str) -> str:
2    # Input expected in AAA-GG-SSSS format
3    return f"***-**-{normalized[-4:]}"
4
5
6print(mask_ssn("123-45-6789"))

Also scan structured logs to ensure raw fields are never emitted by accident.

Testing Strategy

Because SSN handling is sensitive, tests should be explicit and exhaustive for known rule branches.

python
1def test_cases():
2    assert normalize_ssn("123456789") == "123-45-6789"
3    assert normalize_ssn("123-45-6789") == "123-45-6789"
4    assert normalize_ssn("123") == ""
5
6    assert is_valid_ssn("123-45-6789") is True
7    assert is_valid_ssn("000-45-6789") is False
8    assert is_valid_ssn("666-45-6789") is False
9    assert is_valid_ssn("987-45-6789") is False
10    assert is_valid_ssn("219-00-6789") is False
11    assert is_valid_ssn("219-45-0000") is False

Add integration tests to ensure your API returns the same outcome as direct function calls.

Compliance and Product Design Notes

Legal and policy requirements vary by organization and jurisdiction. Work with legal and security teams before collecting SSNs, and collect them only when truly necessary.

A useful product approach:

  • ask for SSN only in required workflows
  • explain clearly why it is needed
  • minimize screen exposure of raw value
  • support secure deletion and retention policies

Designing for minimal data exposure reduces both risk and audit burden.

Common Pitfalls

  • Treating format validation as identity verification.
  • Accepting any nine digits with no segment checks.
  • Logging raw SSN in debug messages or exception traces.
  • Storing SSN unencrypted for convenience during development.
  • Returning overly detailed validation errors that leak rule internals.

Summary

  • Normalize input first, then validate format and segment constraints.
  • Keep rule checks explicit for readability and maintainability.
  • Local checks improve data quality but do not verify identity ownership.
  • Protect SSN with masking, encryption, and strict logging discipline.
  • Back validation logic with unit and integration tests to prevent regressions.

Course illustration
Course illustration

All Rights Reserved.