Security & keys

The two-key model

Client key ck_live_ / ck_test_Server key sk_live_ / sk_test_
LivesBrowsers, mobile apps — public by designYour servers only
CanRegister devices, identify (verified), track events, read that user's own inboxEverything: send, read, segments, users
CannotSend anything, read any list, touch config — structurally, not by policy
If leakedWorst case: junk registrations in your app (rate-limited, hygiene-culled)Rotate immediately — mint a new key, revoke the old

Anyone can decompile your app and extract the client key — the design assumes it, the same way Stripe's publishable keys do. Our secret-scanning pattern (sk_(live|test)_[A-Za-z0-9_-]{43}) deliberately matches only server keys, so GitHub flags real leaks without false-alarming on intentionally-public client keys.

Identity verification (do this)

The one meaningful client-side attack: calling identify("victim-id") with an extracted client key to receive someone else's notifications. Close it in five minutes:

  1. Dashboard → Setup → Generate identify secret (shown once, store server-side).
  2. Your server signs each logged-in user: hex(hmac_sha256(secret, external_id)) — or just signIdentify() from @notibase/node.
  3. Frontend passes the signature to identify().

Once a secret exists, unsigned or wrongly-signed identify calls are rejected (403, constant-time comparison). Rotating the secret invalidates all outstanding signatures.

Your push credentials

APNs .p8 keys, FCM service accounts, and BYO LLM keys are validated at upload (a malformed key is rejected with the reason, before it can ever fail a send), encrypted at rest, and never returned by any API. Uploading replacements auto-revokes the previous set. Delete a credential and sends over that channel stop immediately.

Tenant isolation

Every query is scoped to your app at the application layer, backed by Postgres row-level security bound per-request, and the isolation is enforced by a cross-tenant probe suite that runs in CI on every change — a regression is a failed build, not an incident. Delivery logs, devices, users, segments: another tenant's key or session gets 404s and empty lists, never your data.

Sending discipline (protects your users and your reputation)

Idempotency keysRetries and double-clicks can never double-notify.
Rate limits & quotasA runaway loop 429s before it becomes a reputation event.
Token hygieneDead tokens expire on first bounce; counts stay honest.

Reporting

Vulnerabilities: [email protected] — we respond fast and credit reporters. Abuse by a Notibase customer: [email protected].