Auth eta segurtasuna

Token arkitektura

Login-ean bi token ematen dira eta tokens taulan mantentzen dira:

TokenBiltegiratzeaBizitzaHelburua
Access token (JWT)Frontend cookie access_token15 min (JWT_ACCESS_EXPIRES_IN)Request guztietan Authorization: Bearer gisa bidaltzen da
Refresh token (hex opakoa)Backend HTTP-only cookie7 egun (JWT_REFRESH_EXPIRES_DAYS)Erabilera bakoitzean biratzen da /api/auth/refresh bidez

Login fluxua

1. POST /api/auth/login { email, password }
   -> Backend-ak bcrypt hash-a egiaztatzen du
   -> Sinatutako JWT access token-a ematen du (15 min)
   -> Refresh token-a sortu eta tokens taulan gordetzen du
   -> refresh_token HttpOnly cookie gisa ezartzen du
   -> { user, access_token } itzultzen du body-an

2. Frontend-ak access_token cookiean gordetzen du:
   SameSite=Strict, max-age=900, Secure produkzioan

Refresh fluxua

3. Background query-a 12 minuturo exekutatzen da (SessionKeepAlive bidez)
   -> POST /api/auth/refresh (cookiea automatikoki bidaltzen da)
   -> Backend-ak refresh token-a balidatzen du (ez ezeztatua, ez iraungia)
   -> DB-ko refresh token zaharraren errenkada ezeztatzen du
   -> Refresh token errenkada berria txertatzen du
   -> { access_token } berria itzultzen du + cookie berria ezartzen du

4. Axios interceptor-a ustekabeko 401ean:
   -> Refresh egiten du eta jatorrizko request-a behin berriro bidaltzen du
   -> Bigarren hutsegitean: access_token garbitu eta /login-era birbideratzen du

Logout fluxua

5. POST /api/auth/logout
   -> Backend-ak refresh_token DB-an ezeztatzen du
   -> refresh_token cookiea garbitzen du
   -> Frontend-ak access_token cookiea garbitzen du

Backend-eko res.ok() helper-ak hau aplikatzen du:

Inguruneaaccess_token cookiearefresh_token cookiea
GarapenaSameSite=StrictSameSite=Lax; HttpOnly
ProdukzioaSameSite=Strict; SecureSameSite=None; Secure; HttpOnly

Frontend-ak access token cookiea zuzenean ezartzen du (ez HttpOnly). Hau esposizio azalera ezaguna da; ikusi beheko arriskuak.

Rol eredua

Bi rol daude, route handler guztietan requireAuth(request, allowedRoles) bidez aplikatuta:

RolaSarbidea
adminErabiltzaile kudeaketa, pakete kudeaketa, ruta sorrera, logak
distributorBere paketeak, bere eguneroko ruta, stop iritsiera, pakete egoera eguneraketak

Ruta publikoak (auth gabe)

  • POST /api/auth/login
  • POST /api/auth/forgotPassword
  • PATCH /api/auth/changePwd (token bidezkoa, ez Bearer)
  • GET /api/tracking/:trackingToken (tracking orri publikoa)

Password reset fluxua

1. POST /api/auth/forgotPassword { email }
   -> Beti mezu neutroarekin erantzuten du (email enumeraziorik gabe)
   -> Emaila existitzen bada: reset_pwd_token sortzen du (24h), emaila bidaltzen du

2. PATCH /api/auth/changePwd { reset_pwd_token }
   -> { valid: true } itzultzen du (token egiaztapena, password aldaketarik gabe)

3. PATCH /api/auth/changePwd { reset_pwd_token, new_password }
   -> Token-a ez ezeztatua eta ez iraungia dela balidatzen du
   -> password_hash eguneratzen du, token-a ezeztatzen du
   -> { message: "Password changed successfully" } itzultzen du

Kontu aktibazio fluxua

1. Admin: POST /api/users/create { name, email, role }
   -> Erabiltzailea is_active=FALSE-rekin sortzen da
   -> activate_account_token sortzen da (24h iraungipena)
   -> Aktibazio emaila erabiltzaileari bidaltzen zaio

2. Erabiltzaileak link-a klikatzen du -> POST /api/auth/activateAccount?token=...
   -> Erabiltzaileak bere password-a ezartzen du
   -> is_active=TRUE, token-a ezeztatuta

Arrisku ezagunak

LarritasunaArriskuaIturria
HighJWT_SECRET-ek fallback hardcodeatua du envConfig.ts-n. Produkzioan ez bada ezartzen, repoarekin edonork access token-ak faltsutu ditzake.backend-js/src/app/config/envConfig.ts:14
HighDEFAULT_USER_PASSWORD-ek fallback hardcodeatu bera du. Env var-a falta bada, erabiltzaile berriek password ezagun bat jasotzen dute.backend-js/src/app/config/envConfig.ts:37
MediumhandleError-ek barneko error.message HTTP 500 erantzunetan aurrera bidaltzen du. MySQL edo liburutegi erroreek taula izenak eta stack xehetasunak filtratu ditzakete.backend-js/src/app/lib/response.ts:83
Medium@upstash/ratelimit eta @upstash/redis instalatuta daude baina ez konektatuta. Login, forgotPassword eta tracking endpoint-ak brute force-ren aurka babesik gabe daude.backend-js/package.json
MediumAccess token-a ez-HttpOnly cookiean gordetzen da (access_token). XSS-k irakur dezake. Refresh token-a HttpOnly cookiean seguruago dago.frontend-app/app/lib/api/helpers/client.ts
LowGOOGLE_DIRECTIONS_API_KEY-ek TypeScript ! assertion-a erabiltzen du startup guard gabe. Var-a falta bada undefined isila runtime-an.backend-js/src/app/config/envConfig.ts:9
LowMySQL env aldagaiak ez dira startup-ean balidatzen. Pool-ak undefined isilik onartzen du; lehen query-ak huts egiten du startup errore deskriptiborik gabe.backend-js/src/app/config/envConfig.ts:1-5

Sekretu hardcodeatuak konpontzea

envConfig.ts-n behar den gutxieneko aldaketa:

// Unekoa (ez segurua):
export const jwt_secret = process.env.JWT_SECRET ?? "kjhaf7ya...";
 
// Honela izan behar du:
const jwt_secret = process.env.JWT_SECRET;
if (!jwt_secret) throw new Error("JWT_SECRET env var is required");
export { jwt_secret };

Aplikatu patroi bera DEFAULT_USER_PASSWORD eta GOOGLE_DIRECTIONS_API_KEY aldagaietan.

Rate limiting inplementatzea

@upstash/ratelimit dagoeneko package.json-en dago. Aktibatzeko:

  1. Gehitu UPSTASH_REDIS_REST_URL eta UPSTASH_REDIS_REST_TOKEN .env.local-era.
  2. Sortu backend-js/src/app/lib/rateLimit.ts Ratelimit instantzia batekin.
  3. Deitu limiter-ari hasieran: POST /api/auth/login, POST /api/auth/forgotPassword, GET /api/tracking/:token.