appwrite / appwrite/sdk-for-cli
appwrite login --mfa/--code never creates the MFA challenge (self-hosted TOTP)
- Dominant language
- Go
- Stars
- 100
- Forks
- 45
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 5
Description
### 👟 Reproduction steps
Self-hosted Appwrite 1.9.6, CLI 27.3.0 (Homebrew, darwin/arm64). Console account has TOTP enabled as its **only** MFA factor (`GET /v1/account/mfa/factors` → `{"totp":true,"phone":false,"email":false,"recoveryCode":false}`).
```console
$ appwrite login --endpoint "https://appwrite.example.com/v1" \
--email me@example.com --password '' --mfa totp --code 130705
✗ Error: More factors are required to complete the sign in process.
```
Same result with a fresh code every time, and with `--code` alone or `--mfa` alone.
### 👍 Expected behavior
After `POST /v1/account/sessions/email` returns `user_more_factors_required`, the CLI should create an MFA challenge for the factor given in `--mfa` (`POST /v1/account/mfa/challenge`) and verify it with `--code` (`PUT /v1/account/mfa/challenge`), then store the elevated session.
### 👎 Actual Behavior
The CLI never creates the challenge. `--verbose` shows the request sequence stops right after the email session call:
```
· GET /v1/health/version 200
· GET /v1/account 200
· POST /v1/account/sessions/email 401
```
No `POST /v1/account/mfa/challenge` is ever issued, so `--mfa` / `--code` are effectively ignored and the error from step 1 is surfaced as-is.
Worse, the partial (unelevated) session cookie appears to be written to `~/.appwrite/prefs.json` anyway. Subsequent commands then fail confusingly:
```console
$ appwrite pull all
✗ Error: you are not authenticated. Run `appwrite login` to authenticate and try again
```
Doing the three calls by hand against the same server works fine and produces a usable session:
```bash
curl -c c.txt -X POST "$EP/account/sessions/email" -H "X-Appwrite-Project: console" \
-H 'Content-Type: application/json' -d '{"email":"...","password":"..."}'
CH=$(curl -b c.txt -X POST "$EP/account/mfa/challenge" -H "X-Appwrite-Project: console" \
-H 'Content-Type: application/json' -d '{"factor":"totp"}') # → challengeId
curl -b c.txt -c c.txt -X PUT "$EP/account/mfa/challenge" -H "X-Appwrite-Project: console" \
-H 'Content-Type: application/json' -d '{"challengeId":"'"$ID"'","otp":"123456"}'
```
Writing that cookie into `~/.appwrite/prefs.json` makes the CLI work normally, which confirms the server side is fine and the gap is in the CLI's login flow.
Note: `--mfa` also has a misleading UX — `--mfa 123456` fails with `flag needs an argument` guidance that doesn't hint the value is a *factor name*, not the code.
### 🎲 Appwrite version
Different version (specify in environment)
### 💻 Operating system
MacOS
### 🧱 Your Environment
Appwrite server 1.9.6 (self-hosted, behind HTTPS). appwrite-cli 27.3.0 installed via Homebrew, macOS 15 / arm64.
### 👀 Have you spent some time to check if this issue has been raised before?
- [x] I checked and didn't find similar issue
### 🏢 Have you read the Code of Conduct?
- [x] I have read the [Code of Conduct](https://github.com/appwrite/.github/blob/main/CODE_OF_CONDUCT.md)
Contributor guide
Research direction
Start at the `appwrite login` flow and trace handling of `POST /v1/account/sessions/email` when it returns `user_more_factors_required`, then follow how the session cookie is written to `~/.appwrite/prefs.json`. Reproduce against a self-hosted Appwrite 1.9.6 instance and verify that the MFA challenge and verification requests occur, the elevated session is stored, and `--mfa` help distinguishes factor names from codes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- authentication, cli
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100