136 lines
2.5 KiB
Markdown
136 lines
2.5 KiB
Markdown
# Identity Backend Architecture
|
|
|
|
## Objetivo del módulo `identity`
|
|
|
|
`identity` sustituye progresivamente al módulo legacy `auth`.
|
|
|
|
Responsabilidades actuales:
|
|
|
|
- cuentas autenticables
|
|
- login/password
|
|
- access token
|
|
- refresh token rotado
|
|
- logout
|
|
- sesión actual
|
|
- memberships
|
|
- validación de acceso account-company
|
|
- base para roles/permisos futuros
|
|
|
|
## Dominio actual
|
|
|
|
Agregados y conceptos relevantes:
|
|
|
|
```txt
|
|
Account
|
|
RefreshToken
|
|
CompanyMembership
|
|
Role
|
|
```
|
|
|
|
`Company` funcional no pertenece a `identity`; vive en `modules/companies`.
|
|
|
|
## Seguridad
|
|
|
|
Servicios definidos:
|
|
|
|
```txt
|
|
IPasswordHasher
|
|
IAccessTokenIssuer
|
|
IAccessTokenVerifier
|
|
IRefreshTokenGenerator
|
|
IRefreshTokenHasher
|
|
```
|
|
|
|
Decisiones vigentes:
|
|
|
|
- password hashing con `bcrypt`
|
|
- access token JWT con `accountId` y `email`
|
|
- refresh token aleatorio
|
|
- refresh token persistido como hash
|
|
- no incluir `companyId`, `companySlug`, roles ni permisos en access token
|
|
|
|
## Builders públicos
|
|
|
|
`identity` expone desde `@erp/identity/api`:
|
|
|
|
```ts
|
|
requireIdentityAuthenticated(params: StartParams): RequestHandler[];
|
|
requireIdentityTenant(params: StartParams): RequestHandler[];
|
|
```
|
|
|
|
Uso correcto:
|
|
|
|
```ts
|
|
import { requireIdentityTenant } from "@erp/identity/api";
|
|
|
|
router.use(...requireIdentityTenant(params));
|
|
```
|
|
|
|
```ts
|
|
import { requireIdentityAuthenticated } from "@erp/identity/api";
|
|
|
|
router.use(...requireIdentityAuthenticated(params));
|
|
```
|
|
|
|
## `req.user`
|
|
|
|
Shape mínimo esperado:
|
|
|
|
```ts
|
|
{
|
|
userId: UniqueID;
|
|
email?: EmailAddress;
|
|
companyId?: UniqueID;
|
|
roles?: string[];
|
|
}
|
|
```
|
|
|
|
`req.user.companyId` solo se debe poblar cuando el middleware tenant valida correctamente la request.
|
|
|
|
No añadir:
|
|
|
|
- `companySlug`
|
|
- `company`
|
|
- `permissions` enriquecidos
|
|
- `companyStatus`
|
|
|
|
## Tenant validation
|
|
|
|
`requireIdentityTenant(params)` ya no es solo validación sintáctica.
|
|
|
|
Valida:
|
|
|
|
1. token válido
|
|
2. account autenticable
|
|
3. `X-Company-Id` presente
|
|
4. UUID válido
|
|
5. membership `active`
|
|
6. company `active`
|
|
|
|
## Relación con `companies`
|
|
|
|
- `identity` resuelve membership y accesibilidad
|
|
- `companies` resuelve la ficha operativa de empresa
|
|
- no introducir dependencia `identity -> companies`
|
|
|
|
Si un consumidor necesita `slug`, debe resolverlo desde `companies`, no desde auth.
|
|
|
|
## Prohibiciones de diseño
|
|
|
|
No usar en módulos consumidores:
|
|
|
|
```ts
|
|
IdentityInternalDeps;
|
|
authenticateUserDependencies;
|
|
getInternal("identity");
|
|
```
|
|
|
|
No crear helpers locales de auth por módulo como patrón estable.
|
|
|
|
No añadir al access token:
|
|
|
|
- `companyId`
|
|
- `companySlug`
|
|
- roles
|
|
- permisos
|