WayFy uses JSON Web Tokens (JWT) for stateless authentication across its Flask backend and React frontend. When a user logs in, the backend signs a token containing the user’s identity and role, which the client stores inDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/jhonyes04/new-wayfy/llms.txt
Use this file to discover all available pages before exploring further.
localStorage and includes as a Bearer header on every subsequent request. The frontend’s AuthContext manages the token lifecycle — validating it on mount, exposing it to components, and clearing it on logout. Backend routes are guarded with Flask-JWT-Extended’s @jwt_required() decorator, and admin-only endpoints additionally verify the is_admin claim embedded in the token.
Auth Flow Overview
Register a new account
Send a A successful response returns a
POST request to /api/users/register with the user’s name, email, and password. No authentication is required for this endpoint.201 status with the created user object. The email must be unique — submitting a duplicate email returns a 409 conflict.Log in and receive a token
Send a A successful response includes the signed JWT access token:
POST request to /api/users/login with the user’s email and password. No authentication header is required.Store the token on the client
The frontend stores the token and its expiration timestamp in These keys are read back on every page load to rehydrate the session without requiring a new login. The
localStorage under fixed keys:AuthContext sets loading: true while this validation runs, preventing protected routes from flashing before the check completes.Include the token in API requests
All authenticated requests must include the token in an
Authorization: Bearer header. Use the getAuthHeader(token) helper from apiUtils.js, which also sets Content-Type: application/json:handleResponse checks response.ok and throws an Error with the server’s body.msg if the request failed, so you can catch meaningful error messages in your UI.Token expiry and logout
Tokens expire after the number of hours set in
JWT_ACCESS_TOKEN_EXPIRES_HOURS (default: 1 hour). When the token expires, the backend returns a 401 Unauthorized response. The frontend’s logout() function clears both localStorage keys and resets the AuthContext state, redirecting the user to /login.JWT Payload Structure
Every token issued by WayFy contains the following claims in its payload. The identity (sub) is stored as a string — the backend issues it via identity=str(user.id) — so get_jwt_identity() always returns a string and must be cast with int() when a numeric comparison is needed.
| Claim | Type | Description |
|---|---|---|
sub | string | The user’s database id as a string. Returned by get_jwt_identity() on the backend. Cast to int when needed: int(get_jwt_identity()). |
email | string | The user’s email address at the time the token was issued. |
is_admin | boolean | Whether the user has admin privileges. Used to gate admin-only endpoints and UI. |
exp | integer | Unix timestamp when the token expires. Controlled by JWT_ACCESS_TOKEN_EXPIRES_HOURS. |
iat | integer | Unix timestamp when the token was issued. |
The full claims dictionary — including
email and is_admin — is accessible on the backend via get_jwt(). The identity alone (user id as a string) is accessible via the lighter get_jwt_identity() call. Use the latter when you only need to look up the user record, and cast to int before integer comparisons or DB lookups.Backend: Protecting Routes
Requiring Authentication
Decorate any Flask route with@jwt_required() to reject unauthenticated requests with a 401 response:
Admin-Only Endpoints
Read theis_admin claim from the full JWT dictionary to gate admin operations:
Direct Bearer Token Requests
For testing or server-to-server calls, pass the token directly in theAuthorization header:
Frontend: AuthContext API
TheAuthContext provider wraps the entire application and exposes the following values and methods to any component via useContext(AuthContext):
- State Values
- Methods
| Property | Type | Description |
|---|---|---|
user | object | null | The decoded user object (id, email, is_admin, etc.) or null when not logged in. |
token | string | null | The raw JWT string, ready to pass to getAuthHeader(). |
loading | boolean | true while the context is validating a token from localStorage on mount. Render null or a loading spinner while this is true to avoid route flicker. |
Usage Example
Protected and Admin Routes
WayFy uses two route-guard components to restrict access at the React Router level.ProtectedRoute
Checks
!!user from AuthContext. If the user is not authenticated, it redirects to /login. Wrap any route that requires a logged-in user.AdminRoute
Checks
user.is_admin. If the flag is false or the user is not logged in, it redirects to /login. Wrap routes that are only accessible to administrators.Rate Limiting
WayFy uses Flask-Limiter to protect API endpoints against abuse. Rate limits are applied to the AI assistant routes (e.g. 20–30 requests per minute) and utility routes (60 requests per minute). The/api/users/login and /api/users/register endpoints do not currently have per-route rate limits applied.
Handling 429 responses in the frontend
Handling 429 responses in the frontend
When
handleResponse receives a 429 status, it throws an Error with the server’s msg. Catch it in your login form and display a user-friendly message: