zautha

Security

Password hashing, session management, rate limiting, and tenant isolation.

Password Security

Hashing: Argon2id with the following parameters:

ParameterValue
Memory cost64 MB
Time cost3 iterations
Parallelism4
Salt length16 bytes
Hash length32 bytes

Policy:

  • Minimum 8 characters, maximum 128
  • No complexity requirements (per NIST SP 800-63B)
  • Checked against HaveIBeenPwned via k-anonymity API
  • Checked against top 100k common passwords
  • Context-specific checks: rejects passwords containing the user's email, username, or domain

Session Security

PropertyValue
Access token typeJWT (RS256)
Access token lifetime15 minutes
Refresh token typeOpaque (stored hashed in DB)
Refresh token lifetime7 days
Refresh token rotationYes (new token on each refresh)
Reuse detectionYes (all sessions revoked if a token is reused)

Cookies

CookieFlags
zautha_sessionhttpOnly, secure, sameSite=Lax
zautha_refresh_tokenhttpOnly, secure, sameSite=Strict, path=/v1/auth/refresh

CSRF protection: Double-submit cookie pattern. The zautha_csrf cookie value must be sent in the X-CSRF-Token header.

Rate Limiting

Implemented via Redis sliding window counters.

EndpointLimitWindowKey
Sign-in51 minIP + email
Sign-up31 minIP
Password reset31 houremail
Email verification51 houremail
Global10001 minIP

Account lockout: After 5 consecutive failed sign-in attempts, the account is locked with progressive durations: 15m, 30m, 1h, 2h.

Fail-closed: When Redis is unavailable, both the rate limiter and lockout service deny requests rather than allowing them through.

Tenant Isolation

Tenant isolation is enforced at multiple layers:

  1. Database — Every tenant-scoped table has a tenant_id column. EF Core global query filters ensure all queries include WHERE tenant_id = @current_tenant.
  2. API — The tenant_id is derived from the authenticated session's JWT tid claim. It cannot be overridden by the client.
  3. Cache — Redis keys are prefixed with tenant:{tenant_id}:.
  4. Logs and events — All log entries and domain events include tenant_id.
  5. Testing — Integration tests verify that a session from tenant A cannot access data belonging to tenant B.

Webhook Signatures

Webhook payloads are signed with HMAC-SHA256:

X-Zautha-Signature: t=1704067200,v1=abc123...

The signature is computed as:

HMAC-SHA256(key: webhook_secret, message: "{timestamp}.{raw_body}")

Webhook secrets are stored encrypted with AES-GCM.

JWT Structure

{
  "header": {
    "alg": "RS256",
    "typ": "JWT",
    "kid": "key_abc123"
  },
  "payload": {
    "iss": "https://auth.zautha.com",
    "aud": "proj_xyz789",
    "sub": "user_def456",
    "tid": "tenant_ghi012",
    "iat": 1704067200,
    "exp": 1704070800,
    "org_id": "org_jkl345",
    "org_role": "admin"
  }
}

On this page