2 How to use 2FA
Alfred Syatsukwa edited this page 2026-04-16 06:50:29 +02:00

Two-Factor Authentication (2FA) in Cypht

Cypht supports TOTP-based two-factor authentication (Time-based One-Time Password), which is compatible with any standard authenticator app. When enabled, users must enter a 6-digit code from their app after their password on every login.


Table of contents


How it works

Cypht uses the TOTP protocol (RFC 6238). Each user gets a unique secret derived from the server-side APP_2FA_SECRET pepper and their username via PBKDF2. This means:

  • 2FA state is stored in the existing user settings
  • The server-side secret is never sent to the client; only a QR code encoding each user's derived secret is shown
  • Codes are valid for a 30-second window and are validated with HMAC-SHA1

Compatible apps include: Google Authenticator, Authy, Microsoft Authenticator, Bitwarden Authenticator, 1Password, and any other TOTP-compatible app.


Requirements

Requirement Details
PHP extensions gd — required by bacon/bacon-qr-code to render the QR code image
Composer packages bacon/bacon-qr-code ^3.0.0, christian-riesen/base32 ^1.3.2 (included in composer.json)
Server time Must be NTP-synchronized — TOTP codes are time-based

Administrator setup

1. Enable the module

Add 2fa to the CYPHT_MODULES list in your .env file:

CYPHT_MODULES="core,imap,smtp,...,2fa"

Note: config/app.php is version-controlled and should not be edited. All module configuration belongs in .env.

2. Set the shared secret

APP_2FA_SECRET is a server-side pepper used to derive each user's individual TOTP secret. It must be at least 10 characters and must remain constant — changing it invalidates all users' enrolled 2FA.

Option A — Automatic (recommended)

Simply leave APP_2FA_SECRET empty in .env. When you run config_gen.php, it detects that the 2fa module is enabled and automatically generates and writes a cryptographically secure 32-character secret:

APP_2FA_SECRET=""  # will be filled automatically
$ php scripts/config_gen.php
Generated APP_2FA_SECRET and saved to .env

Ref pull request

Option B — Manual

Set it yourself to any random string of at least 10 characters:

APP_2FA_SECRET="your-random-secret-here"

You can generate a strong value with:

openssl rand -base64 32 | tr -d '/+=' | head -c 32

Optional: shorter secrets

By default, user secrets are 64 characters before base32 encoding. If you want shorter secrets that are easier to type manually into an authenticator app, set:

APP_2FA_SIMPLE=true

Warning: Changing APP_2FA_SIMPLE after users have enrolled forces all of them to re-enroll using a backup code.

3. Regenerate the site

After updating .env, always run:

php scripts/config_gen.php

This compiles the module into the production site/ directory.


User guide: enabling 2FA on your account

Step 1 — Open the 2FA settings

Log in to Cypht, click the Settings icon, then open the Site tab. Scroll down to the 2 Factor Authentication section and click the section header to expand it.

Settings_site_qr

Step 2 — Scan the QR code

Open your authenticator app and scan the QR code displayed on the page. The code encodes a otpauth://totp/ URI containing your account name and derived secret.

If you cannot scan the QR code, tap Manual entry in your app and type in the long base32 code shown below the QR image (ignore line breaks).

Step 3 — Verify the code

Once your app shows a 6-digit code, enter it in the six individual digit boxes below the QR code and click Verify code.

A green confirmation appears if the code matches. The Enable 2 factor authentication checkbox is automatically checked.

qr_code_with_confirmation_code

If the code does not match, wait for the next 30-second window and try again. If it consistently fails, check that your server and device clocks are accurate.

Step 4 — Save your backup codes

After successful verification, three 9-digit backup codes are shown. These are your only recovery option if you lose access to your authenticator app.

Store them somewhere safe — a password manager, printed paper in a secure location, etc. Each code can only be used once.

Step 5 — Save settings

Click the Save settings button at the bottom of the settings form. 2FA is now active on your account.


Logging in with 2FA

After entering your username and password on the login page, a second screen appears asking for your 6-digit code.

login_with_6_digits_prompt

Open your authenticator app, find the Cypht entry, and enter the current 6-digit code. Codes refresh every 30 seconds.

Click Submit. If the code is correct, you are taken to your home page. If it is wrong, you can retry — there is no lockout, but each code is only valid for one 30-second window.


Recovering access with backup codes

If you have lost your authenticator device, enter one of your saved 9-digit backup codes on the 2FA login screen instead of a 6-digit TOTP code.

After logging in with a backup code:

  1. Go to Settings → Site → 2 Factor Authentication
  2. The used code will no longer appear in your list
  3. Scan the QR code with your new device
  4. Verify and save — a new set of 3 backup codes is generated

You have 3 backup codes. Once all are used without re-enrolling, you will be locked out. If that happens, an administrator can reset your user settings file.


Disabling 2FA

  1. Go to Settings → Site → 2 Factor Authentication
  2. Uncheck Enable 2 factor authentication
  3. Click Save settings

2FA is immediately disabled. You will not be prompted for a code on your next login.


Troubleshooting

Symptom Likely cause Fix
QR code does not appear APP_2FA_SECRET is empty Run php scripts/config_gen.php or set the secret manually in .env
Code never matches Server clock is out of sync Ensure NTP is running on the server (systemctl status ntp or chrony)
Code never matches after config change APP_2FA_SIMPLE was changed Each user must log in with a backup code and re-enroll
"Unable to generate QR code" message Composer packages missing Run composer install
Locked out with no backup codes All backup codes used without re-enrolling Administrator deletes or resets the user settings file in USER_SETTINGS_DIR

Security notes

  • APP_2FA_SECRET is a server-side pepper, not a per-user secret. Keep it confidential and out of version control. Your .env file should be in .gitignore.
  • Changing APP_2FA_SECRET invalidates all enrolled users — they will need to re-enroll using backup codes.
  • The derived per-user secret is computed with PBKDF2 (SHA-512, 256 iterations) — it is never stored; it is re-derived on each login.
  • Backup codes are single-use 9-digit integers generated with random_int().
  • TOTP validation uses a single 30-second window (no clock drift tolerance beyond the current window). Keep your server clock accurate.