| Method | Endpoint | Description |
|---|---|---|
| POST | /auth/signup/email |
Register a new user with email+password |
| POST | /auth/login/email |
Login with email+password |
| POST | /auth/login/google |
Login / signup via Google OAuth token |
| POST | /auth/refresh |
Refresh JWT when access token expires |
| POST | /auth/password/reset/request |
Send password-reset email link |
| POST | /auth/password/reset/confirm |
Set new password via reset token |
| POST | /auth/token/verify |
Verify access token and auto-login |
Refer to the Micro-Level API Specification for more details on password reset endpoints.
-
Sign-Up
-
Request:
POST /auth/signup/email { "email": "...", "password": "...", "name": "..." }
-
Server:
- Hash the password (e.g. using bcrypt).
- Create a new User document in MongoDB (see
userscollection schema) withhashed_password, email, name, etc. - (Optionally) create & store a refresh token record in a
refresh_tokenscollection, tied to the user and device/browser. - Generate a short-lived Access Token (JWT, e.g. 15 min) and a longer-lived Refresh Token (e.g. 30 days).
-
Response:
200 OK { "access_token": "...jwt...", "refresh_token": "...opaque-or-jwt...", "user": { "id": "...", "email": "...", "name": "..." } }
-
-
Sign-In
-
Request:
POST /auth/login/email { "email": "...", "password": "..." }
-
Server:
- Look up the user by email.
- Compare submitted password with the stored hash.
- If OK, issue new Access + Refresh tokens (and store/rotate the refresh token in DB).
-
Response: same shape as Sign-Up.
-
-
Access Token (JWT)
-
Lifespan: short (e.g. 15 min)
-
Usage: attached to every protected request as
Authorization: Bearer <access_token> -
Storage (Client): in memory (e.g. React state / Redux store).
- Why not localStorage? To reduce XSS risk.
-
-
Refresh Token
-
Lifespan: long (e.g. 30 days)
-
Usage: call
POST /auth/refresh { "refresh_token": "..." }to get a new Access Token.
-
Storage (Client): in a secure persistent store:
-
Web:
httpOnly,Securecookie (preferred), or if you must use localStorage, encrypt it. -
React Native / Expo: use
SecureStore(orAsyncStoragewith encryption).
-
-
Server-Side Tracking
-
Keep a collection
refresh_tokenswith fields{ token, user_id, device_info, created_at, expires_at, revoked: bool }
-
On every
refreshcall, you can rotate the token (issue a brand-new refresh token and mark the old one revoked). That way, you can:- Immediately revoke sessions (e.g. on password change).
- Detect token reuse attacks.
-
-
In Your Expo App UI
-
Use
expo-auth-sessionorfirebase/authto do Google OAuth and get back a Firebase ID Token (JWT) on the client. -
Example (pseudo):
const result = await Google.logInAsync({ … }); const idToken = result.idToken;
-
-
Backend Endpoint
-
Request:
POST /auth/login/google { "id_token": "<firebase-id-token>" }
-
Server (FastAPI):
- Verify
id_tokenwith the Firebase Admin SDK (or by calling Google’s tokeninfo endpoint). - Extract
uid, email, name, picture. - Look up or auto-provision a User in your MongoDB (
userscollection). - Issue your own Access + Refresh tokens (just like email/password flow), and store the Refresh token record.
- Verify
-
Response:
{ "access_token": "...", "refresh_token": "...", "user": { "id": "...", "email": "...", "name": "...", "avatar": "..." } }
-
-
Client Side
- Receive your own tokens in the response.
- Store them exactly the same way as in the email/password flow (Access in memory, Refresh in SecureStore/cookie).
- All subsequent API calls (to
/groups,/expenses, etc.) use your own Access token.
This endpoint allows the client application to verify an existing access token, typically on application startup, to automatically log the user in without requiring credentials.
- Request:
POST /auth/token/verify { "access_token": "..." }
- Server:
- Validate the provided
access_token(check signature, expiry, etc.). - If the token is valid, retrieve the associated user details.
- If the token is invalid or expired, return an appropriate error (e.g., 401 Unauthorized).
- Validate the provided
- Response (Success):
200 OK { "user": { "id": "...", "email": "...", "name": "..." } }
- Response (Failure):
401 Unauthorized { "error": "Invalid or expired token" }
This endpoint helps in providing a seamless login experience if a valid session token is already present on the client. If this verification fails, the client should then attempt to use the refresh token via the /auth/refresh endpoint or prompt the user for a full login.
-
On App Launch
- Check SecureStore (or cookies) for a stored Refresh Token.
- If found, call
/auth/refreshto get a fresh Access token (and possibly a rotated Refresh token). - If no valid tokens, show the Login/Sign-Up screen.
-
On Login / Sign-Up
- Save the returned Access token in React state.
- Save the Refresh token in SecureStore or an HttpOnly cookie.
- Redirect into your logged-in UI.
-
On API Calls
- Automatically inject the
Authorization: Bearer <access_token>header via an Axios or Fetch interceptor. - If you get a 401 (Access token expired), automatically call
/auth/refreshonce and retry the original request.
- Automatically inject the
-
On Logout
- Call
/auth/logout(if you implement a logout endpoint that revokes the refresh token). - Clear tokens from SecureStore and in-memory state.
- Redirect back to the Login screen.
- Call
- Token Rotation & Auto-Refresh means users rarely see login screens once they’ve signed in.
- SecureStore / HttpOnly Cookies keep tokens safe from attackers.
- Centralized Refresh-Token Store on the server lets you revoke stolen tokens instantly (e.g. via an “Active Sessions” screen).
- Single Codepath for both Email/Password and Google Sign-In after the initial identity check (you end up issuing your own tokens in both cases, interacting with the User Service for profile data).