Skip to content

Password Reset

Overview

A user who has forgotten their password cannot reset it themselves (no self-service flow yet). An admin must reset it via the CLI. The reset updates all three credential stores atomically and — in production — refreshes the running server’s in-memory Anki sync state without a restart.


Production (Docker on DigitalOcean)

Terminal window
docker exec flashcard-flow-server-1 \
flashcard-flow-server reset-password <email> '<new-password>'

Expected output:

Password reset for '<username>' (<email>)
In-memory credentials refreshed — Anki Desktop sync works immediately.

The user can immediately:

  • Log in to the web UI with the new password
  • Sync from Anki Desktop with the new password (no server restart needed)

Dev / Local (bare-metal)

The server must be running with DATABASE_URL set (i.e. loaded from .env) for the no-restart path to work. If it is:

Terminal window
./target/release/flashcard-flow-server reset-password <email> '<new-password>'

If the server was started without DATABASE_URL (SQLite mode), the CLI will print:

Warning: server returned 404 Not Found — Anki Desktop sync will work after next restart.

This means the DB reset succeeded (web login works immediately) but the in-memory refresh failed due to a DB mismatch. Fix: restart the server.

Terminal window
pkill -f flashcard-flow-server
cargo run --release -p flashcard-flow-server &

How it works

The CLI subcommand does two things:

  1. DB update — recomputes and writes all three credential hashes for the user:

    • password_hash (Argon2) — used by web login
    • hkey (SHA-1 of username:password) — used by Anki Desktop sync (in-memory)
    • pbkdf2_hash (PBKDF2) — used to restore Anki sync state after a server restart
  2. In-memory refresh — calls POST /api/admin/refresh-user on the running server (authenticated with JWT_SECRET). The server reads the new hashes from the DB and pushes them into the sync server’s in-memory table, evicting the stale entry. This means Anki Desktop sync works immediately with the new password.

If the server is unreachable or returns an error, the CLI prints a warning and the DB update still stands — web login works immediately, Anki Desktop sync works after the next server restart.


Security notes

  • The admin endpoint (POST /api/admin/refresh-user) is authenticated with JWT_SECRET as a bearer token. Anyone with JWT_SECRET can call it, so keep that secret secure.
  • The new password is passed as a CLI argument, which is visible in shell history. After use, consider clearing history (history -d <n>) or advising the user to change their password immediately after receiving it.
  • There is no rate limiting on admin-initiated resets — only human access controls.

Future: self-service reset

When self-service “forgot password” is implemented, it will send a time-limited reset link via Resend. The same change_password / in-memory refresh logic will be reused under the hood.