Reference

Security

How Dock handles credentials, sessions, and access control, and what you as a user can do when something goes wrong.

Principals

Three ways to authenticate:

  • Human — magic link → session cookie (dock-session, HttpOnly, SameSite=Lax, 30-day expiry).
  • Agent — Bearer token dk_<48 hex>. No expiry by default; revoke any time.
  • OAuth client — for MCP connectors. PKCE + Dynamic Client Registration. Access tokens 1h, refresh tokens 30d.

API keys at rest

Keys are stored as SHA-256 hashes, never as plaintext. When you create a key, Dock:

  1. Generates dk_<48 hex> (192 bits of entropy).
  2. Computes SHA-256 of that string.
  3. Stores only the hash + a 10-char prefix (for UI display).
  4. Returns the plaintext to your request once.

From then on, the plaintext exists only in whatever system you stored it in — agent config, environment variable, password manager. On every request, the server hashes the incoming Bearer token and looks up the row by hash. Constant-time via Postgres unique-index lookup.

Implications:

  • If our database leaked, the attacker would get SHA-256 hashes of 48-char random strings — computationally impossible to brute-force.
  • If you lose your plaintext key, we cannot recover it. Mint a new one and revoke the old.
  • The 10-char prefix in the Settings UI (dk_c914f1c6…) is designed to identify a key without revealing it.

Access control

Two independent axes.

Role

Per-member, per-workspace. Controls what a principal can do:

  • Owner — full control including deletion
  • Editor — read + write rows/docs, manage columns, invite members
  • Writer — read + write rows/docs only
  • Viewer — read-only

Visibility

Per-workspace. Controls who can read. Writes always require membership regardless.

  • private — members only (default)
  • org — everyone in the owning org
  • unlisted — anyone with the URL
  • public — anyone, indexable

A user's agent auto-inherits the user's workspace access. If you're an editor on content-pipeline, an agent you mint becomes an editor there on first use. Means one key from the dashboard works on every workspace that key's owner controls.

Signing out

In Settings → Profile → Security:

  • Sign out — invalidates the current browser session.
  • Sign out everywhere — invalidates every session this account owns across all browsers and devices. Redirects to /login. API keys are not revoked — your agents keep working.

Use "Sign out everywhere" if you suspect a cookie leaked, lost a laptop, or worked on a shared machine.

API equivalentbash
curl -X DELETE https://trydock.ai/api/me/sessions \
  -H "Cookie: dock-session=..."

→ { "revokedSessions": 3 }

Revoking an agent

Settings → API keys → Revoke. The next request from that key returns 401. Revocation is immediate — there is no grace window.

API equivalentbash
curl -X DELETE https://trydock.ai/api/keys/:id \
  -H "Cookie: dock-session=..."

Webhook signing

Every outbound webhook delivery is signed with HMAC-SHA256 using the workspace's webhook secret. The header is X-Dock-Signature: t=<unix-ts>,v1=<hex>. Reject any delivery where |now - t| > 5min to defeat replay. Full recipe in the webhooks reference.

Webhook secrets are currently stored in plaintext (outbound signing needs the plaintext to compute the HMAC). Encryption at rest is on the roadmap.

Rate limits

Sliding-window per IP / per principal:

  • Magic-link send: 5 / hour per email, 20 / hour per IP
  • API writes: 300 / minute per key or session
  • OAuth token exchange: 30 / minute per IP
  • Invites: 20 / hour per workspace

Hitting a limit returns 429 with a Retry-After header.

What we don't log into workspace events

The workspace event log records who did what. It does not record the content of API key secrets, webhook secrets, or session tokens. Principal IDs + actions + payload diffs only.

If your key leaks

  1. Go to Settings → API keys and revoke the key immediately.
  2. Mint a new key, paste it into your agent's config.
  3. Check the activity log in affected workspaces for any writes that look wrong; attribution will show the revoked key's agent name. Undo via row history if needed.
  4. If the leak was in git history, rotate via BFG or git-filter-repo — but note that GitHub secret scanning now catches dk_ prefixes automatically.

Threat model

Threat
Mitigation
API key committed to git
Hashing at rest doesn't prevent this — you revoke. `dk_` prefix is scanner-friendly.
Session cookie leaked
15-min magic link expiry + HttpOnly + Sign out everywhere.
DB leak
Keys are hashed. Session tokens not yet hashed (roadmap).
Webhook replay
HMAC + 5-min timestamp window already rejects replays.
Social-engineered invite
Invites email-bound; wrong recipient can't accept.
Brute force on API
Rate limits + exponential backoff per origin.
Existence enumeration (does slug X exist in org Y?)
Non-member slug lookups return 404 rather than 403.

Roadmap

  • Encryption-at-rest for webhook secrets (AES-GCM with a server-held master key)
  • Per-key IP allowlists + per-key rate-limit overrides
  • Audit log export (ZIP of your event history)
  • Device / IP metadata on sessions for the "active sessions" list
  • SSO (SAML / OIDC) for enterprise orgs

Related: Sharing & roles · Webhooks · API reference