How it's encrypted
TLS 1.3 in transit (Let's Encrypt). External API keys, bank tokens, and broker secrets — AES-256-GCM with a unique IV per record. Passwords — bcrypt (12 rounds). Encryption key lives in env, not in the database.
Beveiliging
MyFina is uw huishoudboekje. Financiële gegevens behandelen we met extra zorg: we laten zien hoe ze beveiligd zijn zonder marketing-gedoe.
Drie korte antwoorden op de belangrijkste vragen
TLS 1.3 in transit (Let's Encrypt). External API keys, bank tokens, and broker secrets — AES-256-GCM with a unique IV per record. Passwords — bcrypt (12 rounds). Encryption key lives in env, not in the database.
PostgreSQL 16 in a managed instance at Hetzner (Germany, EU). Isolated Docker network, no external connections to the DB. Backups — daily, encrypted before upload, 30-day retention.
Account hard-delete in a single frame: transactions, accounts, categories, currencies, tokens cascade-removed. No soft-delete tables, no "just in case" archive. Marketing leads under the same email — separate erase-hook (GDPR Art. 17).
Zes pijlers van beveiliging
NextAuth.js v5 on JWT, passwords hashed with bcrypt. Login throttling — 5 attempts / 15 min per identifier and 20 / 15 min per IP. Optional Google OAuth. Password reset uses a 32-byte token; only its SHA-256 is stored.
External API keys (banks, Resend, Anthropic) and broker secrets are encrypted with AES-256-GCM. The key never leaves the server. Each bank connection carries a per-connection 32-byte hex webhook secret.
Every UPDATE/DELETE filters by `userId`. IDOR protection is centralized in `assertCanAccessAccount/Category` — access to another user's account returns 403, not 404. Shared family accounts use explicit OWNER/MEMBER/VIEWER roles.
JWT with an incrementing `session_version`. Password change, account block, or role change invalidate all live sessions. Mobile-API refresh tokens rotate on every refresh.
Hard-deleting the account removes all transactions, accounts, and categories cascading in a single transaction. Data export — CSV/XLSX/PDF, one click. Cookie consent with two categories (essential / functional), no analytics, no trackers.
All admin actions and sensitive user operations are written to `audit_log` with IP, user-agent, and source. Login-attempt logs are kept 30 days. Stripe webhook events sit in a dedicated idempotency journal for safe replay on failure.
What we do NOT do
If you connect Monobank or a PSD2 bank via GoCardless, we only receive what's needed to sync transactions: outbound payments, incoming transfers, account balances. No bank-side personal data (passport, photo, biometrics). The bank API token is stored encrypted with AES-256-GCM; you can revoke access in one click from Settings → Banks. GoCardless consent expires every 90 days per PSD2 requirements — we remind you 7 days in advance.
Deeper details
Full list of third-party services processing your data: Hetzner (hosting), Stripe (billing), Resend (email), Anthropic (AI, DRAFT), GoCardless (PSD2), Monobank API, FCM.
Open listPer-feature matrix: what's stored, how long, how it's deleted. GDPR Art. 15/17/20 flow and retention windows per entity.
Open matrixCommon questions about security
Servers are hosted at Hetzner's Frankfurt data centre, Germany (EU). The data controller is MyFina's owner — no aggregator middlemen, no US-based cloud providers. The full subprocessor list is on /security/subprocessors.
At least 30 days before shutdown we email you with a notice and a one-click "Download everything" button (CSV / XLSX / PDF). After the grace period the database is destroyed. This is an operational commitment in our Terms, not a marketing promise.
Yes. Settings → Data → Delete account is a hard-delete in a single DB transaction: transactions, accounts, categories, tokens, and marketing leads tied to the same email are wiped cascadingly. No soft-delete, no "just in case" archives. Fully compliant with GDPR Art. 17 (right to be forgotten).
No "staff" has routine access to your financial rows. The owner can only reach the database during a security incident or with your explicit support request. All admin actions are recorded in audit_log with IP and user-agent.
Browser sessions are JWTs with a TTL, not "logged in forever". If your current browser is signed out, nobody can sign in without the password. If a session is active — use OS lock-screen and/or change your password from any other device (this invalidates all active sessions instantly).
No. We don't run a single analytics script on user pages. The cookie banner shows only two categories — essential (NextAuth session) and functional (referral links). There's no analytics category because there's nothing to analytics.
What you can verify yourself
Every claim above is auditable via code and API.
src/lib/crypto.ts (AES-256-GCM, randomBytes IV, auth tag).src/auth.ts, src/lib/auth/rate-limit.ts.src/lib/auth/ownership.ts (assertCanAccessAccount).https://app.my-fina.com/api/openapi (OpenAPI 3.1).https://app.my-fina.com/api/health (public liveness).Abonneer u om op de hoogte te blijven van CVE's, beveiligingspatches en uitbreidingen van het dreigingsmodel. Geen marketing.