Skip to content

feat: secure Aadhaar tokenization and step-up detokenization - #114

Open
DUKartik wants to merge 22 commits into
vicharanashala:mainfrom
DUKartik:feature/aadhaar-vault
Open

feat: secure Aadhaar tokenization and step-up detokenization#114
DUKartik wants to merge 22 commits into
vicharanashala:mainfrom
DUKartik:feature/aadhaar-vault

Conversation

@DUKartik

@DUKartik DUKartik commented Aug 1, 2026

Copy link
Copy Markdown

Pull Request: Feat --- Aadhaar Vault Microservice (Tokenization & Step-Up Auth)

🎯 Objective

This PR introduces a standalone Aadhaar Vault microservice for securely tokenizing and protecting sensitive student identity numbers such as Aadhaar.

It isolates plaintext PII from the main application and provides two capabilities:

  • Tokenization --- converts Aadhaar into an opaque Vault Token.
  • Step-Up Detokenization --- releases plaintext only after JWT authorization, MFA/TOTP verification, and approval of a short-lived challenge.

🏗️ Architecture & Stack

The service follows Clean Architecture, keeping application logic independent from HTTP, database, and cryptographic infrastructure.

  • Runtime: Node.js 20+, TypeScript, ESM
  • Framework: Fastify 4
  • Database: PostgreSQL 16 (pg) + custom MemoryPool for tests
  • Validation: Zod strict schemas
  • Authentication: HS256 Bearer JWT using jose
  • MFA: TOTP (RFC 6238)
  • Cryptography: HKDF-SHA-256 + AES-256-GCM
  • Testing: 213 passing tests across 17 Vitest suites

✨ Core Features

Tokenization

POST /v1/tokenize --- vault:tokenize

Plaintext Aadhaar is encrypted inside the vault and represented externally using an opaque token. The authenticated JWT subject is used as the trusted actor for audit attribution.

Aadhaar → Encrypt → Vault Storage → Vault Token

Step-Up Detokenization

Plaintext recovery requires an additional MFA-protected authorization
flow:

Vault Token
    ↓
Enroll MFA
    ↓
Factor ID + OTP URI
    ↓
Request Step-Up
    ↓
Challenge ID
    ↓
Approve with TOTP
    ↓
APPROVED
    ↓
Detokenize
    ↓
Plaintext Aadhaar

Key endpoints:

  • POST /v1/mfa/enroll --- creates a TOTP factor.
  • POST /v1/detokenize/request --- creates a short-lived challenge.
  • POST /v1/detokenize/step-up/:challengeId/approve --- verifies TOTP
    and approves the challenge.
  • POST /v1/detokenize --- consumes the approved challenge and
    releases plaintext.
  • POST /v1/mfa/verify --- standalone factor verification; not
    required by the dedicated Step-Up console flow.

Consumed challenges cannot be reused, providing replay protection.

🔒 Security

  • Plaintext Aadhaar is not intentionally persisted.
  • AES-256-GCM provides authenticated encryption.
  • HKDF-SHA-256 provides context-bound key derivation.
  • Sensitive key buffers are wiped using safeZero() where applicable.
  • The trusted actor is derived from the verified JWT sub.
  • Detokenization requires JWT authorization + MFA + fresh TOTP + a
    short-lived approved challenge.
  • Security-sensitive operations are recorded in the audit trail.
  • LocalDevKeyManager is guarded against accidental production use.

🖥️ Developer Consoles

Two separate developer interfaces are provided:

  • Tokenization Console --- /console/index.html
    Used for tokenization and architecture inspection.

  • Step-Up Console --- /console/stepup.html
    Guides developers through:

Select Token → Enroll MFA → Request Step-Up → Approve → Detokenize

Intermediate Factor IDs and Challenge IDs are propagated automatically.

🏥 Operations

  • GET /health
  • GET /health/ready
  • PostgreSQL migrations via npm run migrate
  • Readiness checks database and key-provider availability

🧪 Testing

The test suite covers tokenization, encryption, JWT/scopes, MFA/TOTP, Step-Up challenges, expiry, replay rejection, detokenization, auditing, key management, and Clean Architecture boundaries.

The end-to-end smoke flow verifies:

Tokenize → Enroll MFA → Request → Approve → Detokenize

📋 Reviewer Guide

Recommended starting points:

  • src/server.ts --- dependency wiring
  • src/auth/plugin.ts --- JWT authentication and scopes
  • src/application/commands/tokenize-aadhaar.ts --- tokenization
  • src/application/commands/detokenize-aadhaar.ts --- plaintext
    recovery
  • STEP_UP_AUTH.md --- Step-Up design
  • AADHAAR_VAULT_FREE_ARCHITECTURE.md --- architecture
  • RUN.md --- local setup

✅ Summary

This PR adds a standalone Aadhaar Vault with tokenization, envelope encryption, JWT authentication, TOTP MFA, Step-Up authorization, replay protection, audit logging, PostgreSQL persistence, developer consoles, and automated security/workflow tests.

The main application can operate on opaque identity tokens while plaintext Aadhaar remains isolated behind a dedicated security boundary.

DUKartik and others added 22 commits July 21, 2026 12:57
…scaffolding

- Add isolated microservices/aadhaar-vault/ workspace (Fastify 4, TypeScript 5,

  strict mode + noUncheckedIndexedAccess) with its own package.json, tsconfig,

  vitest config, Dockerfile, and docker-compose.yml.

- Wire a Pino logger whose redact paths cover Authorization / cookie headers and

  any aadhaar-shaped field; a defensive stdout/stderr scrubber strips any

  12-digit sequence before it reaches the wire.

- Stand up the /health, /health/live, /health/ready routes mandated by

  architecture §6, plus a JSON 404 fallback so PII never leaks via Fastify's

  default HTML error page.

- Boot smoke test covers live + ready + JSON 404 + Authorization-header

  redaction. tsc --noEmit is clean and all 5 vitest cases pass in 1.85 s.

- Zero changes outside microservices/aadhaar-vault/. The root package.json,

  legacy backend/, and frontend/ trees remain untouched — verified before commit.
… + /health/ready

- application/ports/key-manager.ts: 4-method crypto port (getActiveDek / wrapDek / unwrapDek / generateDek)

- infrastructure/key-providers/local-dev-key-manager.ts: HKDF + AES-256-GCM (zero-cost dev impl)

- infrastructure/key-providers/index.ts: factory with prod-guard (refuses to boot LocalDev in production)

- util/dek-zero.ts: handling for '00000000...' sentinel DEK return path

- routes/health.routes.ts: extended /health/ready to assert keyProvider.isReady()

- server.ts: thread keyManager (closure) into /health/ready via app.decorate

- tests/key-manager.test.ts: 8 cases (round-trip, wrong key, missing key, key-rotation, primary-rotation, sentinel, paired DEKs)
@DUKartik DUKartik changed the title Feature/aadhaar vault feat: secure Aadhaar tokenization and step-up detokenization Aug 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant