Skip to main content

Authentication factors

Password

12-character minimum. Complexity validator requires upper, lower, digit, and special character. Checked against breached-password datasets.

TOTP (Authenticator app)

RFC 6238 time-based one-time passwords. Works with Authy, Google Authenticator, 1Password, Bitwarden, etc.

Passkeys (WebAuthn)

FIDO2 phishing-resistant authentication. Platform authenticators (Touch ID, Windows Hello) and roaming authenticators (YubiKey, Titan) both supported.

Google OAuth 2.1

SSO via Google Workspace. Enforced 2-factor at the IdP counts toward our 2FA requirement.
Magic-link sign-in is also available for recovery and low-friction flows, with short TTLs and single-use tokens. Magic links never substitute for 2FA on PHI-accessing accounts.

Session handling

  • httpOnly Secure cookie — JWT delivered as HttpOnly; Secure; SameSite=Lax. Not readable by JavaScript.
  • No Bearer tokens in client-side storage (localStorage / sessionStorage) — session state is cookie-only.
  • Payload TTL — JWT payload expires in 4 hours; refresh is automatic if the user is active.
  • Cookie TTL — 1 day, extending on activity.
  • Idle timeout — sessions terminate after 30 minutes of inactivity.
  • Signout — server-side revocation plus cookie clear; no stale token can survive logout.

Brute-force and enumeration resistance

  • Account lockout after 5 failed password attempts. Auto-unlock after 1 hour. Lockouts are logged to the security audit log.
  • Rack::Attack rate limiting on every sensitive endpoint, backed by Memorystore Redis for cross-instance consistency:
Endpoint classLimit
General requests300 / 5 min per IP
Auth (login, password reset)5 / 20 sec
2FA setup5 / 1 min
Passkey operations10 / 1 min
Email sending (per target address)3 / 5 min
Token verification (magic links)10 / 1 min
  • Timing-safe comparisons for all password and token checks.
  • Indistinguishable responses — invalid-email and wrong-password return the same generic error and the same latency, to prevent enumeration.
  • Cloud Armor adds a second layer at the load balancer: 500–1000 req/min per IP with a 5-minute ban on breach, plus OWASP CRS v3.3.

Authorization

Every API action is gated by object-level authorization via Pundit. No request escapes without an explicit policy decision.
  • Global enforcementApplicationController sets after_action :verify_authorized. Any controller action that doesn’t call authorize or explicitly skip_authorization raises in development and fails in production.
  • 48 policy files cover every PHI-bearing model and every admin action.
  • Role-based authorization layered on top:
RoleDescriptionPHI access
userStandard userOwn data only
analystReporting / analyticsAggregated or anonymized only
supportCustomer supportRead-only PHI access, scoped to assigned org
adminOrg administratorFull access within the org
super_adminDenialbase internalFull platform access; actions audit-logged

Delegation and API access

  • Human-to-system delegation (scoped task tokens, currently in design) — future capability for letting staff authorize Denialbase to take a specific action on their behalf.
  • API tokens for server-to-server integrations have narrow scopes and short TTLs.
  • All authentication and authorization decisions are recorded in the security audit log.

Identity providers

  • Google OAuth 2.1 — live.
  • SAML 2.0 SSO (Okta, Azure AD, Google, any SAML IdP) — see SSO setup.
  • SCIM provisioning — planned for Q3 2026.