seekrit
Docs/Architecture

Architecture

Resource model

seekrit is multi-tenant. Resources nest from organizations down to individual secrets:

organizations ─┬─ members (users, via org_memberships with a role)
               ├─ groups ──────── environments ─┬─ secrets (+ version history)
               ├─ applications ─── environments ─┤   (shared, reusable secret bags)
               │        └─ composes groups        └─ key grants (wrapped DEKs)
               ├─ service tokens (bound to one app environment)
               └─ audit log (append-only)
  • Organization — a tenant. Has members, applications, groups, service tokens, and its own audit trail.
  • Application — a deployable (a service, site, or worker) within an org.
  • Group — a reusable secret bag shared across applications (e.g. common-backend, auth-providers). Like an application, it owns environments keyed by slug.
  • Environment — a named context (production, staging, dev, …) owned by either an application or a group. Each environment owns one data key.
  • Composition — an application environment pulls in one or more groups, matched by slug. At read time the layers merge, lowest precedence first: group secrets < app secrets.
  • 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.
  • Service token — bound to one application environment; that binding selects the org, app, and environment it resolves at runtime, plus the group slices composed into it.

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 runs entirely on Cloudflare's edge.

ComponentCloudflare productRole
APIWorkersThe Hono API worker
DatabasePostgres (PlanetScale, via Hyperdrive)Orgs, users, secrets (ciphertext), grants, audit
CacheKVCached identity-provider JWKS (and future session/rate-limit state)
Web dashboardWorkers (via OpenNext)Next.js app serving the browser client

The API and web dashboard run as separate Workers, backed by Hyperdrive (database) and KV bindings.

Request lifecycle

  1. A request arrives at the API worker with a credential — a Stytch session JWT (web), a CLI session (a signed-in human at a terminal), or a service token (machines).
  2. Auth middleware resolves the actor (a user — whether from a browser session or a CLI session — or a service token) and, for org-scoped routes, checks membership and role.
  3. The handler reads or writes ciphertext in Postgres. It never handles plaintext secrets — including the ciphertext of a value that references another secret, which the client expands after decrypting.
  4. Any mutating action writes an entry to the append-only audit log before the response returns. High-volume environment resolves are metered for usage/billing instead of audited per call (denied resolves are still audited).

Authentication

  • Web — Stytch B2B sign-in (Google/GitHub OAuth discovery, or email/password 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). The auth method is opaque to the API — every method yields the same session JWT, so nothing server-side changes per method.
  • CLI (you)seekrit login opens a browser, you authorize the device, and the CLI saves a CLI session (skc_…) that authenticates as your user. The CLI generates that token itself and registers only its hash, so the credential never travels through the API. It carries no key material: decryption still unlocks your own private key with your passphrase, on your machine.
  • CLI / machines (unattended) — service tokens (skt_…) sent as bearer tokens.
  • Agents — Stytch M2M client credentials (OAuth client-credentials), sent as HTTP Basic auth or as a pre-fetched access token. Agents self-register at /v1/signup and authorize against seekrit's own client→org mapping (never token claims). A machine credential holds no key material, so it bootstraps a service token for anything that touches ciphertext.

The first time a valid session proves access to a Stytch organization, seekrit provisions the matching org and membership just-in-time.