Security Checklist

Authentication

  • Use short-lived JWT access tokens (15 min TTL) — already enforced by ESUS
  • Store tokens in httpOnly cookies, not localStorage
  • Use SMART on FHIR with PKCE for all third-party/browser clients
  • Rotate API key secrets regularly using POST /api-keys/:id/rotate
  • Set expiration dates on API keys when creating them

Authorization

  • Follow the principle of least privilege — request only the scopes your app needs
  • Use role-based access control — assign users the most restrictive role that still meets their needs
  • Review role assignments regularly
  • Never grant * (wildcard) scope to API keys unless absolutely necessary

Data Protection

  • Use TLS 1.2+ for all connections (enforced by ESUS infrastructure — TLS 1.3 is preferred when available)
  • PHI is encrypted at rest by ESUS (AES-256) — do not store raw PHI in external systems
  • Do not log access tokens or API key secrets in application logs

Privacy

  • Collect and store only the minimum necessary data
  • Create Consent records before accessing a patient’s PHI
  • Respond to patient data deletion requests promptly

Common Mistakes to Avoid

1. Storing Tokens in Local Storage

// BAD — vulnerable to XSS
localStorage.setItem('token', accessToken)

// GOOD — tokens set as httpOnly cookies by ESUS
// The /auth/login response sets httpOnly cookies automatically
// Your frontend never needs to store the token manually

2. Requesting Overly Broad Scopes

// BAD — requests more access than needed
scope: 'patient/*.read patient/*.write user/*.read system/*.read'

// GOOD — minimal necessary access for a read-only patient viewer
scope: 'patient/Patient.read patient/Observation.read'

3. Ignoring Emergency Override Audits

Emergency overrides (X-Emergency-Override: true) are fully logged. Set up alerts so your team is notified when they occur:

curl -X POST https://api.esus.health/fhir/Subscription \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/fhir+json" \
  -d '{
    "resourceType": "Subscription",
    "status": "active",
    "criteria": "AuditEvent?outcome=success",
    "channel": {
      "type": "rest-hook",
      "endpoint": "https://your-app.com/security-alerts",
      "payload": "application/fhir+json"
    }
  }'

4. Weak API Key Naming

Always use descriptive names for API keys so you know what to revoke if compromised:

# BAD
{ "name": "key1" }

# GOOD
{ "name": "prod-ehr-integration-2024", "scopes": ["Patient.read", "Observation.read"] }

Incident Response

If you suspect a token or API key has been compromised:

# 1. Log out the affected user session immediately
curl -X POST https://api.esus.health/auth/logout \
  -H "Authorization: Bearer COMPROMISED_TOKEN"

# 2. Delete the compromised API key
curl -X DELETE https://api.esus.health/api-keys/:id \
  -H "Authorization: Bearer ADMIN_TOKEN"

# 3. Create a new API key with a fresh secret
curl -X POST https://api.esus.health/api-keys/:id/rotate \
  -H "Authorization: Bearer ADMIN_TOKEN"

# 4. Review the audit log for unauthorized access
curl "https://api.esus.health/admin/audit/user/:userId" \
  -H "Authorization: Bearer ADMIN_TOKEN"

Security Monitoring

Set up automated alerting for failed access attempts:

# Subscribe to webhook alerts for failed auth
curl -X POST https://api.esus.health/fhir/Subscription \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/fhir+json" \
  -d '{
    "resourceType": "Subscription",
    "status": "active",
    "criteria": "AuditEvent?outcome=failure",
    "channel": {
      "type": "rest-hook",
      "endpoint": "https://your-app.com/security-alerts"
    }
  }'

Compliance Mappings

RegulationESUS Features
HIPAA § 164.312AES-256 encryption, Argon2id passwords, audit logging, consent gating
HIPAA § 164.308Role-based access control, emergency override with audit
GDPRConsent resource, data deletion, audit trail
SMART on FHIROAuth 2.0 PKCE, scoped access tokens, .well-known discovery

Regular Security Reviews

  • Review audit logs weekly via GET /admin/audit
  • Rotate API keys quarterly using POST /api-keys/:id/rotate
  • Audit role assignments monthly via GET /roles
  • Review active Consent records and expire stale ones