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:
- Generates
dk_<48 hex>(192 bits of entropy). - Computes SHA-256 of that string.
- Stores only the hash + a 10-char prefix (for UI display).
- 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 orgunlisted— anyone with the URLpublic— 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.
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.
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
- Go to Settings → API keys and revoke the key immediately.
- Mint a new key, paste it into your agent's config.
- 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.
- 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
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