Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/BladimirGS/judicial-backend/llms.txt

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

Judicial Backend does not implement its own identity store. Instead it uses the BFF (Backend-for-Frontend) pattern: the Express server acts as a proxy between the browser client and a dedicated external authentication API. Clients never communicate with that external API directly — they only talk to this backend, which forwards credentials, holds the refreshToken in a secure server-set cookie, and returns a short-lived access_token for use in subsequent API calls.

How the BFF Pattern Works

The BFF layer handles three responsibilities on behalf of the client:
  1. Credential forwardingPOST /api/auth/login receives { usuario, contrasenia }, enriches the payload with the idSistema identifier, and forwards the request to the external API’s /api/AuthJWT/Login endpoint.
  2. Cookie management — the refreshToken returned by the external API is stored in an httpOnly cookie (path: /api/auth) and never exposed to JavaScript. Rotation on refresh and clearance on logout are handled automatically.
  3. Token relay — only the access_token is returned in the JSON response body for the client to store in memory and attach to subsequent requests.
The refreshToken cookie is set with httpOnly: true, which means it is completely inaccessible to JavaScript running in the browser. This eliminates an entire class of XSS-based token theft attacks. The cookie is also scoped to path: /api/auth so it is only sent to the token-refresh and logout endpoints.

Authentication Flow

1

Client sends login credentials

The client POSTs { usuario, contrasenia } to POST /api/auth/login. The request body is validated by LoginDto using class-validator before it reaches the controller — a 400 is returned immediately if either field is missing or non-string.
2

AuthController delegates to AuthExternalAdapter

AuthController.login() calls AuthExternalAdapter.login(usuario, contrasenia). The adapter constructs a JSON body that includes idSistema (read from envs.ID_SISTEMA) and POSTs it to ${EXTERNAL_AUTH_URL}/api/AuthJWT/Login.
3

External API authenticates and responds

The external auth API validates the credentials and returns an access_token in the JSON body. The refreshToken is returned as a Set-Cookie header, which the adapter parses via a regex on the raw header value.
4

Backend sets httpOnly cookie and returns access token

AuthController calls res.cookie('refreshToken', refreshToken, COOKIE_OPTIONS) — setting httpOnly: true, the configured secure and sameSite flags, and a maxAge of 24 hours. It then returns { access_token } in the JSON response body via responseUtil.success.
5

Client stores access_token in memory

The client stores the access_token in application memory (never in localStorage). For all subsequent requests to protected routes it sends the token in the Authorization header as a Bearer token.
6

protect middleware verifies the Bearer token

Every request to a protected route passes through the protect middleware, which extracts the Bearer token from the Authorization header, fetches the RS256 public key from the external JWKS endpoint, verifies the signature plus iss and aud claims, and populates req.user with the decoded JwtPayload. See JWT Protection for the full verification flow.
7

Token renewal via refresh endpoint

When the access token expires the client calls POST /api/auth/refresh. The refreshToken cookie is sent automatically by the browser. The backend forwards it to ${EXTERNAL_AUTH_URL}/api/AuthJWT/RefreshToken and, if the external API rotates the refresh token, updates the cookie before returning a new access_token.
8

Logout revokes the session

POST /api/auth/logout forwards the cookie to ${EXTERNAL_AUTH_URL}/api/AuthJWT/Revoke (errors are swallowed with a warning log so logout always succeeds from the client perspective), then clears the refreshToken cookie with res.clearCookie.

Route Protection

Protection is applied centrally in src/routes/index.ts. Auth routes are entirely public; every other route group requires a valid Bearer JWT.
RouteProtectedNotes
/api/auth/*NoLogin, refresh, and logout — public by design
/api/apelaciones/*YesRequires Bearer JWT; rate-limited by apiLimiter
/api/busquedas/*YesRequires Bearer JWT; rate-limited by apiLimiter
/api/estadisticas/*YesRequires Bearer JWT; rate-limited by apiLimiter
Auth routes are additionally protected by a stricter authLimiter (default: 20 requests per 15-minute window) to slow credential-stuffing attempts.

Required Environment Variables

All four authentication environment variables are required. The application calls process.exit(1) at startup if any of them is missing or empty. Set them in your .env file before starting the server.
VariableDescription
EXTERNAL_AUTH_URLBase URL of the external authentication API (no trailing slash). Used by both AuthExternalAdapter and the JWKS client in protect.
JWT_ISSUERExpected iss claim in every JWT. Passed as issuer to jwt.verify.
JWT_AUDIENCEExpected aud claim in every JWT. Passed as audience to jwt.verify.
ID_SISTEMASystem identifier forwarded to the external API during login as idSistema.
Additional related variables — COOKIE_SECURE, COOKIE_SAME_SITE, CORS_ORIGINS — control cross-site cookie and CORS behaviour and should also be reviewed for production deployments.

Quick-start: Login and Call a Protected Route

# 1. Obtain an access token
curl -s -c cookies.txt -X POST http://localhost:4000/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"usuario": "jdoe", "contrasenia": "s3cr3t"}' \
  | jq -r '.data.access_token'

# Store the token in a shell variable
TOKEN=$(curl -s -c cookies.txt -X POST http://localhost:4000/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"usuario": "jdoe", "contrasenia": "s3cr3t"}' \
  | jq -r '.data.access_token')

# 2. Call a protected endpoint
curl -s http://localhost:4000/api/apelaciones \
  -H "Authorization: Bearer $TOKEN" | jq

# 3. Refresh the token (the refreshToken cookie is sent automatically)
TOKEN=$(curl -s -b cookies.txt -c cookies.txt \
  -X POST http://localhost:4000/api/auth/refresh \
  | jq -r '.data.access_token')

# 4. Logout
curl -s -b cookies.txt -X POST http://localhost:4000/api/auth/logout
The -c cookies.txt flag tells curl to save the refreshToken cookie set by the server; -b cookies.txt sends it on subsequent requests, mirroring what a browser does automatically.

Auth Endpoint Reference

POST /api/auth/login

Authenticate with usuario and contrasenia. Returns access_token; sets refreshToken httpOnly cookie.

POST /api/auth/refresh

Exchange a valid refreshToken cookie for a new access_token. Rotates the cookie if the external API issues a new refresh token.

POST /api/auth/logout

Revoke the session on the external API and clear the refreshToken cookie.

Build docs developers (and LLMs) love