# Frontend Auth And Company Selection ## Runtime actual El frontend ERP usa el runtime nuevo: ```txt @erp/identity/client IdentityAuthSessionProvider DataSourceProvider Axios compartido ``` No debe usarse `@erp/auth/client` como runtime nuevo. ## Flujo actual ```txt login -> GET /identity/auth/session -> GET /companies/available -> resolver empresa activa -> auto-selección si hay una sola empresa -> selector si hay varias -> /no-companies si no hay empresas -> X-Company-Id en rutas tenant-scoped ``` ## Login El login usa: ```http POST /identity/auth/login ``` Tras login correcto: - se guardan `accessToken` y `refreshToken` - se limpia cualquier `activeCompanyId` previo - se carga `GET /companies/available` - se resuelve el redirect autenticado según companies disponibles ## Session restore Si existe `accessToken` persistido: 1. se llama `GET /identity/auth/session` 2. se hidrata la sesión autenticada 3. se llama `GET /companies/available` 4. se resuelve `activeCompanyId` persistido o auto-selección Si la restauración falla: - se limpia la sesión - se limpia `activeCompanyId` ## Selección de empresa ### Cero empresas Si `companies.length === 0`: - se muestra `/no-companies` - no existe `activeCompanyId` - no se envía `X-Company-Id` - sigue disponible el logout ### Una empresa Si `companies.length === 1`: - se selecciona automáticamente - se guarda `activeCompanyId` - no se muestra `/company-selection` - se continúa al área privada ### Varias empresas Si `companies.length > 1`: - se muestra `/company-selection` - no existe `activeCompanyId` hasta elegir - el usuario selecciona company - se guarda `activeCompanyId` - se continúa al área privada ### `activeCompanyId` persistido ya no disponible Si el `activeCompanyId` persistido ya no aparece en `GET /companies/available`: - con `0` companies -> `/no-companies` - con `1` company -> auto-selección de la disponible - con varias companies -> `/company-selection` ## `GET /companies/available` Endpoint actual: ```http GET /companies/available Authorization: Bearer ``` No requiere: - `X-Company-Id` No usa: - `requireIdentityTenant(params)` Devuelve: ```ts export type AvailableCompaniesResponseDTO = { companies: AvailableCompanyDTO[]; }; ``` ## Headers ### No deben llevar `X-Company-Id` ```txt POST /identity/auth/login POST /identity/auth/refresh POST /identity/auth/logout GET /identity/auth/session GET /companies/available ``` ### Sí deben llevar `X-Company-Id` Rutas tenant-scoped como: - `/customers` - `/catalogs/*` - `/customer-invoices/*` - `/factuges` siempre que exista `activeCompanyId`. ## Refresh automático sobre `401` El frontend implementa refresh automático global sobre Axios. Comportamiento: 1. una request autenticada recibe `401` 2. si existe `refreshToken`, se llama `POST /identity/auth/refresh` 3. se guardan los nuevos tokens 4. se reintenta una única vez la request original 5. si refresh falla, se limpia la sesión y se redirige a `/login` ## Reglas implementadas - retry único por request con `_retry` - refresh concurrente único con `refreshPromise` compartida - varias requests `401` esperan el mismo refresh - login `401` no dispara refresh - refresh `401` no intenta refrescarse a sí mismo - `/identity/auth/refresh` no lleva `X-Company-Id` - la request tenant-scoped reintentada conserva `X-Company-Id` ## Endpoints excluidos de tenant header y refresh ```txt /identity/auth/login /identity/auth/refresh /identity/auth/logout /identity/auth/session /companies/available ```