PII Data Encryption & Security Model
ClinicFlow implements defense-in-depth data protection standards to secure Sensitive Personally Identifiable Information (PII), patient health metadata, and third-party API credentials across all persistence and transit layers.
1. Data Classification
Section titled “1. Data Classification”Data within ClinicFlow is classified into three risk tiers:
| Tier | Sensitivity | Data Types | Security Controls |
|---|---|---|---|
| Tier 1: High Sensitivity (PII & Secrets) | Extreme | Patient DUI numbers, tax profiles (NIT/NRC), Meta WhatsApp API access tokens, MH DTE private keys. | AES-256-GCM application-layer envelope encryption at rest; restricted DB access. |
| Tier 2: Protected Health Information (PHI) | High | Clinical dental entries, periograms, medical notes, appointment reasons, doctor notes. | Multi-tenant PostgreSQL Row-Level Security (RLS) isolation; ES256 JWT claim verification. |
| Tier 3: Operational Data | Standard | Clinic business names, public doctor schedules, non-PII appointment counts. | Standard TLS 1.3 transit encryption; tenant-scoped RLS policies. |
2. Application-Layer Envelope Encryption (AES-256-GCM)
Section titled “2. Application-Layer Envelope Encryption (AES-256-GCM)”High-sensitivity fields (Tier 1) undergo cryptographic envelope encryption before being written to PostgreSQL tables.
Cryptographic Algorithm & Parameters
Section titled “Cryptographic Algorithm & Parameters”- Cipher:
AES-256-GCM(Galois/Counter Mode) providing both confidentiality and authenticated integrity. - Master Key: Derived from
ENCRYPTION_KEYenvironment variable (32-byte / 256-bit hexadecimal string). - Initialization Vector (IV): Cryptographically secure random 12-byte (96-bit) IV generated per encryption operation via
crypto.randomBytes(12). - Authentication Tag: 16-byte (128-bit) GCM tag appended to ciphertext to detect tampering.
Storage Format
Section titled “Storage Format”Encrypted fields are stored in database columns as string blobs formatted with a colon separator:
<iv_hex>:<auth_tag_hex>:<ciphertext_hex>Encryption Implementation (backend/src/utils/encryption.ts)
Section titled “Encryption Implementation (backend/src/utils/encryption.ts)”import crypto from 'node:crypto';
const ALGORITHM = 'aes-256-gcm';const MASTER_KEY = Buffer.from(process.env.ENCRYPTION_KEY!, 'hex');
export function encrypt(text: string): string { const iv = crypto.randomBytes(12); const cipher = crypto.createCipheriv(ALGORITHM, MASTER_KEY, iv);
let encrypted = cipher.update(text, 'utf8', 'hex'); encrypted += cipher.final('hex');
const authTag = cipher.getAuthTag().toString('hex'); return `${iv.toString('hex')}:${authTag}:${encrypted}`;}
export function decrypt(encryptedData: string): string { const [ivHex, authTagHex, ciphertextHex] = encryptedData.split(':'); const iv = Buffer.from(ivHex, 'hex'); const authTag = Buffer.from(authTagHex, 'hex'); const decipher = crypto.createDecipheriv(ALGORITHM, MASTER_KEY, iv);
decipher.setAuthTag(authTag); let decrypted = decipher.update(ciphertextHex, 'hex', 'utf8'); decrypted += decipher.final('utf8');
return decrypted;}3. Session Security & Token Storage
Section titled “3. Session Security & Token Storage”In-Memory Access Tokens
Section titled “In-Memory Access Tokens”To mitigate Cross-Site Scripting (XSS) risks, JWT access tokens are stored strictly in frontend application memory (authToken variable in frontend/src/services/api.ts). Access tokens are never saved to localStorage or sessionStorage.
Secure Refresh Cookies
Section titled “Secure Refresh Cookies”Longer-lived session refresh tokens are delivered in HTTP responses using secure cookies with strict flags:
httpOnly: true(Inaccessible to JavaScript)Secure: true(HTTPS transit mandatory)SameSite: Lax(Protection against Cross-Site Request Forgery - CSRF)Path: /api/auth(Restricted cookie delivery path)
4. Transmission & Infrastructure Security
Section titled “4. Transmission & Infrastructure Security”- TLS 1.3 Encryption: All incoming HTTP traffic to backend and frontend services is forced over HTTPS via Caddy and Railway edge routers.
- Database Transit Encryption: Connections between Express Node.js application nodes and Supabase PostgreSQL require SSL (
sslmode=require). - Secret Masking & Zero-Logging: Sensitive headers and encrypted values are automatically stripped by Winston logger middleware (
backend/src/utils/logger.ts) before writing to log streams.