Skip to content
Docs · Account & billing

Security & data isolation

Two-factor sign-in, scoped API keys, read-only AI connectors, and how one customer's data is kept apart from another's at every layer.

View as Markdown
All topics
On this page

Every request is checked the same way: who is calling, which workspace, what their role allows, and whether the resource belongs to that workspace's project. An id from another workspace answers 404 before any work happens.

Your account

  • Two-factor sign-in: Settings → Account. Scan the code with an authenticator app, confirm a code, and keep the recovery codes. Sign-in then asks for a code (the API answers { mfaRequired, ticket }; complete with POST /api/auth/login/mfa { ticket, code | recoveryCode }). Turning it off needs your password and a code.
  • Changing your email needs your current password (and a code when two-factor is on), then a code sent to the new address. The old address is told.
  • A password reset or change signs out your other sessions and disconnects AI connectors.
  • Sessions last 30 days; Settings lists them and signs the others out.
  • Changes made with the dashboard cookie are refused when they come from another site.

Keys and connectors

  • API keys can be read-only, limited to one project, or both (see API keys & authentication). Give each app the narrowest key that works.
  • AI connectors are connected read-only or read-and-manage; a read-only connector cannot change anything. Changes still ask you first in the assistant.
  • No key or connector can change your email, password or sessions, accept invitations, or move money out — those need you in a browser.
  • Revoke keys in Settings → API access and connectors in Dashboard → Connectors; both take effect immediately.

How your data is kept apart

LayerSeparation
Every API callYour credential resolves to one workspace; resources are found through project → workspace, never by id alone.
DatabasesEach database is its own SQLite database. SQL in one can never reach another.
StorageEach bucket is its own bucket in object storage; a signed URL is for one key in one bucket.
Vector DBOne index per collection.
MemoryRows in Harakumo's control database, keyed by store and scope; searches never cross scopes.
Functions and static sitesEach runs as its own isolated edge program with only its project's environment variables and no access to platform storage.
Server appsEach deployment runs in its own container.
Auth poolsOne per project, with its own signing secret.
PaymentsBuyers pay into Harakumo's processor account; each project's share is tracked in a ledger, and withdrawals go only to the payout account the workspace owner connected.
MailEach workspace sends from no-reply@harakumo.com or from its own verified domains (a domain belongs to one workspace), with its own log and suppression list.
DomainsEach root domain has one owning workspace; no other workspace can add a hostname under it.

How secrets are stored

  • Passwords (yours and your end users'): PBKDF2 hashes.
  • Sessions, API keys, connector tokens and auth-pool client secrets: SHA-256 hashes; the plaintext is shown once.
  • Two-factor recovery codes: hashed, and each works once.
  • Environment variables and auth-pool JWT secrets: stored readable, because they are injected into deploys and used to sign tokens. Encryption at rest is planned.

Reference

REST
POST /api/auth/login           { "email", "password" }        → session, or { mfaRequired, ticket }
POST /api/auth/login/mfa       { "ticket", "code" | "recoveryCode" }
GET|POST|PUT|PATCH|DELETE /api/auth/mfa   # status, set up, confirm, new recovery codes, turn off (browser session)
GET  /api/auth/sessions · DELETE                                # sign out other sessions
GET  /api/security/overview    # the workspace's security checks