node-user-auth

Provider di autenticazione e sessione utente. È l'auth backend per gli altri ingress (sub-request nginx).
identity
/user-authauth: public

node-user-auth

In sintesi

Auth backend trasversale del namespace ditta: ogni richiesta che arriva sugli altri ingress passa prima da qui via nginx auth_request, e solo se la risposta è 200 la richiesta originale viene inoltrata al microservizio applicativo. Il servizio non memorizza password — l'identità arriva da un Identity Provider esterno (OAuth2/OIDC o claim propagati da nginx) e qui viene materializzata in sessione, ruolo Postgres, claim JWT e cookie. Espone quattro strategie di autenticazione (nginx, apiKey, oauth, jwt) che coprono traffico utente da browser, comunicazione M2M fra microservizi e accessi di sviluppo o test.

Funzionalità principali

  • Multi-strategia auth sullo stesso processo: subrequest nginx per il traffico web di default, apiKey per ambienti dev/test, oauth con token introspection per M2M, jwt self-contained per casi che richiedono token firmato verificabile offline
  • Endpoint /nginx/auth dedicato a auth_request: valida cookie/JWT, esegue refresh inline trasparente e propaga gli header X-Auth-User, X-Auth-User-ID, X-Auth-Session-ID al backend protetto
  • Sessioni server-side su Redis con TTL standard ed esteso ("remember me"), limite di sessioni concorrenti, cleanup periodico e revoca puntuale o massiva
  • JWT asimmetrici RS256/EdDSA firmati con chiave privata custodita dal servizio; chiave pubblica esposta via JWKS per la verifica da parte degli altri microservizi
  • Token rotation dei refresh token con detection del riuso (reuse → revoca dell'intera famiglia)
  • OAuth2/OIDC completo: Authorization Code + PKCE, Client Credentials, Refresh, Token Exchange (RFC 8693), Device Authorization Grant, introspection endpoint per i consumer M2M
  • MFA TOTP opzionale con backup codes, integrato nel flusso di login standard
  • Rate limiting e brute-force protection specifici per endpoint sensibili (/auth/login, /auth/refresh, /auth/forgot-password) con progressive delay e IP blocking
  • NATS Auth Callout subscriber su $SYS.REQ.USER.AUTH: autorizza gli utenti NATS riusando le stesse policy applicative
  • Integrazione con node-user-profiling per ruoli, scope e profilazione contestuale (device, geo, behavior)
  • Audit logging strutturato per ogni evento di sicurezza (login, refresh, logout, lockout, revoca) con correlation ID

Architettura

Stack: Fastify v5 · Inversify (DI con constructor injection) · PostgreSQL via driver pg · Redis (sessioni, rate limiting, blocklist) · jose per JWT/JWS/JWE · @fastify/cookie per i cookie firmati · bcrypt per gli hash legacy migrati · speakeasy per TOTP · device-detector-js + geoip-lite per il contesto Zero Trust · @pzeta/fastify-utils (security, errorHandler, openapi plugins) · @pzeta/node-user-auth (schemi Zod condivisi con i consumer) · @pzeta/log per logging correlato.

Layout DDD (src/):

LayerContenuto
domain/Aggregate User, Session, value object (password policy, scope), eventi di dominio, errori, SecurityPolicy
application/services/AuthenticationService, SessionService, TotpService (authentication); OAuth2Service, OidcService, TokenExchangeService, DeviceAuthorizationService, ClientCredentialsGrantService, RefreshTokenRotationService (oauth2); JwtPayloadBuilder + ClaimProviderRegistry (jwt); use case password, registration, invitation, social, admin
infrastructure/DatabaseConnectionManager, RedisConnectionManager, JwtKeyInitializer, NatsAuthCalloutService, OrchestratorIntegrationService, RateLimitService, BruteForceProtection, ConfigurationService/SystemConfigurationService
presentation/NginxAuthRoutes, EnhancedAuthRoutes, OAuth2Routes, OidcRoutes, MfaRoutes, SessionRoutes, PasswordRoutes, RegistrationRoutes, InvitationRoutes, SocialAuthRoutes, Admin*Routes, NatsRealtimeRoutes; AuthMiddleware e RateLimitMiddlewareFactory

Pattern adottati: multi-strategia di autenticazione orchestrata da AuthMiddleware, Repository, Token Rotation con famiglia, Singleton thread-safe per la configurazione, Claim Provider Registry per arricchire i JWT (estensibile da plugin esterni), Circuit Breaker sulle chiamate a node-user-profiling, Audit Trail su PostgreSQL.

Flusso nginx auth_request: il browser richiede https://ditta.pzeta.it/orchestrator/foo → l'ingress nginx esegue una subrequest interna verso GET /user-auth/nginx/auth → il controller NginxAuthController valida cookie jwt_token/refresh_token, se necessario esegue refresh inline e propaga il nuovo cookie via X-Auth-Set-Cookie (che nginx rimette nella response originale), poi risponde 200 con header X-Auth-User, X-Auth-User-ID, X-Auth-Session-ID → nginx legge gli header, li propaga al backend (proxy_set_header) e instrada la richiesta a node-orchestrator. In caso di sessione assente o invalida la risposta è 401 e nginx restituisce un redirect a /login. La cache di auth_request deve essere ≤30 s o disabilitata, altrimenti maschera la scadenza del cookie e impedisce il refresh trasparente.

Casi d'uso

  • Login utente da Vue (cookie JWT): il frontend chiama POST /user-auth/auth/login con credenziali → il servizio valida l'identità presso il provider esterno (OIDC) o presso node-user-profiling, materializza una sessione su Redis ed emette i cookie HttpOnly jwt_token e refresh_token. Tutte le chiamate successive dal browser verso qualsiasi servizio del namespace passano dal auth_request, che riconosce i cookie e propaga gli header al backend.
  • Subrequest nginx per microservizi protetti: ogni ingress di node-orchestrator, node-storage, node-notification, ecc. ha auth_request /nginx/auth configurato verso questo servizio; nessun altro microservizio implementa logica di auth — si limita a leggere X-Auth-User-ID dagli header iniettati.
  • M2M con OAuth2 Client Credentials: node-scheduler o un modulo orchestratore esterno richiede un access token a POST /user-auth/oauth/token con grant_type=client_credentials; il token JWT firmato viene poi verificato dal microservizio destinazione tramite la chiave pubblica esposta su JWKS, oppure introspettato su POST /user-auth/oauth/introspect.
  • API key per integrazioni dev/test: uno script di seed o un test E2E imposta l'header x-api-key; le chiavi sono configurate via env (API_KEYS) e mappano a un utente fittizio con scope ristretti — utile in pipeline CI e per debug locale senza coinvolgere il provider esterno.
  • Autenticazione NATS: i client NATS dei microservizi PZeta non si autenticano con credenziali statiche; quando aprono la connessione al broker, NATS pubblica una richiesta su $SYS.REQ.USER.AUTH che NatsAuthCalloutService consuma, verifica il JWT presentato e risponde con i permessi pub/sub appropriati per quel servizio.
  • MFA per utenti privilegiati: gli admin abilitano TOTP via POST /auth/mfa/setup; il login successivo richiede un secondo step che valida il codice prima di emettere i cookie di sessione.

Identità & esposizione

CampoValore
Categoriaidentity
Versione cluster1.0.0
Imagegitea.pzetatouch.it/pzeta_touch/node-user-auth:1.0.80
URL pubblicohttps://ditta.pzeta.it/user-auth
Path regex ingress`/user-auth(/
Rewrite a backend/$2
DNS internonode-user-auth-ditta.ditta.svc.cluster.local:3000
Auth nginxno auth nginx (servizio pubblicamente accessibile)
Repositorynode-user-auth
Endpoint REST84 (vedi sezione "API reference")

Endpoint operazionali

Endpoint convenzionali esposti da tutti i microservizi PZeta basati su @pzeta/fastify-utils:

Path pubblicoScopo
https://ditta.pzeta.it/user-auth/healthliveness probe
https://ditta.pzeta.it/user-auth/readyreadiness probe
https://ditta.pzeta.it/user-auth/metricsmetriche Prometheus
https://ditta.pzeta.it/user-auth/api-docs.jsonspec OpenAPI runtime (richiede OPENAPI_EXPOSE_IN_PRODUCTION=true)
https://ditta.pzeta.it/user-auth/api-docsSwagger UI (solo in NODE_ENV !== production)

A questi si aggiungono, specifici per il dominio auth:

Path pubblicoScopo
https://ditta.pzeta.it/user-auth/nginx/authendpoint chiamato da auth_request per validare cookie/JWT e propagare header utente
https://ditta.pzeta.it/user-auth/.well-known/jwks.jsonchiavi pubbliche JWKS per la verifica dei JWT da parte dei consumer
https://ditta.pzeta.it/user-auth/.well-known/openid-configurationdiscovery document OIDC
https://ditta.pzeta.it/user-auth/oauth/introspectintrospection token endpoint per i consumer M2M

Configurazione

Variabili d'ambiente che un integratore deve conoscere (per la lista completa vedi config/example.env del repo):

VariabileRuolo
DATABASE_HOST / _PORT / _USER / _PASSWORD / _NAMEConnessione PostgreSQL — utenti, sessioni persistenti, audit log, configurazione dinamica
REDIS_HOST / _PORT / _PASSWORDSessioni, rate limiting, blocklist IP, cache profilazione
JWT_PRIVATE_KEY_PATH / JWT_PUBLIC_KEY_PATHPath ai PEM RSA/EdDSA; in alternativa JWT_PRIVATE_KEY_PEM / JWT_PUBLIC_KEY_PEM inline. Se mancanti in dev le chiavi vengono generate automaticamente al boot
JWT_ISSUER / JWT_AUDIENCEClaim iss/aud standard; tutti i consumer devono allinearli
JWT_ALGORITHMAlgoritmo di firma (RS256 default, EdDSA supportato)
JWT_ACCESS_TOKEN_EXPIRES_IN / JWT_REFRESH_TOKEN_EXPIRES_INTTL nel formato `<s
COOKIE_SECRETSegreto (≥32 char) per firmare i cookie jwt_token e refresh_token
COOKIE_SECURE / COOKIE_HTTP_ONLY / COOKIE_SAME_SITE / COOKIE_MAX_AGEFlag dei cookie di sessione; secure=true obbligatorio se sameSite=none
ENABLE_AUTH_COOKIESAbilita il flusso cookie-based per POST /auth/login (default per il frontend Vue)
API_KEYSLista key:user:scopes per la strategia apiKey — uso dev/test, non in produzione
OAUTH_INTROSPECTION_URLURL di introspection del provider OAuth2 esterno (per la strategia oauth M2M, se non si verifica via JWKS)
USER_PROFILING_URLBase URL di node-user-profiling per ruoli, scope e profilazione contestuale
NATS_URLURL del cluster NATS; necessario per il subscriber Auth Callout
ORCHESTRATOR_ENABLED / ORCHESTRATOR_URL / MODULE_IDRegistrazione opzionale come modulo di node-orchestrator per esporre task riusabili (revoca sessione, sblocco account, ecc.)
RATE_LIMIT_MAX / RATE_LIMIT_WINDOWSoglie generali di rate limiting; quelle specifiche per /auth/* sono governate da SecurityPolicy su DB
OPENAPI_EXPOSE_IN_PRODUCTIONEspone /api-docs.json anche in produzione (off di default)

FORBIDDEN: nessuna variabile contiene o accetta password utente in chiaro. Le credenziali primarie sono delegate all'Identity Provider esterno; questo servizio gestisce solo claim, hash di tecnologia (cookie secret, JWT secret) e configurazione di sicurezza.

Note eventing NATS

Il servizio è esclusivamente subscriber di sistema: si registra su $SYS.REQ.USER.AUTH (subject di sistema riservato a NATS Auth Callout) e risponde sincronicamente con le claim del client che sta tentando di connettersi al broker. Non pubblica eventi applicativi propri — l'auth callout sostituisce, su NATS, il ruolo che il subrequest svolge per HTTP.

I consumer non si "sottoscrivono" a questo servizio: lo invocano via HTTP o, indirettamente, via il broker. Per questo motivo lo scanner statico riporta zero publishes e un solo subscribe di sistema.

Dipendenze e dipendenti

Dipende da (servizi che questo servizio chiama):

Consumato da (chi chiama questo servizio):

Infrastruttura (PostgreSQL, NATS, Redis, MinIO) non è elencata qui — vedi sezione Architettura del singolo servizio.

Loading OpenAPI…
Loading NATS contracts…