Frontend Authentication
JWT auth flow, token refresh, and registration in the SPA.
Auth context
src/contexts/AuthContext.js provides user, login, logout, fetchUser, refreshToken, and loading. Most pages gate content on this context.
Login flow
AuthContext.login(orAdminLogin) callsPOST /api/loginwith{username, password}.- The backend looks up the user by email OR username OR phone, verifies the bcrypt hash, and returns
{access_token, refresh_token}. - Both tokens are stored in
localStorage. GET /api/profileis called to hydrate the user state.- Admin login additionally checks
profile.role === "admin"; if not admin, tokens are cleared and login rejected.
Token refresh (axios interceptor)
src/api/axios.js has a response interceptor that handles expired access tokens transparently:
The interceptor also sets cache-busting headers (no-cache, Pragma, Expires) globally.
Registration (3-step)
State is persisted in sessionStorage across the steps so a refresh doesn't lose progress.
| Step | Route | Collected |
|---|---|---|
| 1 | /register | username, email, password |
| 2 | /register/details | NIK (16 digits), full name, alias (forum pseudonym), WhatsApp |
| 3 | /preferences | info preferences (medical, mental health, 6 religions, "other belief") |
Step 3 submits everything via POST /api/register, which encrypts the NIK with AES-GCM before storing.
Password reset
/forgot-password→GET /api/send-verification-code?phone=→ backend stores a UUID reset token and WhatsApps a link{FRONTEND_URL}/reset-password?code=<token>./reset-password?code=...→POST /api/update-passwordwith{code, new_password}→ validates, hashes, clears token.
Logout
POST /api/logout clears the stored refresh token on the backend, then the frontend clears localStorage and redirects.
Committed secret
VAPID_PRIVATE_KEY is committed in .env of the frontend repo. It should not be in the frontend — move it to the backend environment.