Core Docs

Future Ideas

Future Ideas



Ideas, explorations, and hardening measures for core.auth that aren't needed now but may become relevant as the platform grows or handles more sensitive data.

Security Hardening



Cloud HSM for JWT Signing Keys



When: When handling medical data with regulatory requirements (HIPAA, Swiss DPA, GDPR special categories), or when the userbase justifies the cost.

What it solves: If the VPS is compromised (root access), an attacker can read environment variables and extract the JWT signing secret. With an HSM, the secret never touches the server's memory — signing operations happen inside the hardware.

Options:

ProviderCostIntegrationNotes






AWS CloudHSM~$1.50/hr ($1,100/mo)PKCS#11, Java/C SDKDedicated hardware, FIPS 140-2 Level 3
GCP Cloud HSM~$0.06/hr ($43/mo) + per-operationCloud KMS APIManaged, easier than AWS
Azure Dedicated HSM~$4/hr ($2,900/mo)PKCS#11Expensive, enterprise-grade
YubiHSM 2$500 one-timePKCS#11, USBPhysical device, requires on-prem
Nitrokey HSM 2€200 one-timePKCS#11, USBOpen-source hardware, EU-based

Integration approach:
  1. Small signing service (Go or Rust) wraps the HSM API

  2. Exposes a local HTTP endpoint: POST /sign with payload → returns HMAC signature

  3. PHP calls the local endpoint instead of computing the signature itself

  4. The HSM secret never leaves the hardware

Tradeoff: Adds latency (~5-20ms per signing operation) and operational complexity. Only worth it when regulatory or threat model demands it.

Key Rotation



When: Any time, but especially important with or without HSM.

What it does: Periodically rotate the JWT signing secret. Old tokens remain valid until they expire naturally, but new tokens are signed with the new key.

Key rotation schedule: every 90 days


core.auth generates new secret


Both old and new secrets are accepted for verification


New tokens are signed with the new secret


After 90 days + max token TTL (15 min), old secret is retired


This limits the blast radius of a leaked key — even if an attacker gets the key, it's only valid for the current rotation period + 15 minutes.

Implementation: Store multiple secrets in a keyring (JSON array or DB table). createJwt uses the latest. verifyJwt tries all of them.

// Keyring: [{ "id": "k1", "secret": "...", "created_at": "...", "retired_at": null }]
function verifyJwtWithKeyring(string $token, array $keyring): ?array
{
foreach ($keyring as $key) {
if ($key['retired_at'] !== null) continue;
$result = verifyJwt($token, $key['secret']);
if ($result) return $result;
}
return null;
}


Medical Data Considerations



If core.auth handles authentication for medical applications (patient records, clinical tools), additional requirements may apply:

Swiss DPA (nDSG, revised 2023):
  • Data minimization: collect only what's necessary

  • Purpose limitation: auth data used only for auth

  • Right to access and deletion

  • Cross-border transfer restrictions (EU/EEA adequacy)

HIPAA (if US patients):
  • Access controls (§164.312(a))

  • Audit controls (§164.312(b))

  • Authentication (§164.312(d))

  • Encryption at rest and in transit

What this means for core.auth:
  • ident_events retention may need to be longer (audit requirements)

  • Encryption at rest for users.two_fa_secret, recovery_codes (already planned)

  • TLS everywhere (already planned)

  • Access logging must be comprehensive (already covered by ident_events)

  • Data residency: if serving EU/Swiss patients, DB must be in EU/Switzerland

HSM-backed signing keys become more justifiable in this context — it's a concrete, auditable security control that satisfies regulatory auditors.

Architecture



Redis Session Store



When: When PostgreSQL session lookups become a bottleneck (thousands of concurrent users).

What changes: Session validity checks move from PostgreSQL to Redis. The session row stays in Postgres as the source of truth / audit trail, but Redis becomes the fast path for refresh checks.

Phase 1 (now):  Session check → PostgreSQL query (~1-5ms)
Phase 2: Session check → Redis GET (~0.1ms)
Session write → PostgreSQL + Redis (write-through)
Session delete → PostgreSQL + Redis (invalidate)


Migration is transparent — no client-side changes, no API changes. Just swap the lookup from PG to Redis in the /session/refresh handler.

Refresh Token Rotation



When: When the userbase is large enough that even Redis session checks become a concern, or when you want stolen-token detection without relying on anomaly heuristics.

What changes: Add opaque refresh tokens with rotation (the design from the original auth articles). The session-based refresh mechanism becomes a fallback for clients that don't support refresh tokens.

The migration path is clean because the client-side contract doesn't change: "send JWT with requests, call refresh endpoint when JWT expires." The refresh endpoint's internal logic evolves.

Multi-Region Auth



When: When serving users across multiple continents and latency to a single core.auth instance becomes noticeable.

Options:
  • Read replicas: JWT verification is already local (no DB hit). Session refresh hits the nearest read replica.

  • Regional core.auth instances: Each region has its own core.auth with shared session store (Redis Cluster or CockroachDB).

  • Edge JWT verification: CDN/edge workers verify JWTs locally, only hit core.auth for refresh.

None of this changes the client-side architecture — it's all backend optimization.

Features



Push Notification 2FA



Mobile-based 2FA where the user approves a login attempt via push notification (like Google Prompt). Requires a registered mobile device with push notification support.

See 2FA & Passkeys — "Mobile Device as 2FA (Future)" section.

Social Login (OAuth)



Allow users to sign in with Google, Apple, GitHub, etc. The social identity is linked to the master account — the user still has a core.auth account, just authenticated via a third party.

See Registration & Social Login (planned article).

Device Trust



Register trusted devices. When a user logs in from a trusted device, 2FA can be skipped (or reduced to a simpler check). Untrusted devices always require full 2FA.

User logs in from new device → full 2FA required


User checks "Trust this device"


core.auth stores device fingerprint in trusted_devices table


Next login from same device → 2FA skipped (or simplified)


After 90 days → trust expires, re-verification needed


Adaptive Risk Scoring



Combine multiple signals (IP, geo, user agent, device trust, time of day, login frequency) into a risk score. Higher risk = more friction (require 2FA, send notification). Lower risk = less friction (skip 2FA on trusted devices).

See Revocation & Security — "Future: Adaptive Scoring" section.




This article is a living document. Add ideas as they come up.