RLS · Passkeys · MLS · Audit-by-design

Security isn’t a feature. It’s the architecture.

Eight rules concrete enough to fail a code review. Sourced directly from our internal principles document — not marketing copy bolted on top.

S1

Tenant isolation lives in the database, not the application.

Every multi-tenant table has a workspace_id column. Postgres Row-Level Security policies enforce isolation as a hard backstop — a forgotten WHERE clause in application code cannot leak data across workspaces. The application sets the current workspace per request; RLS policies reference it. We chose this after watching Microsoft Teams ship a cross-tenant bypass that came down to trusting the application layer.

sql
SET LOCAL app.current_workspace = ?;

CREATE POLICY tenant_isolation ON messages
  USING (workspace_id = current_setting('app.current_workspace')::uuid);
S2

No bytes leave the server that the client doesn’t need.

In 2017 Slack shipped hashed user passwords to other workspace members for four years through shared invite links. The lesson: every API response is hand-shaped. We never serialize a model directly. Explicit resources (UserResource, MessageResource) allowlist exactly the fields a given endpoint returns. If a field isn’t named, it doesn’t go on the wire.

S3

Sessions are bound to context, not just identity.

Slack’s 2022 breach used stolen session cookies to act as employees. Sessions in OmniTeam are bound to IP class, user-agent fingerprint, and a device-bound key in the Secure Enclave / StrongBox / WebAuthn. Token theft alone is not enough to impersonate. A substantial context change forces a silent rebind, not a logout modal — security that doesn’t punish the user.

S4

Multi-factor by default. Passkeys-first. SMS never.

New accounts default to passkey registration with a single Continue tap. TOTP is the fallback. SMS is never offered — SIM swap attacks make it strictly worse than nothing. Production workspaces have no passwords-only path. SSO via OIDC is on every paid tier as a self-serve toggle, not a sales call.

S5

WebSocket auth is signed, scoped, and short-lived.

Every channel subscription requires a Sanctum-signed authentication callback that proves the user has access to that specific channel. The signature includes channel ID, user ID, workspace ID, and an expiry. A leaked auth token cannot be replayed against a different channel. The realtime layer is not a trust shortcut.

pseudocode
sig = HMAC_SHA256(secret, channel_id|user_id|workspace_id|expiry)
// The client cannot mint this. The server's realtime auth endpoint does.
// expires after 60 seconds.
S6

Rate limits are layered, not single-point.

Each layer protects a different failure mode. Per-user-per-endpoint limits stop compromised accounts. Per-IP-per-endpoint limits at the edge stop botnets. Per-workspace limits inside Octane stop runaway integrations. Per-WebSocket-connection limits stop abusive clients. Defense in depth is cheaper than incident response.

config
• Per-user, per-endpoint   → Laravel RateLimiter
• Per-IP, per-endpoint      → Bunny.net edge / Caddy
• Per-workspace             → Octane in-process
• Per-WS-connection         → Reverb config
S7

End-to-end encryption is opt-in per channel — and we say so.

E2EE-by-default destroys server-side search, link unfurling, mobile push previews, and history-on-a-new-device. For B2B chat, those capabilities are often required. We implement E2EE channels using the MLS protocol (RFC 9420), which scales to hundreds of members; Signal Double Ratchet does not. The UI tells you when a channel is E2EE and what’s degraded by design — no false promises.

S8

We don’t retain what we don’t need.

Telemetry uses Plausible — no user identifiers, no cross-site tracking. Logs are scrubbed of PII at write-time and retained 30 days. Backups are encrypted at rest, 90-day retention, then irreversible deletion. Right-to-erasure (GDPR Art. 17) is implemented as content tombstoning, not row deletion — see I3 in our integrity principles.

Read the full Principles document on GitHub →

— BEGIN —

Start your workspace in 60 seconds.

Free for teams up to 10. No credit card. No call required.

Create your workspace →

or read the security model first →