Skip to main content

Documentation 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.

WayFy’s API uses JSON Web Tokens (JWT) issued by Flask-JWT-Extended to authenticate requests. The flow is straightforward: register or log in to receive a signed token, then include that token as a Bearer credential in the Authorization header of every subsequent request to a protected endpoint. Tokens carry identity claims (user ID, email, admin status) directly in their payload, so the server can authorise requests without an additional database lookup for each call.

Auth Flow

1

Register a new account

Send a POST request to /api/users/register with the user’s email, password, password confirmation, and mobility preferences. On success, the API returns a 201 response containing the new user object and a ready-to-use JWT token — no separate login step is needed after registration.
2

Log in to an existing account

Send a POST request to /api/users/login with email and password. On success, the API returns a 200 response containing the token and the user object.
3

Store the token client-side

Persist the token and its expiration timestamp so you can attach it to subsequent requests. The WayFy web frontend stores these under the localStorage keys wayfy_token and wayfy_token_expiration.
4

Attach the token to protected requests

Include the token in the Authorization header as Bearer <token> alongside Content-Type: application/json for every call to a protected endpoint.
5

Re-authenticate when the token expires

Tokens expire after the duration configured by JWT_ACCESS_TOKEN_EXPIRES_HOURS (default: 1 hour). When the API returns 401 with {"msg": "Token has expired"}, prompt the user to log in again to obtain a fresh token.

Register

POST /api/users/register

Creates a new WayFy user account and returns a JWT token immediately. All five fields are required — confirmPassword must match password, and selectedMobility must contain at least one option. Request body:
{
  "email": "amara@example.com",
  "password": "S3cur3P@ssword!",
  "confirmPassword": "S3cur3P@ssword!",
  "firstname": "Amara",
  "lastname": "Osei",
  "selectedMobility": ["wheelchair"]
}
email
string
required
The user’s email address. Must be unique across all WayFy accounts.
password
string
required
The user’s chosen password. Must be at least 8 characters. Stored as a bcrypt hash — never in plain text.
confirmPassword
string
required
Must match password exactly. The server validates both fields before creating the account.
firstname
string
required
The user’s first name. Returned in the user object and used in the UI.
lastname
string
required
The user’s last name.
selectedMobility
array
required
At least one mobility preference string (e.g. ["wheelchair"]). Used to tailor accessibility results across the platform.
curl example:
curl -X POST "http://localhost:3001/api/users/register" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "amara@example.com",
    "password": "S3cur3P@ssword!",
    "confirmPassword": "S3cur3P@ssword!",
    "firstname": "Amara",
    "lastname": "Osei",
    "selectedMobility": ["wheelchair"]
  }'
Response 201 Created:
{
  "msg": "Usuario registrado correctamente",
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expiresIn": 3600,
  "user": {
    "id": 42,
    "email": "amara@example.com",
    "firstname": "Amara",
    "lastname": "Osei",
    "is_admin": false,
    "is_active": true,
    "avatar": "/api/users/avatar/default_avatar.png",
    "selected_mobility": ["wheelchair"]
  }
}

Login

POST /api/users/login

Authenticates an existing user and returns a JWT token. Returns 401 Unauthorized if the email is not found or the password does not match. Returns 403 Forbidden if the account is inactive. Request body:
{
  "email": "amara@example.com",
  "password": "S3cur3P@ssword!"
}
email
string
required
The registered email address for the account.
password
string
required
The account password.
curl example:
curl -X POST "http://localhost:3001/api/users/login" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "amara@example.com",
    "password": "S3cur3P@ssword!"
  }'
Response 200 OK:
{
  "msg": "Autenticado correctamente",
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expiresIn": 3600,
  "user": {
    "id": 42,
    "email": "amara@example.com",
    "firstname": "Amara",
    "lastname": "Osei",
    "is_admin": false,
    "is_active": true,
    "avatar": "/api/users/avatar/default_avatar.png",
    "selected_mobility": ["wheelchair"]
  }
}
Response 401 Unauthorized:
{
  "msg": "Credenciales incorrectas"
}

Using the Token

Once you have a token, include it in every request to a protected endpoint using the Authorization header:
curl -X GET "http://localhost:3001/api/trips/" \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -H "Content-Type: application/json"

JavaScript / Fetch Example

The WayFy frontend constructs auth headers using a getAuthHeader helper and processes responses with a handleResponse utility. Here is the canonical pattern used throughout the codebase:
// Build the auth header object from a stored token
function getAuthHeader(token) {
  return {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  };
}

// Fetch the current user's trips
async function fetchTrips(token) {
  const response = await fetch('http://localhost:3001/api/trips/', {
    method: 'GET',
    headers: getAuthHeader(token)
  });

  if (!response.ok) {
    const body = await response.json();
    throw new Error(body.msg || body.message || 'Request failed');
  }

  return response.json();
}

// Usage inside an auth-aware component
const { token } = useAuth(); // from WayFy's AuthContext
const trips = await fetchTrips(token);
The WayFy AuthContext exposes user, token, loading, login(), logout(), setSession(), and updateUserContext(). Use the context’s login() method rather than calling /api/users/login directly — it handles token storage and session setup for you.

JWT Payload Structure

Every WayFy JWT is created with create_access_token(identity=str(user.id), additional_claims={...}). The standard sub claim holds the user’s ID as a string. Use get_jwt_identity() on the backend to retrieve the user ID, and get_jwt() to read the additional claims:
sub
string
The authenticated user’s unique ID as a string (e.g. "42"). This is the standard JWT subject claim. Returned by get_jwt_identity() on the backend.
email
string
The authenticated user’s email address.
firstname
string
The authenticated user’s first name.
lastname
string
The authenticated user’s last name.
avatar
string
The avatar path embedded in the token (e.g. /api/users/avatar/default_avatar.png).
is_active
boolean
Whether the user account is active.
is_admin
boolean
Whether the user holds admin privileges. Defaults to false for all standard accounts. Read via get_jwt() on the backend: claims.get('is_admin', False).

Token Expiry

Tokens expire after the number of hours specified by the JWT_ACCESS_TOKEN_EXPIRES_HOURS environment variable on the backend (default: 1 hour). The expiresIn field in the login and register responses contains the token lifetime in seconds. After expiry, any request using the old token will receive:
{
  "msg": "Token has expired"
}
# backend .env — extend lifetime for development if needed
JWT_ACCESS_TOKEN_EXPIRES_HOURS=8
WayFy does not implement a refresh token mechanism. Once a token expires, the user must log in again via POST /api/users/login to obtain a new one. Clients should watch for 401 responses and redirect to the login screen accordingly. Avoid extending token lifetime in production as a substitute for a proper refresh flow.

Optional Authentication

Some WayFy endpoints use @jwt_required(optional=True). These endpoints function without a token but may return reduced or public-only data. If you include a valid token, the endpoint will personalise its response (e.g., a private trip is only accessible to its owner). To call an optionally-authenticated endpoint anonymously, simply omit the Authorization header entirely:
# Anonymous request — returns public data only
curl -X GET "http://localhost:3001/api/trips/15"

# Authenticated request — owner can also see private trips
curl -X GET "http://localhost:3001/api/trips/15" \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

Admin Access

Certain privileged endpoints check the is_admin claim embedded in the token. On the backend, admin status is verified like this:
from flask_jwt_extended import get_jwt

claims = get_jwt()
if not claims.get('is_admin', False):
    raise APIException("Admin access required.", status_code=403)
Admin accounts are provisioned directly in the database — there is no self-service admin registration endpoint. If you attempt to call an admin-only endpoint with a standard user token, you will receive 403 Forbidden.
The avatar serve endpoint (GET /api/users/avatar/<filename>) requires authentication. Trip cover images (GET /api/trips/cover/<filename>) and accessibility photos (GET /api/accessibility/photos/<filename>) are publicly accessible without a token.

Build docs developers (and LLMs) love