Autentificare și autorizare
ASYDATA folosește ASP.NET Core Identity nativ pentru autentificare, cu Google OAuth pentru login. Nu există server de identitate extern (Keycloak a fost respins): totul rulează în procesul .NET, sub jurisdicția noastră (PII de login = date sensibile). Această pagină descrie ce e implementat, cum se leagă de multi-tenancy și ce urmează.
Ce e implementat
Secțiune intitulată „Ce e implementat”Configurarea trăiește în AddAsyAuthentication
(asydata-app-backend-dotnet/src/Asy.Infrastructure/Auth/AuthExtensions.cs):
| Element | Stare |
|---|---|
| ASP.NET Core Identity peste EF Core (Postgres pooled) | ✅ |
Google OAuth (Microsoft.AspNetCore.Authentication.Google) | ✅ wired |
Sesiune pe cookie după login (asy.session, HttpOnly, SameSite=Lax, 14 zile sliding) | ✅ |
/api/auth/google/login → 302 Google (PKCE S256) → callback → cookie | ✅ |
/api/auth/me ([Authorize], cookie-protected) | ✅ |
| Roluri Identity + token providers default | ✅ |
Personal Access Tokens (PAT) pentru agenți AI pe /api/mcp | ✅ |
Flux de login
Secțiune intitulată „Flux de login”SPA ─► /api/auth/google/login ─► 302 Google (scope: openid email profile) │ Google callback ─► upsert AppUser ─► sign-in cookie "asy.session"Cookie-ul e schema default pentru tot (inclusiv challenge): pe /api/* neautentificat se întoarce
401 (nu 302 către Google) — login-ul Google se declanșează explicit din /api/auth/google/login.
Scope-urile Google sunt doar non-sensitive (openid, email, profile) → fără ecran „app
neverificat”. Login = doar identitate; emailurile tranzacționale se trimit separat.
MFA (step-1 cookie)
Secțiune intitulată „MFA (step-1 cookie)”Există deja schele pentru MFA: un cookie scurt separat (asy.mfa, 15 min) emis după Google când
userul are TwoFactorEnabled; sesiunea completă se emite doar după /api/auth/mfa/verify. Vezi
MfaTokenService (asydata-app-backend-dotnet/src/Asy.Infrastructure/Auth/MfaTokenService.cs).
Planul (docs/SECURITY_PLAN.md): cod 6 cifre prin email (Gmail), nu TOTP — publicul țintă fiind
contabilii, friction-ul authenticator-ului e prea mare; TOTP rămâne opt-in pentru roluri sensibile.
Multi-tenancy peste Identity
Secțiune intitulată „Multi-tenancy peste Identity”Identity nu are concept nativ de tenant. Modelul ASYDATA:
ApplicationUser(AppUser) extins cu apartenența la companii;- relația user ↔ companie prin
CompanyMember (user_id, company_id, role, status); - tenantul efectiv al unui request se rezolvă separat de identitate, în
TenantContextMiddleware, din headerX-Firm-Idsau (canonical) claimfirm_id— vezi Multi-tenancy și RLS.
Astfel un user poate aparține mai multor firme, iar firma activă vine din context (header/claim), nu din identitatea fixă.
Autorizare (RBAC)
Secțiune intitulată „Autorizare (RBAC)”Peste autentificare, accesul pe modul/acțiune se decide cu filtrul RequirePermission
(asydata-app-backend-dotnet/src/Asy.Platform/Authorization/RequirePermission.cs):
routes.MapGet(...).RequirePermission("efactura", "view");Decizia (Allow / Deny / Unauthenticated) e delegată unui IPermissionEnforcer din
Infrastructure (care vede DbContext-ul: rolul userului în firmă + permisiunile rolului). Pentru harta
rolurilor și permisiunilor, vezi Actori și roluri.
Roadmap (pending — decizii Alex)
Secțiune intitulată „Roadmap (pending — decizii Alex)”Ce nu avem încă (docs/AUTH.md, docs/SECURITY_PLAN.md):
| Lipsă | De ce contează |
|---|---|
| JWT access tokens | necesar pentru mobile native sau SPA pe alt domeniu (acum SPA e same-origin → cookie ajunge) |
| Refresh tokens cu rotation | cookie-ul de 14 zile e „all-or-nothing” |
| Token revocation / session revocation | suspendarea unui user nu invalidează imediat cookie-ul |
| CSRF explicit, rate limiting, audit log | întăriri pre-prod |
| Magic-link prin email | planificat (flow propriu peste Identity) |
Două direcții majore, pending de la dev (Alex Cozlovschi):
- Opțiunea A — BFF cookie-only (recomandată cât timp SPA stă în
wwwroot, same-origin): SPA nu vede niciodată JWT, serverul ține tokenurile. - Opțiunea B — JWT bearer + refresh cu rotation: necesară doar dacă apare mobile app sau SPA pe alt domeniu.
Pentru session revocation, planul preferat e SecurityStamp (Identity nativ): schimbi stamp-ul la suspend/role-change → cookie-urile vechi devin invalide la următorul tick.
Legături
Secțiune intitulată „Legături”- Izolarea per tenant peste identitate: Multi-tenancy și RLS.
- Roluri și permisiuni: Actori și roluri.
- Unde stă auth în straturi: Clean Architecture + module.
- Stack și decizii respinse: Stack tehnologic.