Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/sdurutr436/stay-sidekick/llms.txt

Use this file to discover all available pages before exploring further.

The Stay Sidekick API authenticates requests using JWT HS256 tokens. To call any protected endpoint, you first fetch a CSRF token, then log in to receive a JWT, and include that JWT as an Authorization: Bearer header on all subsequent requests. State-changing operations (POST, PUT, PATCH, DELETE) additionally require the CSRF token in an X-CSRF-Token header.

Step 1: Get a CSRF Token

Before any state-changing request (including login), fetch a CSRF token. The response sets a csrf_token cookie and returns the token value in the JSON body.
curl -c cookies.txt http://localhost/api/csrf-token
{
  "ok": true,
  "csrf_token": "a7f3b2e1d4c9..."
}
The CSRF token is tied to the cookie. Use -c cookies.txt to save cookies and -b cookies.txt to send them on subsequent requests.

Step 2: Log In

Call POST /api/auth/login with the CSRF token header and cookie. On success, the response contains a signed JWT token. Endpoint: POST /api/auth/login
Rate limit: 10 requests/hour per IP
Auth required: No
curl -b cookies.txt \
  -H "X-CSRF-Token: a7f3b2e1d4c9..." \
  -H "Content-Type: application/json" \
  -d '{"email":"dev@staysidekick.es","password":"admin123"}' \
  http://localhost/api/auth/login
Request body:
email
string
required
The user’s email address.
password
string
required
The user’s password.
Success response (200):
{
  "ok": true,
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "debe_cambiar_password": false
}
ok
boolean
Always true on success.
token
string
Signed JWT HS256 token. Include this as Authorization: Bearer <token> on all protected requests.
debe_cambiar_password
boolean
If true, the user must change their password before using the platform. Redirect them to the password change flow.
Error responses:
StatusMeaning
400Body is not valid JSON
401Invalid credentials (message is intentionally generic — does not reveal whether email exists)
403CSRF token missing or invalid
422Validation error in login payload
429Rate limit exceeded (10/hour per IP)

Step 3: Use the Token

Pass the JWT as an Authorization: Bearer header on all protected endpoints:
curl -H "Authorization: Bearer $TOKEN" \
  http://localhost/api/apartamentos
For state-changing requests, also include the CSRF cookie and header:
curl -b cookies.txt \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-CSRF-Token: $CSRF_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"nombre":"Apartamento Sol","id_externo":"APT-001"}' \
  http://localhost/api/apartamentos

Token Details

PropertyValue
AlgorithmHS256
TTLConfigurable via JWT_ACCESS_TOKEN_HOURS (default: 1 hour)
Signing keyJWT_SECRET_KEY environment variable
JWT claims included:
ClaimDescription
subSubject — the authenticated user’s email or identifier (standard JWT claim)
iatIssued-at timestamp
expExpiry timestamp — token is rejected after this time
user_idUUID of the authenticated user
empresa_idUUID of the user’s company (used for multi-tenant data scoping)
rolUser role: operativo or admin
es_superadminBoolean — superadmin can manage all companies

CSRF Protection Details

Stay Sidekick uses the double-submit cookie pattern:
1

Fetch the CSRF token

Call GET /api/csrf-token. The server generates a 256-bit random token, sets it as a csrf_token cookie (HttpOnly=False, SameSite=Strict), and returns it in the JSON body. The cookie is intentionally readable by JavaScript so the frontend can copy it into the X-CSRF-Token header.
2

Include both cookie and header

On every POST, PUT, PATCH, or DELETE request, send the csrf_token cookie (automatically via -b cookies.txt) and include the same value in the X-CSRF-Token header.
3

Server validates

The @csrf_protect decorator reads both values and compares them with secrets.compare_digest. A mismatch returns 403 Forbidden.
The login endpoint (POST /api/auth/login) itself requires CSRF protection. Always fetch a CSRF token before attempting to log in.

Internal Token Validation Endpoint

GET /api/auth/validacion is used internally by Nginx’s auth_request module to validate tokens before proxying requests to the Angular SPA. It returns 200 for valid tokens and 401 otherwise.
Do not call GET /api/auth/validacion directly from client applications. It is an internal Nginx subrequest endpoint and is not designed for external use.

Complete Authentication Flow Example

# 1. Get CSRF token (saves cookie to cookies.txt)
CSRF_TOKEN=$(curl -s -c cookies.txt http://localhost/api/csrf-token | python3 -c "import sys,json; print(json.load(sys.stdin)['csrf_token'])")

# 2. Log in and capture JWT
TOKEN=$(curl -s -b cookies.txt \
  -H "X-CSRF-Token: $CSRF_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"email":"dev@staysidekick.es","password":"admin123"}' \
  http://localhost/api/auth/login | python3 -c "import sys,json; print(json.load(sys.stdin)['token'])")

# 3. Use the token
curl -H "Authorization: Bearer $TOKEN" http://localhost/api/perfil

Build docs developers (and LLMs) love