Login Workflow
This document describes the current login workflow implemented by the frontend in src/pages/login.tsx.
Overview
The login page supports multiple sign-in paths:
- SMS one-time code login (default tab)
- Password login (email + password)
- Email one-time code login
- Passkey (WebAuthn) login
- Third-party sign-in entry points (WeChat/GitHub)
- Register / Activate / Forgot password / Reset password flows
Core backend session model:
- Server sets session cookie
cjj365 - Frontend refreshes auth state via
GET /auth/status
1) Password Login
Frontend call:
POST /auth/general- body:
{
"action": "login",
"email": "user@example.com",
"password": "...",
"next": "/target(optional)"
}
Behavior:
- Backend validates credentials and sets cookie.
- Frontend forces
checkAuthStatus({ force: true }). - Frontend redirects to
next(or dashboard default).
2) SMS Login (Default)
SMS login is a two-step flow with human challenge.
Step A: Request code
- Get challenge:
GET /auth/human-challenge
- Solve challenge client-side (PoW SHA-256).
- Request SMS code:
POST /auth/general
{
"action": "sms-login",
"phone_number": "+8613800138000",
"next": "/target(optional)",
"human_challenge_salt": "...",
"human_challenge_sig": "...",
"human_challenge_nonce": "...",
"human_challenge_expires_at": 1710000000
}
Step B: Verify code
POST /auth/general
{
"action": "sms-login",
"phone_number": "+8613800138000",
"verify_code": "123456",
"next": "/target(optional)"
}
Behavior after verify success:
- If the phone number already belongs to an existing account:
- Backend sets cookie.
- Frontend refreshes
/auth/status. - Continue normal redirect.
- If the phone number does not belong to any existing account:
- Backend does not create a user yet.
- Backend returns
status=PhoneResolutionRequiredwith a short-livedbind_session_id. - Frontend shows an explicit choice:
- bind an existing email account
- create a new account
- Only after one of those explicit follow-up actions succeeds does the backend create/update the user relation and set the login cookie.
3) Email One-Time Code Login
Two-step flow:
- Request code:
POST /auth/generalwithaction: "email-login"and email
- Verify code:
POST /auth/generalwithaction: "email-login", email,verify_code
On success, backend sets cookie and frontend refreshes /auth/status.
4) Register / Activate
Register
POST /auth/general
{
"action": "register",
"email": "user@example.com",
"password": "StrongPassword123",
"name": "username",
"country_of_residence": "CN"
}
Notes:
- Username availability is checked via
GET /auth/general?name=.... - Password policy is validated in frontend and backend.
Activate
POST /auth/general
{
"action": "activate-user",
"email": "user@example.com",
"verify_code": "123456"
}
Behavior:
- If backend auto-signs-in after activation, frontend will detect it via
/auth/statusand redirect. - Otherwise frontend falls back to login view.
5) Forgot / Reset Password
Request reset code
POST /auth/general
{
"action": "request-reset-password",
"email": "user@example.com"
}
Reset password
POST /auth/general
{
"action": "reset-password",
"email": "user@example.com",
"verify_code": "123456",
"new_password": "NewStrongPassword123"
}
After success, frontend returns to login mode and shows reset success message.
6) Passkey (WebAuthn) Login
Flow:
- Fetch options:
POST /auth/webauthn/login/options
- Browser
navigator.credentials.get(...) - Verify assertion:
POST /auth/webauthn/login/verify
- Backend sets cookie, frontend refreshes
/auth/status, then redirects.
7) Third-Party Sign-In Entry
Current frontend uses full-page redirect entry points:
GET /auth/weixin(+ callback)GET /auth/github(+ callback)
The callback page finalizes sign-in and returns control to app routes.
8) Redirect Rules
Source of target route:
nextquery param from login page URL- server-provided absolute redirect (
data.to) when present - fallback dashboard route
For SMS onboarding special cases, frontend may override and redirect to profile completion page first.
9) Session Checkpoints
Important checkpoints used by frontend:
GET /auth/status: authoritative session stateGET /auth/profile: user profile dataPOST /auth/logout: clear current session
10) Source of Truth in Code
If this document drifts, validate against:
src/pages/login.tsxsrc/components/AuthForm/index.tsxsrc/utils/api.tssrc/types/auth.ts