eqeqo-api-auth

Crates.ioeqeqo-api-auth
lib.rseqeqo-api-auth
version0.0.1
created_at2025-12-29 15:11:14.249353+00
updated_at2025-12-29 15:11:14.249353+00
descriptionCentralized authentication and authorization API for multiple independent services. Manages users, roles, permissions, and service associations.
homepagehttps://gitlab.com/numanope/eqeqo/bazoj/auth-api
repositoryhttps://gitlab.com/numanope/eqeqo/bazoj/auth-api
max_upload_size
id2010726
size326,353
fahedsl (fahedslx)

documentation

README

EQEQO Auth API

Centralized authentication and authorization service for the Eqeqo ecosystem. Issues short-lived tokens, renews them atomically near expiry, and enforces access control with a DB-backed token cache plus periodic cleanup.

βš™οΈ Setup

Local setup

psql -U postgres -f db/run_all.sql
cp .env.example .env
cargo run

Tests Integration tests rely on the seeded api_auth DB from db/run_all.sql. Default server: http://127.0.0.1:7878

cargo test --test api_test

Environment:

AUTH_DATABASE_URL=postgres://USER:PASSWORD@HOST/api_auth
SERVER_PORT=7878
TOKEN_TTL_SECONDS=300
TOKEN_RENEW_THRESHOLD_SECONDS=30

Data reference: see ./db/DB.md (seeded dataset: IDs, users, services, roles, permissions).

πŸ” Auth essentials

  • All protected routes require the token: header (never pass tokens in URLs).
  • Tokens are cached centrally in auth.tokens_cache; renewal is atomic when near expiry.
  • Logout or user deletion revokes related tokens; a background job prunes expired tokens every ~60 seconds.
  • Minimal logging per request records token, endpoint, timestamp, and IP.
  • Tokens are stored hashed in the cache; user passwords are stored as bcrypt hashes (demo users seeded with bcrypt).

πŸš€ Quick request example

Example: fetching user data for β€œJuan” (id 7) from client servcli1 using an arbitrary token:

curl -X GET "http://127.0.0.1:7878/users/7" \
  -H "token: tok_example_123" \
  -H "x-client-id: servcli1"

x-client-id is optional metadata; the API currently only enforces the token header.

🧩 Endpoints

Method Path Description (minimal example)
POST /auth/login Issue token for user (global). Example: {"username":"adm1","password":"adm1-hash"}
POST /auth/logout Revoke current token. Header: token: <value>
GET /auth/profile Validate and optionally renew token. Header: token: <value>
POST /check-token Validate token (optional user_id in body to enforce match). Header: token: <value>
GET /users List users. Header: token: <value>
POST /users Create user. Example body: {"username":"user1","password_hash":"pass","name":"User","person_type":"N","document_type":"DNI","document_number":"123"} + header token.
PUT /users/{id} Update user. Example: {"name":"New Name"} + header token.
DELETE /users/{id} Delete user and revoke tokens. Header: token.
GET /roles List roles. Header: token.
POST /roles Create role. Example: {"name":"Editor"} + header token.
GET /roles/{id} Get role. Header: token.
PUT /roles/{id} Update role. Example: {"name":"New Role"} + header token.
DELETE /roles/{id} Delete role. Header: token.
GET /permissions List permissions. Header: token.
POST /permissions Create permission. Example: {"name":"export"} + header token.
PUT /permissions/{id} Update permission. Example: {"name":"export_csv"} + header token.
DELETE /permissions/{id} Delete permission. Header: token.
POST /role-permissions Assign permission to role. Example: {"role_id":1,"permission_id":2} + header token.
DELETE /role-permissions Remove permission from role. Example: {"role_id":1,"permission_id":2} + header token.
GET /roles/{id}/permissions List role permissions. Header: token.
POST /services Create service. Example: {"name":"Stock","description":"Inventory"} + header token.
GET /services List services. Header: token.
PUT /services/{id} Update service. Example: {"description":"New desc"} + header token.
DELETE /services/{id} Delete service. Header: token.
POST /service-roles Assign role to service. Example: {"service_id":1,"role_id":2} + header token.
DELETE /service-roles Remove role from service. Example: {"service_id":1,"role_id":2} + header token.
GET /services/{id}/roles List roles of a service. Header: token.
POST /person-service-roles Assign role to person in service. Example: {"person_id":1,"service_id":1,"role_id":2} + header token.
DELETE /person-service-roles Remove role from person in service. Example: {"person_id":1,"service_id":1,"role_id":2} + header token.
GET /people/{person_id}/services/{service_id}/roles List roles of person in service. Header: token.
GET /services/{service_id}/roles/{role_id}/people List people with role in service. Header: token.
GET /people/{person_id}/services List services of a person. Header: token.
GET /people/{person_id}/services/{service_id} Get user data plus roles/permissions for that service (may be empty). Header: token.
POST /person-service-permissions Grant a permission directly to a person in a service (creates/uses a scoped role). Example: {"person_id":1,"service_id":1,"permission_name":"read"} + header token.

πŸ” Token logic

  • Generated at login (hash(secret + random + timestamp)). NO JWT nor similar.

  • Stored centrally in auth.tokens_cache with payload and modified_at; token values are stored hashed (no plaintext).

  • Tokens are issued per user (global); services query permissions by sending token: + person_id + service_id to /people/{person_id}/services/{service_id}.

  • All protected requests must include token: header (no query params). /auth/login is the only public route.

  • Short TTL (2–5 min) with atomic renewal near expiry to avoid contention.

  • Revocation on logout or user deletion; cleanup job periodically removes expired tokens.

  • /check-token can optionally validate user to avoid token misuse.

  • No tokens in URLs.

  • Minimal logging per request: token, endpoint, timestamp, IP.

  • Background cleanup job trims expired tokens every ~60 seconds.

🧭 Use case diagram

sequenceDiagram
  autonumber
  actor UI as Frontend (UI)
  participant BACK as Backend (Stock / Sales / Manufacturing)
  participant AUTH as Auth API

  %% 1. Login
  UI->>AUTH: POST /auth/login { user, pass }
  AUTH-->>UI: { token }

  %% 2. Request from UI to Back
  UI->>BACK: GET /{service_id_string}/{user_id_string}\nheaders: token

  %% 3. Cache check + request to Out
  alt Valid local cache (<= 1 min)
    BACK-->>UI: responds using cached payload
  else Expired or missing cache, valid token in Out
    BACK->>AUTH: POST /check-token\n{ token, service_id, user_id } (token header, hashed in cache)
    AUTH-->>BACK: { valid: true, payload }
    BACK-->>UI: responds and saves payload in cache (1 min)
  else Expired or missing cache, invalid token in Out
    BACK->>AUTH: POST /check-token\n{ token, service_id, user_id } (token header, hashed in cache)
    AUTH-->>BACK: { valid: false }
    BACK-->>UI: 401 Unauthorized
  end

  %% 4. Writes always validated
  Note over BACK,AUTH: Write operations (POST / PATCH / DELETE)\nalways query Out without using local cache.

  %% 5. Logout
  UI->>AUTH: POST /auth/logout { token }
  AUTH-->>UI: 200 Logged out

MIT Β© Eqeqo

Commit count: 0

cargo fmt