Skip to main content

Two-Factor Authentication

A password by itself is single-factor authentication: something you know. The "What is Authentication" page explained why one factor is fragile — passwords leak, get phished, get reused. Two-factor authentication (2FA) closes most of that gap by requiring a second piece of evidence.

In Dashify, the second factor is a six-digit code from an authenticator app on your phone.

What an authenticator app is

You have probably used one. Google Authenticator, Authy, 1Password, Microsoft Authenticator, the built-in iOS Passwords app — they all do the same thing. Open the app and you see a list of accounts, each with a six-digit code that changes every thirty seconds.

To enable 2FA on Dashify, you scan a QR code with the app. The QR code contains a shared secret — a long random string that both Dashify and your authenticator app now know. From that point on, both sides can compute the same six-digit code at any moment in time.

When you log in, you type the current code from your app. The platform computes what the code should be right now, and compares.

How the codes are computed (TOTP)

The algorithm is called TOTP — Time-Based One-Time Password. It is an open standard (RFC 6238) and is what makes the same QR code work across every authenticator app.

TOTP takes three inputs:

  • The shared secret.
  • The current time, divided into 30-second windows.
  • A hash function (SHA-1 by tradition, though SHA-256 is supported).

It mixes them, takes the last 31 bits, and renders them as a six-digit decimal. The same secret + the same time window always produces the same code on both sides — no network connection between the app and the platform is needed at all.

Setting up 2FA

Two parts of that flow deserve calling out.

The secret is stored encrypted. Even if Dashify's database is breached, the attacker cannot trivially reconstruct working TOTP codes — the secret is encrypted at rest with a key that lives outside the database.

Recovery codes are issued and shown once. When you set up 2FA, the platform generates ten one-time recovery codes and shows them to you. If you lose your phone, you can use a recovery code to log in. Each code works once. Dashify stores only their hashes, never the codes themselves.

Logging in with 2FA

Refer back to the login flow page for the full picture. The 2FA piece is steps 8–9:

  1. Password verifies.
  2. The API notices 2FA is enabled.
  3. Instead of creating a session, the API responds with { needs2FA: true } and a temporary one-time challenge id.
  4. The browser shows a code-entry form.
  5. The user types the code. The browser POSTs it.
  6. The API uses otplib to compute the expected code for the current 30-second window. If the submitted code matches, the session is created.

A small subtlety: TOTP allows for a small clock-skew window — typically the previous and next 30-second windows are also accepted. Dashify uses a one-window tolerance (current ±1) which is the conventional balance between usability and security.

Disabling 2FA

A user can disable 2FA from their security page. Disabling requires the current password (re-authenticating "something you know") and a current valid TOTP code (proving "something you have"). Both factors are demanded, even though we are about to disable them, so that an attacker who has only one factor cannot turn off the other.

When 2FA is disabled, the secret is wiped from the user document and an audit log entry is written.

Recovery codes — the safety net

When you enable 2FA, the platform shows you ten recovery codes. You are expected to save them somewhere safe (a password manager, a printed sheet, a sealed envelope in a drawer). If you ever lose your phone, you use one recovery code in place of the TOTP code at login.

Each recovery code works exactly once. Used codes are crossed off the list. When you have used most of them, the platform offers to regenerate a fresh batch.

If you lose both your phone and your recovery codes, account recovery requires going through the org admin (for end-users) or the SuperAdmin (for org admins). There is no self-serve recovery from a complete loss because that would defeat the whole point.

Why six digits and thirty seconds?

The code is six digits because that is the shortest length where guessing the right code by chance is essentially impossible — one in a million. With rate limiting capping login attempts, brute-forcing TOTP is not realistic.

The window is thirty seconds because shorter windows would be inconvenient (the user might still be typing when the code rolls over) and longer windows would give an attacker too much time if a code somehow leaks. Thirty seconds is the convention everyone settled on, including Google, Microsoft, and every standard authenticator app.

Where this differs from passkeys

The next page covers WebAuthn passkeys, which are an even stronger second factor (or a complete replacement for the password). 2FA via TOTP is a great improvement over a password alone, but passkeys are better — they are phishing-resistant, hardware-backed, and require no app on your phone at all.

Dashify supports both. Users can enable 2FA, or passkeys, or both. The platform is opinionated that some form of additional factor is the right move for any account that matters.

Key takeaways

  • 2FA in Dashify uses TOTP — six-digit codes from an authenticator app, refreshed every 30 seconds.
  • The secret is established by scanning a QR code at setup time.
  • Both sides compute the code locally; the platform never asks the phone for it.
  • Recovery codes are the safety net for a lost phone — saved once at setup, each code works once.
  • Disabling 2FA requires both factors to be presented again.
  • TOTP is good. Passkeys (next page) are better.