Security: how your platform credentials are protected
Platform credentials are protected by encrypting every OAuth token at rest with AES-256-GCM and isolating them per organization rather than pooling them. Connecting an ad account means handing over a token that can read and change real spend, so the storage of that token is the part worth scrutinising — and the encryption key refuses to fall back to a development default in production.
How credentials are stored
- AES-256-GCM, an authenticated cipher — tampering with stored ciphertext is detected on decrypt rather than silently producing garbage.
- A unique initialization vector per value, so two identical tokens don't produce identical ciphertext.
- Fail-closed in production. If the encryption key is missing, the app refuses to start that path rather than falling back to the development key that ships in the source. A public fallback key in production would make every stored token readable, so the failure is deliberate and loud.
- Per-organization isolation. Credentials belong to one organization and are only resolvable inside it.
What happens when you disconnect
Removing an integration deletes the stored credential rows, and the in-memory cache of resolved tokens is invalidated at the same time — a decrypted token must not outlive the row it came from. That ordering matters: a disconnect that clears the database but leaves a warm cache is a disconnect that didn't happen yet.
Scopes are requested narrowly
The other half of credential security is asking for less. Where a narrower scope does the job we use it — report exports use Google's drive.file scope, which grants access only to files the app itself created, rather than a full Drive read scope. See the AdMob OAuth scopes write-up for how we approach that choice generally.
Authentication
User authentication and organization membership run through Clerk. We don't store passwords — there is no password database of ours to breach.
Frequently asked questions
- How are my ad platform credentials stored?
- OAuth tokens are encrypted at rest with AES-256-GCM using a per-value initialization vector, and are scoped to a single organization. In production the app refuses to operate that path if the encryption key is missing rather than falling back to a development default.
- What happens to my tokens when I disconnect an integration?
- The stored credential rows are deleted and the in-memory cache of resolved tokens is invalidated at the same time, so a decrypted token cannot outlive the row it came from.
- Do you store my password?
- No. Authentication runs through Clerk, so there is no password database on our side.