System & security architecture

The architecture behind a password manager you can actually audit.

Qeva is a layered, open-source platform where every secret is sealed with authenticated encryption, every action is governed by database-driven access control, and your personal vault stays mathematically out of reach - even on a server you host yourself.

256-bit
AES-GCM authenticated encryption
150K
PBKDF2 iterations per key
7
independent defense layers
0
plaintext secrets stored
01 - System architecture

Seven layers, one request path.

A request flows top to bottom through cleanly separated tiers. Each layer owns one responsibility - and never trusts the layer above it.

system-architecture.svgRequest path
Layer 7 · PlatformUser · Browser1PresentationNext.js · React UI2EdgeMiddleware · session · CSRF3APIRoute handlers · Zod · scopes4DomainEncryption · RBAC · sessions5PersistencePrisma ORM · parameterized6StorageDatabase · ciphertext at rest

Request flows top to bottom; the encrypted response returns up the same path.

01
Presentation

Client & UI

Server-rendered React with client-side crypto helpers.

Next.js App RouterReact + TypeScriptTailwind CSSClient crypto helpers
02
Edge

Middleware & guards

Every route is checked before it runs.

Route-guard middlewareSession validationCSRF protectionRate limitingSecurity headers
03
API

Route handlers

REST endpoints with dual authentication.

API route handlersSession authBearer token scopesZod validationVersioned /api/v1Webhooks
04
Domain

Services & crypto

Business logic, encryption, and schedulers.

Encryption servicePer-user encryptionRBAC permissionsSession trackingSecurity scansSAML SSOBackup scheduler
05
Persistence

ORM

Type-safe, parameterized data access.

Prisma clientTyped modelsParameterized queriesSQL-injection safeConnection pooling
06
Storage

Database

Encrypted secrets at rest, on a database you run.

PostgreSQLMySQLSQLiteSQL ServerCiphertext-only secrets
07
Platform

Infrastructure

TLS, reverse proxy, CI/CD, and observability.

Node HTTPS serverNginx reverse proxyCI/CD pipelinesystemd serviceStructured loggingSMTP email
02 - Request lifecycle

Follow one secret through the stack.

From an authenticated click to an encrypted row and back - every request is validated, authorized, and audited.

read-password.sequence.svgSequence
ClientNginx · TLSMiddlewareAPIRBACDatabase01GET /api/passwords/:id02proxy · security headers03validate session · CSRF04route authorized05requires PASSWORD:READ06granted07parameterized query08encrypted row09AES-256-GCM decrypt + audit10200 · secret revealed

A single authorized read, validated and audited end to end.

GET /api/passwords/:idReading a secret the caller is allowed to see
01

Client

The client sends an HTTPS request carrying an HttpOnly session cookie or a scoped Bearer token.

02

TLS / Nginx

Nginx terminates TLS and reverse-proxies to the Node HTTPS server, adding strict security headers.

03

Middleware

Middleware validates the session, blocks unauthenticated routes, and enforces CSRF before the handler runs.

04

API + Zod

The route handler validates input with Zod, rejecting anything malformed at the boundary.

05

RBAC check

A database-driven access check confirms the caller holds the required permission or token scope.

06

Prisma / DB

Prisma runs a parameterized query - no string concatenation, no SQL-injection surface.

07

Decrypt + audit

The service decrypts the ciphertext with AES-256-GCM only for the authorized caller, then writes an immutable audit-log entry.

03 - Encryption model

Two vaults. Two threat models. One cipher.

Every secret is sealed with AES-256-GCM. What changes is who holds the key - so privacy and collaboration never fight each other.

zero-knowledge-vault.svgUSER_MASTER
PBKDF2 · 150KunwrapsealstoreMaster PasswordMaster Key256-bit DEKPlaintext SecretAES-256-GCM128-bit IV · tagCiphertextiv · authTag · dataDatabaseciphertext only

The master password and derived keys never touch disk - only ciphertext is stored.

USER_MASTER

Personal - zero-knowledge

Only the owner can decrypt. Not the server. Not us.

01

Master password stays with the user

It is never transmitted to storage and never persisted - it exists only long enough to derive a key.

02

Derive the master key

PBKDF2 stretches the password against a per-user random salt into a 256-bit key.

PBKDF2-HMAC-SHA256 · 150K iters · 256-bit salt
03

Unwrap the data key

The master key unwraps a random 256-bit DEK generated at setup; a hash of the DEK validates authenticity later.

DEK = decrypt(wrappedDEK, masterKey)
04

Seal the secret

The DEK encrypts the secret with authenticated AES-256-GCM, with a fresh IV and auth tag per operation.

AES-256-GCM · 128-bit IV · 128-bit tag
05

Store ciphertext only

The database holds only { version, iv, authTag, encrypted }. No plaintext, no master password, no unwrapped key ever touches disk.

PUBLIC_KEY

Team & global - shared by policy

Shared secrets, governed by roles - never a shared login.

01

Generate a per-scope key

Shared team and global vaults get a random 256-bit DEK, independent of any single user password.

DEK = randomBytes(32)
02

Seal the secret

The secret is encrypted with the same authenticated AES-256-GCM cipher used everywhere in Qeva.

AES-256-GCM · 128-bit IV · 128-bit tag
03

Wrap the key for the group

The DEK is encrypted under the team key pair, so access belongs to a group - not baked into one person’s login.

wrappedDEK = encrypt(DEK, publicKey)
04

Authorized members decrypt

Access is gated by RBAC and membership; revoking a member needs no password rotation.

DimensionPersonal · USER_MASTERTeam & global · PUBLIC_KEY
ScopePrivate personal vaultShared team & org-wide vaults
Key custodyUser master password (zero-knowledge)Team / organization key pair
Who can decryptOnly the ownerAll authorized members
Data cipherAES-256-GCMAES-256-GCM
Key derivationPBKDF2-HMAC-SHA256 · 150K itersRandom DEK, wrapped for the group
Best forMaximum individual privacyTeam collaboration & continuity
04 - Defense in depth

Seven independent lines of defense.

Security isn't a single wall - it's overlapping controls. A failure in any one layer is contained by the next.

01

Transport

  • TLS / HTTPS everywhere
  • HSTS & secure headers
  • Node HTTPS server
02

Perimeter

  • Nginx reverse proxy
  • Middleware route guards
  • CSRF + rate limiting
03

Authentication

  • Session auth + JWT
  • Email OTP verification
  • SAML 2.0 SSO
  • Argon2 / bcrypt hashing
04

Authorization

  • 29-permission RBAC
  • System + custom roles
  • Scoped API tokens
  • DB-enforced on every call
05

Data at rest

  • AES-256-GCM secrets
  • Zero-knowledge personal vault
  • Encrypted session cookies
06

Integrity & recovery

  • GCM authentication tags
  • HMAC-SHA256 signed recovery
  • Data-key hash validation
07

Assurance

  • Immutable audit logs
  • Structured logging
  • Encrypted scheduled backups
05 - Technology

A deliberately modern, boring-in-the-best-way stack.

Proven building blocks, chosen for type safety, security, and long-term maintainability.

Frontend

Next.jsReactTypeScriptTailwind CSSFramer MotionRecharts

Backend

API routesNextAuth.jsNode.jsZodJob scheduler

Data

PrismaPostgreSQLMySQLSQLiteSQL Server

Security

AES-256-GCMPBKDF2Argon2bcryptSAML 2.0JWT

Platform

NginxCI/CDsystemdWinston logsSMTP email

Quality

TypeScript strictESLintAPI test suiteStructured logging

Don't trust it. Verify it.

Every layer here is open source under the AGPL. Read the code, audit the crypto, and run it on infrastructure you control.