rustdesk / rustdesk/rustdesk-server-pro

[BUG] 2FA TOTP setup fails with "Can't verify the code" - verify endpoint returns {"success":false} despite correct code

Open
#948 9 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
Shell
Stars
317
Forks
119
PR merge metrics
No merged PRs in 30d

Description

Bug Description

Environment

  • RustDesk Server Pro version: 3.46.0 (image tag latest, digest d9af4e3774a4)
  • Deployment: Docker Compose (non-host networking, behind Traefik reverse proxy)
  • Database: SQLite (migrations all completed successfully, verified via _sqlx_migrations)
  • Host OS: (debian 13)
  • Browser: Firefox (tested), Brave (tested)

Bug Description

After updating from an earlier version to 1.8.2 / 3.46.0, no user on this instance can successfully enable 2FA (TOTP) anymore.

  • Pre-update 2FA setups (users created and verified before the update) are unaffected in the database.
  • ALL new 2FA setup attempts fail with the UI error: "Can't verify the code. Check that code and local time settings are correct!"
  • Tested with newly created users (same problem), so the issue is not tied to a specific user record.

Critically: I run an identical second instance (same image digest, same compose structure, same schema, same migrations) where 2FA setup works perfectly — also for newly created users.

How to Reproduce
  1. Log in as admin (no 2FA active)
  2. Go to Account Settings → Enable 2FA
  3. Scan QR code with an authenticator app (tested with Aegis, Google Authenticator, IT-Tools TOTP generator — all produce identical codes)
  4. Enter the generated 6-digit code
  5. Server rejects: POST /api/user/tfa/totp/verify{"success":false}
Expected Behavior
  • 2FA is accepted
Operating system(s) on local (controlling) side and remote (controlled) side

debian 13

RustDesk Version(s) on local (controlling) side and remote (controlled) side

1.8.1 -> 1.8.2

Screenshots
Image
Additional Context

What I've Verified

  • Host time perfectly in sync via chronyd (timedatectl clean)
  • Container time matches host time exactly (date --utc identical in both)
  • TOTP secret shown in QR is identical to the otpauth:// URI returned by /enable
  • Multiple TOTP apps generate identical codes → code is mathematically correct
  • _sqlx_migrations shows all 21 migrations completed successfully, identical to working instance
  • Schema of user table identical to working instance (including tfa blob null column)
  • Image digest identical to working instance (d9af4e3774a4)
  • Accessing the web console directly on port 21114 (bypassing Traefik reverse proxy entirely) produces the same failure → not a proxy/header issue
  • Tested in fresh incognito session, multiple browsers, cleared all cookies
  • Ran reset_2fa_verification via rustdesk-utils between attempts

Debug Log Observations (RUST_LOG=debug)

With debug logging enabled, during the setup flow I see:
POST /api/user/tfa/totp/enable → 200, latency=0ms, response 268 bytes
POST /api/user/tfa/totp/verify → 200, latency=0ms, response 125 bytes, body {"success":false}

Notable: Between enable and verify, there are no SQL queries logged at all. No UPDATE user SET tfa=..., no read from a pending-setup table. The setup state appears to be held in-memory only. The user_data table is empty. The user.tfa field remains NULL after failed verify attempts.

Database State

SELECT name, tfa FROM user WHERE name='admin';
→ admin | (empty/NULL)

Pre-update user from the same database:
SELECT name, hex(tfa) FROM user WHERE name='olli';
→ valid tfa blob with verified:1 JSON payload (setup done before 1.8.2 update)

What I think:

The in-memory pending-TOTP-setup state appears to not be retained or not be retrievable between the /enable and /verify request on this instance. Possibly related to session handling, JWT secret, or a state-loss during a specific upgrade path. The working instance was upgraded from an older version with a backup_db.sqlite3 artifact present — the failing instance has no such backup file, suggesting a slightly different upgrade history.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing the /api/user/tfa/totp/enable and /api/user/tfa/totp/verify entry points, using the debug logs and the failing and working instances for comparison. Determine why pending setup state is unavailable between requests, then verify that a correct TOTP code succeeds and persists the expected user.tfa value without regressing existing 2FA.

Written by the indexing model from the issue text.

Assessment

Tech stack
docker-compose, sqlite
Domain
api, authentication, backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.