node-user-auth
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
nginxper il traffico web di default,apiKeyper ambienti dev/test,oauthcon token introspection per M2M,jwtself-contained per casi che richiedono token firmato verificabile offline - Endpoint
/nginx/authdedicato aauth_request: valida cookie/JWT, esegue refresh inline trasparente e propaga gli headerX-Auth-User,X-Auth-User-ID,X-Auth-Session-IDal 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-profilingper 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/):
| Layer | Contenuto |
|---|---|
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/logincon credenziali → il servizio valida l'identità presso il provider esterno (OIDC) o pressonode-user-profiling, materializza una sessione su Redis ed emette i cookieHttpOnlyjwt_tokenerefresh_token. Tutte le chiamate successive dal browser verso qualsiasi servizio del namespace passano dalauth_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. haauth_request /nginx/authconfigurato verso questo servizio; nessun altro microservizio implementa logica di auth — si limita a leggereX-Auth-User-IDdagli header iniettati. - M2M con OAuth2 Client Credentials:
node-schedulero un modulo orchestratore esterno richiede un access token aPOST /user-auth/oauth/tokencongrant_type=client_credentials; il token JWT firmato viene poi verificato dal microservizio destinazione tramite la chiave pubblica esposta su JWKS, oppure introspettato suPOST /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.AUTHcheNatsAuthCalloutServiceconsuma, 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
| Campo | Valore |
|---|---|
| Categoria | identity |
| Versione cluster | 1.0.0 |
| Image | gitea.pzetatouch.it/pzeta_touch/node-user-auth:1.0.80 |
| URL pubblico | https://ditta.pzeta.it/user-auth |
| Path regex ingress | `/user-auth(/ |
| Rewrite a backend | /$2 |
| DNS interno | node-user-auth-ditta.ditta.svc.cluster.local:3000 |
| Auth nginx | no auth nginx (servizio pubblicamente accessibile) |
| Repository | node-user-auth |
| Endpoint REST | 84 (vedi sezione "API reference") |
Endpoint operazionali
Endpoint convenzionali esposti da tutti i microservizi PZeta basati su @pzeta/fastify-utils:
| Path pubblico | Scopo |
|---|---|
https://ditta.pzeta.it/user-auth/health | liveness probe |
https://ditta.pzeta.it/user-auth/ready | readiness probe |
https://ditta.pzeta.it/user-auth/metrics | metriche Prometheus |
https://ditta.pzeta.it/user-auth/api-docs.json | spec OpenAPI runtime (richiede OPENAPI_EXPOSE_IN_PRODUCTION=true) |
https://ditta.pzeta.it/user-auth/api-docs | Swagger UI (solo in NODE_ENV !== production) |
A questi si aggiungono, specifici per il dominio auth:
| Path pubblico | Scopo |
|---|---|
https://ditta.pzeta.it/user-auth/nginx/auth | endpoint chiamato da auth_request per validare cookie/JWT e propagare header utente |
https://ditta.pzeta.it/user-auth/.well-known/jwks.json | chiavi pubbliche JWKS per la verifica dei JWT da parte dei consumer |
https://ditta.pzeta.it/user-auth/.well-known/openid-configuration | discovery document OIDC |
https://ditta.pzeta.it/user-auth/oauth/introspect | introspection 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):
| Variabile | Ruolo |
|---|---|
DATABASE_HOST / _PORT / _USER / _PASSWORD / _NAME | Connessione PostgreSQL — utenti, sessioni persistenti, audit log, configurazione dinamica |
REDIS_HOST / _PORT / _PASSWORD | Sessioni, rate limiting, blocklist IP, cache profilazione |
JWT_PRIVATE_KEY_PATH / JWT_PUBLIC_KEY_PATH | Path 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_AUDIENCE | Claim iss/aud standard; tutti i consumer devono allinearli |
JWT_ALGORITHM | Algoritmo di firma (RS256 default, EdDSA supportato) |
JWT_ACCESS_TOKEN_EXPIRES_IN / JWT_REFRESH_TOKEN_EXPIRES_IN | TTL nel formato ` |
COOKIE_SECRET | Segreto (≥32 char) per firmare i cookie jwt_token e refresh_token |
COOKIE_SECURE / COOKIE_HTTP_ONLY / COOKIE_SAME_SITE / COOKIE_MAX_AGE | Flag dei cookie di sessione; secure=true obbligatorio se sameSite=none |
ENABLE_AUTH_COOKIES | Abilita il flusso cookie-based per POST /auth/login (default per il frontend Vue) |
API_KEYS | Lista key:user:scopes per la strategia apiKey — uso dev/test, non in produzione |
OAUTH_INTROSPECTION_URL | URL di introspection del provider OAuth2 esterno (per la strategia oauth M2M, se non si verifica via JWKS) |
USER_PROFILING_URL | Base URL di node-user-profiling per ruoli, scope e profilazione contestuale |
NATS_URL | URL del cluster NATS; necessario per il subscriber Auth Callout |
ORCHESTRATOR_ENABLED / ORCHESTRATOR_URL / MODULE_ID | Registrazione opzionale come modulo di node-orchestrator per esporre task riusabili (revoca sessione, sblocco account, ecc.) |
RATE_LIMIT_MAX / RATE_LIMIT_WINDOW | Soglie generali di rate limiting; quelle specifiche per /auth/* sono governate da SecurityPolicy su DB |
OPENAPI_EXPOSE_IN_PRODUCTION | Espone /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):
node-orchestratornode-notificationnode-storagenode-printnode-renderernode-schedulernode-excel-exportnode-excel-importnode-xmlvalidationnode-postgrest-sidecaringress nginx (auth_request)
Infrastruttura (PostgreSQL, NATS, Redis, MinIO) non è elencata qui — vedi sezione Architettura del singolo servizio.