Docs · End user

End user guide

FortPass is unlocked with a PIN (4–8 digits). From that PIN, an AES-256 key is derived that encrypts accounts, cards, banks, notes, documents and TOTP secrets before they touch the database. Without the PIN, what's in the DB is noise — server, admin and support team cannot decrypt it.

Quick glossary

TermMeaning
PIN4–8 digits. Master key. Bcrypt-hashed in DB, never in plaintext.
vault_keyAES-256 key derived from the PIN with PBKDF2-SHA256 (200k iterations). Lives only in the PHP session while the user is authenticated.
Privileged PIN sessionAfter the correct PIN, the privileged session expires after 15 min of inactivity and asks for the PIN again.
HIBPHave I Been Pwned. Indexes leaked passwords. We use its k-anonymity API (only the first 5 chars of SHA-1 leave the server — the password never goes out in plain).
Zero-knowledgeThe server can never decrypt the user's data at any point.
Wrapped encryptionKeyEach item has its own AES key. That key is wrapped with the vault_key before being stored in DB.

Create an account and PIN

Three sign-up paths:

  1. Email passwordless: enter your email at /auth, get a 6-digit code (valid 10 min, max 5 attempts, 3 codes/h per (email, IP)).
  2. Google Sign In: if the admin enabled it.
  3. Apple Sign In: if the admin enabled it.

After the first login you are asked to create a PIN and shown a recovery code once. Save it somewhere safe: with it you can recover the PIN without losing any encrypted data. Without it, recovering the PIN requires wiping the entire vault.

From then on, every 15 minutes of inactivity prompts the PIN again. Five failed attempts per (IP + user) in 60s temporarily locks you out — anti-brute-force.

Accounts, cards, banks, notes, documents

Each section stores encrypted items:

Common features:

Authenticator (TOTP/HOTP)

/authenticator generates 2FA codes Google Authenticator/Authy style. Two intake methods:

  1. Scan QR with the camera (jsQR, everything in-browser, the secret never leaves).
  2. Manual entering the base32 secret, issuer and optional period/digits/algorithm.

Codes rotate every 30s (TOTP) or are generated by counter (HOTP, refresh button). Click the code to copy.

Password generator

Available in two places:

Two modes:

Cryptographic randomness (crypto.getRandomValues with rejection sampling — no modular bias). The entropy meter computes real bits (not zxcvbn-style heuristics).

Vault health

/vault-health scans every password owned by the user and classifies them as:

Each scan is persisted in security_scans (last 20 per user, cron prunes the old ones). The history is visible only if the plan includes scan_history_visible.

The number of scans per month is capped by max_scans_per_month on the plan.

Emergency contacts

/account-and-security#emergency. Designate trusted people who can rescue your vault if you lose access (forgotten PIN, accident, death).

Flow:

  1. The user designates up to max_emergency_contacts contacts. Each gets an invitation email to accept.
  2. On accept, the contact gets a unique emergency code (zero-knowledge: only that person knows it, we never see it).
  3. If the contact needs to rescue access, they click the link they received and request access.
  4. A configurable waiting period starts (e.g. 7 days) during which the owner can deny the request from their panel.
  5. If not denied, after the wait ends the contact gets the encrypted recovery code, which they open with their emergency code.

If the plan allows 0 contacts, the tab shows an upsell panel. Defense in depth: the invite endpoint also rejects when max_emergency_contacts === 0.

Subscription & plan change

If the user has no active subscription or their plan was removed by the admin, the app treats them as Free automatically. /billing shows "Current plan: Free · Free" instead of an empty panel.

Email notifications

/account-and-security#pin, "Notifications" section. Three toggles:

Defense: even if you turn on a toggle, the sender checks the plan at send time — an email the plan doesn't allow is never sent.

Multi-device & sessions

Each login creates a row in user_sessions with last_active_at, IP, UA. The plan caps max_devices simultaneously.

If you try to sign in while there are already ≥ max_devices live sessions, the app shows a "Too many devices" modal with the session list (browser, OS, IP, last active). You pick which to close to make room.

There's a "Select all / Deselect all" button to ease cleanup.

FortPass · © 2026 Medel Platforms · medel.es