Architecture
Resource model
seekrit is multi-tenant. Resources nest from organizations down to individual secrets:
organizations ─┬─ members (users, via org_memberships with a role)
├─ applications ── environments ─┬─ secrets (+ version history)
│ └─ key grants (wrapped DEKs)
├─ service tokens
└─ audit log (append-only)
- Organization — a tenant. Has members, applications, service tokens, and its own audit trail.
- Application — a deployable (a service, site, or worker) within an org.
- Environment — a named context under an application (
production,staging,ci,ephemeral-agent-42, …). Each environment owns one data key. - Secret — a named, encrypted value in an environment. Every write appends a new version.
- Key grant — a wrapped copy of an environment's data key for one principal.
Roles
Membership carries a role: owner > admin > member.
- Admin and owner manage structure (apps, environments), service tokens, key grants, and can read the audit trail.
- Members read and write secrets in environments they hold a key for.
The real access boundary is cryptographic: you can only decrypt an environment if you hold a key
grant for it. Roles gate the management API on top of that. Non-members receive 404s for an org
so its existence can't be probed.
Cloudflare building blocks
seekrit is designed to run entirely on a Cloudflare account.
| Component | Cloudflare product | Role |
|---|---|---|
| API | Workers | The Hono API worker |
| Database | D1 (SQLite) | Orgs, users, secrets (ciphertext), grants, audit |
| Cache | KV | Cached identity-provider JWKS (and future session/rate-limit state) |
| Web dashboard | Workers (via OpenNext) | Next.js app serving the browser client |
The API and web app deploy as separate Workers. D1 and KV are provisioned as bindings; the CLI
wrangler handles migrations and deploys.
Request lifecycle
- A request arrives at the API worker with a credential — a Stytch session JWT, a service token, or (locally) a dev-user header.
- Auth middleware resolves the actor (a user or a service token) and, for org-scoped routes, checks membership and role.
- The handler reads or writes ciphertext in D1. It never handles plaintext secrets.
- Any mutating action (and secret reads) writes an entry to the append-only audit log before the response returns.
Authentication
- Web — Stytch B2B sign-in (Google/GitHub OAuth discovery). The browser holds the session; its JWT is sent as a bearer token and verified by the API against Stytch's JWKS (cached in KV).
- CLI / machines — service tokens (
skt_…) sent as bearer tokens. - Local dev — an
x-seekrit-dev-userheader, enabled only when the API runs withAUTH_MODE=dev.
The first time a valid session proves access to a Stytch organization, seekrit provisions the matching org and membership just-in-time.