Security and privacy
Clatri handles your money, your health, your documents. That demands more than a login screen and a "your data is safe" promise. Clatri's security works in layers, and each layer solves a different problem. The right question isn't "does Clatri encrypt or not" -- it's what each layer protects, what depends on the server, and what depends on you.
The layers
| Layer | What it solves |
|---|---|
| Authentication + 2FA | Who you are, with optional TOTP verification |
| RLS (Row Level Security) | Which data belongs to you or has been shared with you |
| Private storage | Keeping files and documents from being publicly exposed |
| Disk encryption | Physical protection of infrastructure and backups |
| System encryption | Sensitive data the backend still needs to process |
| User encryption | Especially sensitive information, protected with your own key |
| Local protection | Secrets on your device and app lock |
These aren't alternatives. They're complementary. If one fails, the rest keep working.
Where everything lives
Your information isn't all in the same place. Clatri intentionally separates the infrastructure into three independent zones:
- Your device stores your session, the derived key, and local secrets in the operating system's secure storage. It never communicates directly with the database.
- The backend lives on a separate server. It receives your requests over HTTPS and uses your JWT to connect to the database -- which means every query it makes is subject to the same RLS restrictions as if you were making it directly.
- The database and storage live on infrastructure separate from the backend. The backend doesn't have free access to your data: it can only see and modify what your JWT allows according to each table's RLS policies.
The separation matters: compromising one doesn't automatically give access to the others. An attacker who gets into the backend doesn't have the data on disk without the database credentials. Someone with database access doesn't have the encryption keys that live on the backend. And someone holding your device faces the app lock and the operating system's secure storage.
Authentication
Your account authenticates with JWT (JSON Web Token) -- a signed token containing your identity that the app sends with every request. The backend validates it before doing anything: if the token is invalid or expired, the request gets rejected. But authenticating doesn't mean accessing everything. That's what the next layer controls.
Two-factor authentication (2FA)
From Settings > Security you can enable 2FA with TOTP (Time-based One-Time Password) -- a 6-digit numeric code that changes every 30 seconds and that only your authenticator app can generate. It works with Google Authenticator, Microsoft Authenticator, Authy, or any TOTP-compatible app:
- you enable 2FA from settings and Clatri shows you a QR code
- you scan it with your authenticator app
- you confirm with a 6-digit code
- Clatri shows you recovery codes -- save them somewhere safe, they won't be shown again
From that point on, every time you sign in (with Google or Apple), after the normal login Clatri asks for your TOTP code before granting full access. Your session starts at a basic security level and upgrades to full access only when you verify the code.
2FA is optional -- you decide whether to enable it. But if you enable it and lose access to your authenticator app without having the recovery codes, you won't be able to get back into your account. That's why it's important to save the recovery codes somewhere safe when you set them up.
RLS: database-level permissions
Clatri uses Row Level Security in PostgreSQL. Every row in every table has policies that evaluate, per query:
- your
user_id - the active entity
- whether you're the owner or the entity was shared with you
- your permission level (owner, editor, viewer)
- the domains you have access to (finances, health, management, chat)
This isn't an application-level filter you can bypass with a direct API call. It's a database-level restriction: if the policy says you can't read that row, PostgreSQL won't return it. It applies to both structured data and files in storage.
Private storage
Images and documents are stored in a private bucket, organized by entity and content type. There are no permanent public URLs. When you need to access a file, the path depends on whether that file is encrypted or not:
- Files without additional encryption (avatars, audio, general attachments): the backend generates a signed URL valid for 2 hours. The app uses it to load the file directly from storage and caches it locally until it expires. After 2 hours, it requests a new one.
- Encrypted files (health, finances, organization): these never get a signed URL. The app asks the backend for the file, which downloads it from storage, decrypts it in memory with the appropriate keys (system, user, or both), and returns the decrypted bytes directly. The encrypted file in storage is never exposed.
Disk encryption
The database and its backups run on infrastructure with disk-level encryption. If someone gained physical access to the storage medium, they wouldn't have the data in plain text.
This layer protects the infrastructure. It doesn't decide who can read a record inside Clatri -- that's RLS's job.
System encryption
System encryption exists for a specific scenario: someone gaining computational access to the database -- not physical access to the disk, but to the data itself -- and still not being able to read users' sensitive information. Fields and files encrypted with this layer are unreadable without the system key, which lives on the backend, not in the database.
It's used for:
- financial data and documents
- personal organization data and documents
- certain identifying data of the entity
The implementation uses AES-256-GCM -- authenticated encryption that protects both the confidentiality and integrity of the data. Each value is encrypted with a random 12-byte nonce, which means encrypting the same text twice produces different results.
Since the key is managed by the backend and not the user, features like sharing an entity, reviewing documents, or running automations keep working without asking you for an extra password at every step.
User encryption
User encryption exists for the most sensitive information -- today, mainly health data and documents. The idea here is that decryption shouldn't depend only on the server, but also on a key derived from your own password.
Your encryption password
At the end of onboarding, Clatri asks you for an encryption password. It's a separate credential from your login, with its own requirements: minimum 8 characters, uppercase, lowercase, numbers, and symbols.
When you set it up:
- the password travels over HTTPS to the backend
- the backend generates a random 16-byte salt and derives a 32-byte key with Argon2id
- the backend stores the salt and a verification token -- the result of encrypting a known string with your derived key, so it can verify in the future that a password reconstructs the correct key
- the backend returns the derived key to the app
- the app stores it in the operating system's secure storage
What's not stored on the server: your password, the derived key, or a decryptable copy of your data. Only the salt and the verification token.
Double layer
When the user key is available, protected data goes through two encryption layers:
- it's encrypted with your user key (AES-256-GCM)
- that result is encrypted again with the system key (AES-256-GCM)
The stored data is wrapped by both layers. Reading it requires both keys. To decrypt it, you go in reverse: first the system layer, then the user layer.
At runtime
The app doesn't send your password with every message to the agent. What it sends, when the operation requires it, is the derived key in the X-User-Encryption-Key header, inside the HTTPS/TLS connection. The backend uses it to decrypt or encrypt protected content during that specific operation.
Put differently:
- the password is only used for setup, unlock, change, or reset
- the derived key is used for normal operations on protected content
New device
If you sign in from a device that doesn't have the local derived key, Clatri asks for your encryption password once. The backend validates it against the stored salt, re-derives the key, and returns it so the app can store it locally.
Changing and resetting your password
If you change the password knowing the previous one, Clatri rotates the key and re-encrypts all affected content -- prescriptions, medical documents, health files.
If you do a reset without knowing the previous one, a new cryptographic setup is generated, but content protected with the previous key becomes unrecoverable. That's not a bug: it's the direct consequence of decryption depending on a credential the server can't reconstruct for you.
What gets encrypted and how
Not everything is encrypted the same way. The policy depends on the domain:
| Domain | Metadata | Files | Level |
|---|---|---|---|
| Health | User + system encryption | User + system encryption | Maximum |
| Finances | System encryption | System encryption | High |
| Organization | System encryption | System encryption | High |
| Other | No additional encryption | Private storage | Base |
In all cases, RLS and private storage apply. Encryption is the additional layer.
Local protection on the device
The app stores local secrets -- the derived key, the encryption password, and migration metadata -- in the operating system's secure storage:
- iOS/macOS: Keychain, with
firstUnlockThisDeviceaccessibility - Android: System-encrypted SharedPreferences
All values are stored with user-scoped keys, which prevents cross-account access on the same device.
App lock
In Settings you can enable app lock. When enabled, if the app spends more than 5 minutes in the background, it locks and requires local authentication to reopen:
- Face ID or Touch ID on Apple
- Fingerprint or biometrics on Android
- PIN, pattern, or system passcode as fallback, if the platform supports it
This protects physical access to the device. It doesn't replace the encryption password -- they're separate layers.
Your data is yours
From Settings > Export data you can download your information as Excel files:
| Export | Contents |
|---|---|
| Health report | Conditions, episodes, prescriptions, medications, body metrics, medical events |
| Financial snapshot | Accounts, cards, recurring payments, obligations, assets, savings, investments, and summary with net worth |
| Financial transactions | Expenses and incomes by date range, with category breakdown |
You can export a single entity as an Excel file (.xlsx) or multiple entities as a ZIP file. There are no locks or waiting periods -- your information belongs to you and you can take it with you whenever you want.
In summary
Clatri's security doesn't depend on a single lock. It combines strict database-level permissions, private storage, layered encryption with AES-256-GCM, key derivation with Argon2id, and local device protection. If one layer gets compromised, the rest keep limiting access to your information.