01/08/2026
Every health-tech vendor says: "Use Auth0. Use Okta. Use Cognito. It's industry standard."
Industry standard is fine — if you want a system that works like everyone else's.
We chose a different path. We built our own authentication layer from scratch. Here's why, and what it actually looks like in the code:
🔐 Custom bcrypt password hashing — 12 rounds. Every password in the Terk-Age HMIS gets hashed with bcrypt at 12 rounds. That's the same level of security Auth0 and Okta provide — but it's ours. We control the salt, the rounds, the algorithm. No vendor decides to lower the security bar for cost savings.
🔑 JWT access tokens + refresh tokens — our own rotation. Access tokens expire in 15 minutes. Refresh tokens expire in 7 days. When a refresh token is used, it's deleted and a new one is issued — no token reuse, no replay attacks. The JWT_SECRET and REFRESH_TOKEN_SECRET are environment variables, not hardcoded strings.
🛡️ TOTP authenticator app — built on speakeasy. We use speakeasy for TOTP generation and verification — the same library Auth0 uses under the hood. But we control the enrollment flow, the QR code generation, the secret storage. Every 30-second code is single-use. Codes can't be replayed within 90 seconds.
📧 Email OTP fallback — our own implementation. If a user doesn't have an authenticator app, they get a one-time code via email. It's not a "forgot password" flow — it's a second authentication path, equally secure.
🚪 LAN break-glass code — for when everything else fails. In a hospital, a doctor can't wait for an email OTP during a code blue. The break-glass code lets them through — but every single use is logged with action: 'auth.mfa_break_glass_lan', including who, when, and what they accessed.
📱 Device trust — once verified, less friction. The first time you log in on a new device, 2FA fires. After that, the system remembers that device via a trustedDeviceToken. Dr. Adesanmi doesn't enter a code every morning — just once per device, then smooth sailing.
🔄 Password history — last 5 passwords blocked. passwordPolicy.ts checks the last 5 password hashes before allowing a change. You can't reuse your old password. Ever. The isPasswordReused function compares against passwordHistory records and the current active hash.
🔍 Full audit trail — every auth event logged. Every login, every failed attempt, every password change, every break-glass access — logged via logAudit() to the auditLog table with userId, action, resourceType, ipAddress, userAgent, and changes. The audit logs are excluded from sync replication (they stay local) and are append-only.
The tradeoff we accepted: Building custom auth means more code, more maintenance, more responsibility. No vendor support line to call when something breaks. No monthly per-seat fee that scales with every new staff member. No "we'll deprecate that feature next quarter" surprise.
But it means we own every line of the security stack.