@jmlq/auth 0.0.1-alpha.8 → 0.0.1-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.es.md +133 -0
- package/README.md +81 -207
- package/dist/application/dtos/index.d.ts +1 -1
- package/dist/application/dtos/index.js +1 -1
- package/dist/application/dtos/request/change-password.request.d.ts +15 -0
- package/dist/application/dtos/request/index.d.ts +5 -0
- package/dist/application/dtos/request/index.js +5 -0
- package/dist/application/dtos/request/logout.request.d.ts +2 -1
- package/dist/application/dtos/request/me.request.d.ts +3 -0
- package/dist/application/dtos/request/me.request.js +2 -0
- package/dist/application/dtos/request/register-user.request.d.ts +2 -1
- package/dist/application/dtos/request/request-password-reset.request.d.ts +6 -0
- package/dist/application/dtos/request/request-password-reset.request.js +2 -0
- package/dist/application/dtos/request/reset-password.request.d.ts +14 -0
- package/dist/application/dtos/request/reset-password.request.js +2 -0
- package/dist/application/dtos/request/verify-email.request.d.ts +3 -0
- package/dist/application/dtos/request/verify-email.request.js +2 -0
- package/dist/application/dtos/response/change-password.response.d.ts +7 -0
- package/dist/application/dtos/response/change-password.response.js +2 -0
- package/dist/application/dtos/response/index.d.ts +5 -0
- package/dist/application/dtos/response/index.js +5 -0
- package/dist/application/dtos/response/login.response.d.ts +2 -1
- package/dist/application/dtos/response/me.response.d.ts +11 -0
- package/dist/application/dtos/response/me.response.js +2 -0
- package/dist/application/dtos/response/refresh-token.response.d.ts +1 -0
- package/dist/application/dtos/response/register-user.response.d.ts +9 -0
- package/dist/application/dtos/response/request-password-reset.response.d.ts +15 -0
- package/dist/application/dtos/response/request-password-reset.response.js +2 -0
- package/dist/application/dtos/response/reset-password.response.d.ts +7 -0
- package/dist/application/dtos/response/reset-password.response.js +2 -0
- package/dist/application/dtos/response/verify-email.response.d.ts +4 -0
- package/dist/application/dtos/response/verify-email.response.js +2 -0
- package/dist/application/dtos/types/user-role.type.js +2 -0
- package/dist/application/facades/auth.facade.d.ts +33 -0
- package/dist/application/facades/auth.facade.js +60 -0
- package/dist/application/facades/create-auth-facade.d.ts +22 -0
- package/dist/application/facades/create-auth-facade.js +9 -0
- package/dist/application/facades/index.d.ts +2 -0
- package/dist/application/facades/index.js +18 -0
- package/dist/application/factories/auth-service.factory.d.ts +4 -4
- package/dist/application/factories/auth-service.factory.js +16 -4
- package/dist/application/factories/index.js +1 -0
- package/dist/application/types/auth-service-factory-options.type.d.ts +44 -0
- package/dist/application/use-cases/change-password.use-case.d.ts +21 -0
- package/dist/application/use-cases/change-password.use-case.js +49 -0
- package/dist/application/use-cases/index.d.ts +5 -0
- package/dist/application/use-cases/index.js +5 -0
- package/dist/application/use-cases/internal/index.d.ts +1 -0
- package/dist/application/use-cases/internal/index.js +17 -0
- package/dist/application/use-cases/internal/password-assertions.d.ts +13 -0
- package/dist/application/use-cases/internal/password-assertions.js +26 -0
- package/dist/application/use-cases/login-with-password.use-case.js +24 -28
- package/dist/application/use-cases/logout.use-case.js +14 -2
- package/dist/application/use-cases/me.use-case.d.ts +7 -0
- package/dist/application/use-cases/me.use-case.js +28 -0
- package/dist/application/use-cases/refresh-token.use-case.d.ts +16 -2
- package/dist/application/use-cases/refresh-token.use-case.js +33 -5
- package/dist/application/use-cases/register-user.use-case.d.ts +6 -1
- package/dist/application/use-cases/register-user.use-case.js +18 -7
- package/dist/application/use-cases/request-password-reset.use-case.d.ts +19 -0
- package/dist/application/use-cases/request-password-reset.use-case.js +43 -0
- package/dist/application/use-cases/reset-password.use-case.d.ts +20 -0
- package/dist/application/use-cases/reset-password.use-case.js +59 -0
- package/dist/application/use-cases/verify-email.use-case.d.ts +8 -0
- package/dist/application/use-cases/verify-email.use-case.js +30 -0
- package/dist/domain/entities/credential.entity.d.ts +36 -11
- package/dist/domain/entities/credential.entity.js +41 -11
- package/dist/domain/entities/user.entity.d.ts +32 -1
- package/dist/domain/entities/user.entity.js +54 -1
- package/dist/domain/errors/auth-error-code.d.ts +16 -0
- package/dist/domain/errors/auth-error-code.js +60 -0
- package/dist/domain/errors/auth.errors.d.ts +29 -8
- package/dist/domain/errors/auth.errors.js +59 -8
- package/dist/domain/errors/general.errors.d.ts +4 -0
- package/dist/domain/errors/general.errors.js +10 -0
- package/dist/domain/errors/identity.errors.d.ts +17 -12
- package/dist/domain/errors/identity.errors.js +29 -25
- package/dist/domain/errors/index.d.ts +5 -0
- package/dist/domain/errors/index.js +5 -0
- package/dist/domain/errors/jwt-payload.error.d.ts +4 -0
- package/dist/domain/errors/jwt-payload.error.js +10 -0
- package/dist/domain/errors/jwt.errors.d.ts +7 -0
- package/dist/domain/errors/jwt.errors.js +16 -0
- package/dist/domain/errors/password-reset.errors.d.ts +14 -0
- package/dist/domain/errors/password-reset.errors.js +29 -0
- package/dist/domain/index.d.ts +1 -0
- package/dist/domain/index.js +1 -0
- package/dist/domain/ports/auth/email-verification-token.port.d.ts +19 -0
- package/dist/domain/ports/auth/email-verification-token.port.js +2 -0
- package/dist/domain/ports/auth/index.d.ts +2 -0
- package/dist/domain/ports/auth/index.js +2 -0
- package/dist/domain/ports/auth/password-reset-token.port.d.ts +36 -0
- package/dist/domain/ports/auth/password-reset-token.port.js +2 -0
- package/dist/domain/ports/jwt/payload/jwt-payload.port.d.ts +25 -3
- package/dist/domain/ports/repository/credential.repository.d.ts +55 -2
- package/dist/domain/ports/token/token-session.port.d.ts +2 -0
- package/dist/domain/props/entities/credential.props.d.ts +9 -1
- package/dist/domain/props/entities/user.props.d.ts +1 -0
- package/dist/domain/props/jwt/generate-access-token.props.d.ts +3 -2
- package/dist/domain/props/jwt/generate-refresh-token.props.d.ts +3 -2
- package/dist/domain/props/jwt/jwt-user.d.ts +11 -2
- package/dist/domain/services/helpers/assert-jwt-structure.helper.d.ts +1 -0
- package/dist/domain/services/helpers/assert-jwt-structure.helper.js +13 -0
- package/dist/domain/services/helpers/index.d.ts +7 -0
- package/dist/domain/services/helpers/index.js +23 -0
- package/dist/domain/services/helpers/optional-audience.helper.d.ts +14 -0
- package/dist/domain/services/helpers/optional-audience.helper.js +49 -0
- package/dist/domain/services/helpers/optional-non-empty-string.helper.d.ts +1 -0
- package/dist/domain/services/helpers/optional-non-empty-string.helper.js +9 -0
- package/dist/domain/services/helpers/optional-record.helper.d.ts +1 -0
- package/dist/domain/services/helpers/optional-record.helper.js +15 -0
- package/dist/domain/services/helpers/optional-roles.helper.d.ts +3 -0
- package/dist/domain/services/helpers/optional-roles.helper.js +32 -0
- package/dist/domain/services/helpers/require-finite-number.helper.d.ts +1 -0
- package/dist/domain/services/helpers/require-finite-number.helper.js +12 -0
- package/dist/domain/services/helpers/require-non-empty-string.helper.d.ts +1 -0
- package/dist/domain/services/helpers/require-non-empty-string.helper.js +12 -0
- package/dist/domain/services/index.d.ts +1 -0
- package/dist/domain/services/index.js +1 -0
- package/dist/domain/services/normalize-jwt-payload.service.d.ts +19 -0
- package/dist/domain/services/normalize-jwt-payload.service.js +58 -0
- package/dist/domain/types/access-snapshot.type.d.ts +15 -0
- package/dist/domain/types/access-snapshot.type.js +2 -0
- package/dist/domain/types/index.d.ts +1 -0
- package/dist/domain/types/index.js +2 -0
- package/dist/in-memory/in-memory-credential.repository.d.ts +66 -3
- package/dist/in-memory/in-memory-credential.repository.js +174 -46
- package/dist/index.d.ts +18 -2
- package/dist/index.js +24 -9
- package/dist/infrastructure/index.d.ts +3 -0
- package/dist/infrastructure/index.js +18 -0
- package/dist/infrastructure/security/bcrypt-password-hasher.js +0 -1
- package/dist/infrastructure/services/token-session.service.d.ts +163 -8
- package/dist/infrastructure/services/token-session.service.js +290 -37
- package/dist/infrastructure/types/auth-service-container.d.ts +21 -2
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/index.js +1 -0
- package/dist/shared/jwt-plugin/create-jwt-id.d.ts +6 -0
- package/dist/shared/jwt-plugin/create-jwt-id.js +30 -0
- package/dist/shared/jwt-plugin/index.d.ts +9 -0
- package/dist/shared/jwt-plugin/index.js +25 -0
- package/dist/shared/jwt-plugin/is-retryable-auth-code.d.ts +8 -0
- package/dist/shared/jwt-plugin/is-retryable-auth-code.js +15 -0
- package/dist/shared/jwt-plugin/normalize-clock-skew-seconds.d.ts +14 -0
- package/dist/shared/jwt-plugin/normalize-clock-skew-seconds.js +23 -0
- package/dist/shared/jwt-plugin/normalize-default-expires-in.d.ts +16 -0
- package/dist/shared/jwt-plugin/normalize-default-expires-in.js +36 -0
- package/dist/shared/jwt-plugin/read-custom-claims.d.ts +12 -0
- package/dist/shared/jwt-plugin/read-custom-claims.js +21 -0
- package/dist/shared/jwt-plugin/read-expires-in.d.ts +12 -0
- package/dist/shared/jwt-plugin/read-expires-in.js +20 -0
- package/dist/shared/jwt-plugin/read-session-id.d.ts +11 -0
- package/dist/shared/jwt-plugin/read-session-id.js +17 -0
- package/dist/shared/jwt-plugin/resolve-expires-in.d.ts +14 -0
- package/dist/shared/jwt-plugin/resolve-expires-in.js +31 -0
- package/dist/shared/jwt-plugin/to-date-from-unix-seconds.d.ts +7 -0
- package/dist/shared/jwt-plugin/to-date-from-unix-seconds.js +12 -0
- package/package.json +12 -11
- /package/dist/application/dtos/{type/user-role.type.js → request/change-password.request.js} +0 -0
- /package/dist/application/dtos/{type → types}/index.d.ts +0 -0
- /package/dist/application/dtos/{type → types}/index.js +0 -0
- /package/dist/application/dtos/{type → types}/user-role.type.d.ts +0 -0
package/README.es.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# @jmlq/auth 🧩
|
|
2
|
+
|
|
3
|
+
## 🎯 Objetivo
|
|
4
|
+
|
|
5
|
+
`@jmlq/auth` es un **core de autenticación** (no un framework) diseñado con **Clean Architecture** para centralizar:
|
|
6
|
+
|
|
7
|
+
- Casos de uso de autenticación (registro, login, refresh, logout)
|
|
8
|
+
- Flujos de seguridad de contraseña (remember/reset/change)
|
|
9
|
+
- Contratos (ports) para persistencia, hashing y servicios de tokens
|
|
10
|
+
|
|
11
|
+
El paquete **no expone endpoints HTTP** y está pensado para integrarse desde un host (por ejemplo Express) mediante adapters.
|
|
12
|
+
|
|
13
|
+
## ⭐ Importancia
|
|
14
|
+
|
|
15
|
+
- Evita “auth ad‑hoc” por cada API: el **core concentra reglas y casos de uso**.
|
|
16
|
+
- Fuerza separación de responsabilidades: dominio fuerte + infraestructura intercambiable.
|
|
17
|
+
- Habilita sesiones multi‑dispositivo (vía `sessionId/sid`) y rotación/revocación (refresh).
|
|
18
|
+
|
|
19
|
+
## 🏗️ Arquitectura (visión rápida)
|
|
20
|
+
|
|
21
|
+
- Punto de entrada: `AuthServiceFactory.create(...)` construye el contenedor de Auth y evita wiring repetido.
|
|
22
|
+
- La sesión se orquesta con `TokenSessionService` (rotación/revocación).
|
|
23
|
+
- El hashing de contraseñas se implementa con `BcryptPasswordHasher`.
|
|
24
|
+
|
|
25
|
+
➡️ Ver detalle en: [architecture.md](./docs/es/architecture.md)
|
|
26
|
+
|
|
27
|
+
## 🔧 Implementación
|
|
28
|
+
|
|
29
|
+
### 5.1 Instalación
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm i @jmlq/auth
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 5.2 Dependencias
|
|
36
|
+
|
|
37
|
+
Dependencia directa del paquete:
|
|
38
|
+
|
|
39
|
+
- `bcryptjs`
|
|
40
|
+
|
|
41
|
+
(El host aporta el resto: repositorios, tokens, transporte HTTP, etc.)
|
|
42
|
+
|
|
43
|
+
### 5.3 Quickstart (implementación rápida)
|
|
44
|
+
|
|
45
|
+
En un host, la construcción del contenedor se realiza en el composition root (ej. infrastructure/bootstrap):
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
import { AuthServiceFactory } from "@jmlq/auth";
|
|
49
|
+
|
|
50
|
+
const auth = AuthServiceFactory.create(
|
|
51
|
+
userRepository,
|
|
52
|
+
credentialRepository,
|
|
53
|
+
tokenService,
|
|
54
|
+
passwordResetToken,
|
|
55
|
+
emailVerificationToken,
|
|
56
|
+
{
|
|
57
|
+
bcryptSaltRounds: 10,
|
|
58
|
+
accessTokenTtl: "15m",
|
|
59
|
+
refreshTokenTtl: "7d",
|
|
60
|
+
// opcional:
|
|
61
|
+
// passwordResetTokenTtl: "30m",
|
|
62
|
+
// emailVerificationTokenTtl: "1d",
|
|
63
|
+
},
|
|
64
|
+
);
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 5.4 Variables de entorno (.env) 📦
|
|
68
|
+
|
|
69
|
+
`@jmlq/auth` no usa `.env` internamente; el host (API) define su configuración y luego construye adapters.
|
|
70
|
+
|
|
71
|
+
En el `host` se sugiere declarar variables relacionadas con cookies/headers y generación de links empleados en las funcionalidades de registro y autentificación, por ejemplo:
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
process.env.AUTH_COOKIE_NAME; // => envs.auth.COOKIE_NAME
|
|
75
|
+
process.env.AUTH_FRONTEND_BASE_URL; // => envs.auth.FRONTEND_BASE_URL
|
|
76
|
+
process.env.AUTH_FRONTEND_RESET_PASSWORD_PATH; // => envs.auth.FRONTEND_RESET_PASSWORD_PATH
|
|
77
|
+
|
|
78
|
+
process.env.AUTH_LINK_API_BASE_URL; // => envs.auth.LINK_API_BASE_URL
|
|
79
|
+
process.env.AUTH_LINK_API_VERIFY_EMAIL_PATH; // => envs.auth.LINK_API_VERIFY_EMAIL_PATH
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
> Nota: los nombres exactos de las variables `.env` dependen de tu módulo `envs` (host).
|
|
83
|
+
|
|
84
|
+
### 5.5 Helpers y funcionalidades clave
|
|
85
|
+
|
|
86
|
+
#### ✅ Validaciones HTTP en el host (Express)
|
|
87
|
+
|
|
88
|
+
En `host` se pueden aplicar validaciones explícitas antes de delegar al core. Por ejemplo:
|
|
89
|
+
|
|
90
|
+
- **change-password**: garantiza que `newPassword` sea diferente a `currentPassword` y que coincida con `confirmNewPassword`.
|
|
91
|
+
- **refresh**: obtiene refresh token desde cookie y como fallback desde header.
|
|
92
|
+
- **logout**: es opcional; si no hay refresh token, se limpia cookie y se responde ok.
|
|
93
|
+
|
|
94
|
+
#### ✅ Headers estándar (fallback de refresh token)
|
|
95
|
+
|
|
96
|
+
En `host` el header para refresh puede usar el nombre derivado de `envs.auth.COOKIE_NAME`:
|
|
97
|
+
|
|
98
|
+
- `X-${envs.auth.COOKIE_NAME}`
|
|
99
|
+
|
|
100
|
+
#### ✅ Generación de links de Password Reset y Verify Email
|
|
101
|
+
|
|
102
|
+
El `host` genera links combinando `base + path` y parametriza el token con `URL.searchParams`:
|
|
103
|
+
|
|
104
|
+
- Reset password: `{FRONTEND_BASE_URL}{FRONTEND_RESET_PASSWORD_PATH}?token=...`
|
|
105
|
+
- Verify email: `{LINK_API_BASE_URL}{LINK_API_VERIFY_EMAIL_PATH}?token=...`
|
|
106
|
+
|
|
107
|
+
## ✅ Checklist (pasos rápidos)
|
|
108
|
+
|
|
109
|
+
- [Instalar](#51-instalación)
|
|
110
|
+
- [Implementar ports en tu host](./docs/es/configuration.md#ports-que-tu-host-debe-implementar)
|
|
111
|
+
- [Construir el contenedor con AuthServiceFactory](./docs/es/configuration.md#construcción-del-contenedor-authservicefactorycreate)
|
|
112
|
+
- [Integrar con Express](./docs/es/integration-express.md)
|
|
113
|
+
- [Configurar headers/cookies y links](./docs/es/integration-express.md#refresh-token-cookie--header-fallback)
|
|
114
|
+
- [Troubleshooting](./docs/es/troubleshooting.md)
|
|
115
|
+
|
|
116
|
+
## 📌 Menú
|
|
117
|
+
|
|
118
|
+
- [Arquitectura](./docs/architecture.md)
|
|
119
|
+
- [Configuración](./docs/es/configuration.md)
|
|
120
|
+
- [Integración Express](./docs/es/integration-express.md)
|
|
121
|
+
- [Troubleshooting](./docs/es/troubleshooting.md)
|
|
122
|
+
|
|
123
|
+
## 🔗 Referencias
|
|
124
|
+
|
|
125
|
+
- [`@jmlq/auth-plugin-jose`](../auth-plugin-jose/README.md)
|
|
126
|
+
|
|
127
|
+
- [`@jmlq/auth`](https://github.com/MLahuasi/jmlq-auth#readme)
|
|
128
|
+
- Plugins relacionados del ecosistema:
|
|
129
|
+
- [`@jmlq/auth-plugin-jose`](https://github.com/MLahuasi/jmlq-auth-plugin-jose#readme)
|
|
130
|
+
|
|
131
|
+
## ⬅️ 🌐 Ecosistema
|
|
132
|
+
|
|
133
|
+
- [`@jmlq`](https://github.com/MLahuasi/jmlq-ecosystem#readme)
|
package/README.md
CHANGED
|
@@ -1,259 +1,133 @@
|
|
|
1
|
-
# @jmlq/auth
|
|
1
|
+
# @jmlq/auth 🧩
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## 🎯 Objective
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
Proporciona **casos de uso, servicios y contratos** listos para integrarse en APIs reales.
|
|
5
|
+
`@jmlq/auth` is an **authentication core** (not a framework) designed with **Clean Architecture** to centralize:
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
- Authentication use cases (register, login, refresh, logout)
|
|
8
|
+
- Password security flows (remember/reset/change)
|
|
9
|
+
- Contracts (ports) for persistence, hashing, and token services
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
This package **does not expose HTTP endpoints** and is intended to be integrated from a host (e.g., Express) via adapters.
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
npm install @jmlq/auth
|
|
14
|
-
```
|
|
13
|
+
## ⭐ Importance
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
- Avoids “ad-hoc auth” per API: the **core centralizes rules and use cases**
|
|
16
|
+
- Enforces separation of responsibilities: strong domain + interchangeable infrastructure
|
|
17
|
+
- Enables multi-device sessions (via `sessionId/sid`) and rotation/revocation (refresh)
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
## 🏗️ Architecture (quick view)
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
- Entry point: `AuthServiceFactory.create(...)` builds the Auth container and avoids repetitive wiring
|
|
22
|
+
- Session orchestration via `TokenSessionService` (rotation/revocation)
|
|
23
|
+
- Password hashing implemented with `BcryptPasswordHasher`
|
|
21
24
|
|
|
22
|
-
|
|
25
|
+
➡️ See details in: [architecture.md](./docs/en/architecture.md)
|
|
23
26
|
|
|
24
|
-
|
|
25
|
-
- **[📚 Ejemplos de Código](./examples/)** - Casos de uso reales y implementaciones
|
|
27
|
+
## 🔧 Implementation
|
|
26
28
|
|
|
27
|
-
|
|
28
|
-
- Separación estricta:
|
|
29
|
+
### 5.1 Installation
|
|
29
30
|
|
|
30
|
-
```
|
|
31
|
-
|
|
31
|
+
```bash
|
|
32
|
+
npm i @jmlq/auth
|
|
32
33
|
```
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
### 5.2 Dependencies
|
|
35
36
|
|
|
36
|
-
|
|
37
|
+
Direct dependency of the package:
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
- ✅ Clean Architecture real
|
|
41
|
-
- ✅ Framework agnostic
|
|
42
|
-
- ✅ Access Token + Refresh Token
|
|
43
|
-
- ✅ Rotación de refresh tokens
|
|
44
|
-
- ✅ Logout por revocación
|
|
45
|
-
- ✅ Autorización por Roles y Permissions
|
|
46
|
-
- ✅ Password hashing con bcrypt
|
|
47
|
-
- ✅ Repositorios in-memory para testing
|
|
48
|
-
- ✅ TypeScript first
|
|
49
|
-
|
|
50
|
-
---
|
|
39
|
+
- `bcryptjs`
|
|
51
40
|
|
|
52
|
-
|
|
41
|
+
(The host provides the rest: repositories, tokens, HTTP transport, etc.)
|
|
53
42
|
|
|
54
|
-
###
|
|
43
|
+
### 5.3 Quickstart (fast implementation)
|
|
55
44
|
|
|
56
|
-
|
|
45
|
+
In a host, the container is built in the composition root (e.g., infrastructure/bootstrap):
|
|
57
46
|
|
|
58
47
|
```ts
|
|
59
|
-
import {
|
|
60
|
-
AuthServiceFactory,
|
|
61
|
-
InMemoryUserRepository,
|
|
62
|
-
InMemoryCredentialRepository,
|
|
63
|
-
} from "@jmlq/auth";
|
|
64
|
-
import { JoseTokenService } from "@jmlq/auth/infrastructure";
|
|
48
|
+
import { AuthServiceFactory } from "@jmlq/auth";
|
|
65
49
|
|
|
66
50
|
const auth = AuthServiceFactory.create(
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
51
|
+
userRepository,
|
|
52
|
+
credentialRepository,
|
|
53
|
+
tokenService,
|
|
54
|
+
passwordResetToken,
|
|
55
|
+
emailVerificationToken,
|
|
56
|
+
{
|
|
57
|
+
bcryptSaltRounds: 10,
|
|
58
|
+
accessTokenTtl: "15m",
|
|
59
|
+
refreshTokenTtl: "7d",
|
|
60
|
+
// optional:
|
|
61
|
+
// passwordResetTokenTtl: "30m",
|
|
62
|
+
// emailVerificationTokenTtl: "1d",
|
|
63
|
+
},
|
|
79
64
|
);
|
|
80
65
|
```
|
|
81
66
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
- Casos de uso
|
|
85
|
-
- TokenSessionService
|
|
86
|
-
- TokenService
|
|
67
|
+
### 5.4 Environment variables (.env) 📦
|
|
87
68
|
|
|
88
|
-
|
|
69
|
+
`@jmlq/auth` does not use `.env` internally; the host (API) defines its configuration and then builds adapters.
|
|
89
70
|
|
|
90
|
-
|
|
71
|
+
In the `host`, it is recommended to define variables related to cookies/headers and link generation used in registration and authentication flows, for example:
|
|
91
72
|
|
|
92
73
|
```ts
|
|
93
|
-
auth.
|
|
94
|
-
auth.
|
|
95
|
-
auth.
|
|
96
|
-
auth.logoutUseCase;
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
---
|
|
100
|
-
|
|
101
|
-
## 🔐 Ejemplo de Integración (Express)
|
|
74
|
+
process.env.AUTH_COOKIE_NAME; // => envs.auth.COOKIE_NAME
|
|
75
|
+
process.env.AUTH_FRONTEND_BASE_URL; // => envs.auth.FRONTEND_BASE_URL
|
|
76
|
+
process.env.AUTH_FRONTEND_RESET_PASSWORD_PATH; // => envs.auth.FRONTEND_RESET_PASSWORD_PATH
|
|
102
77
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
```ts
|
|
106
|
-
router.post("/auth/register", async (req, res) => {
|
|
107
|
-
try {
|
|
108
|
-
const result = await auth.registerUserUseCase.execute(req.body);
|
|
109
|
-
return res.status(201).json(result);
|
|
110
|
-
} catch (err) {
|
|
111
|
-
return res.status(400).json({ error: err.message });
|
|
112
|
-
}
|
|
113
|
-
});
|
|
78
|
+
process.env.AUTH_LINK_API_BASE_URL; // => envs.auth.LINK_API_BASE_URL
|
|
79
|
+
process.env.AUTH_LINK_API_VERIFY_EMAIL_PATH; // => envs.auth.LINK_API_VERIFY_EMAIL_PATH
|
|
114
80
|
```
|
|
115
81
|
|
|
116
|
-
|
|
82
|
+
> Note: exact `.env` variable names depend on your host `envs` module.
|
|
117
83
|
|
|
118
|
-
###
|
|
84
|
+
### 5.5 Helpers and key features
|
|
119
85
|
|
|
120
|
-
|
|
121
|
-
router.post("/auth/login", async (req, res) => {
|
|
122
|
-
const result = await auth.loginWithPasswordUseCase.execute(req.body);
|
|
86
|
+
#### ✅ HTTP validations in the host (Express)
|
|
123
87
|
|
|
124
|
-
|
|
125
|
-
httpOnly: true,
|
|
126
|
-
sameSite: "lax",
|
|
127
|
-
path: "/auth/refresh",
|
|
128
|
-
});
|
|
88
|
+
In the `host`, explicit validations can be applied before delegating to the core. For example:
|
|
129
89
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
90
|
+
- **change-password**: ensures `newPassword` differs from `currentPassword` and matches `confirmNewPassword`
|
|
91
|
+
- **refresh**: retrieves refresh token from cookie and falls back to header
|
|
92
|
+
- **logout**: optional; if no refresh token, clear cookie and respond ok
|
|
133
93
|
|
|
134
|
-
|
|
94
|
+
#### ✅ Standard headers (refresh token fallback)
|
|
135
95
|
|
|
136
|
-
|
|
96
|
+
In the `host`, the refresh header can use the name derived from `envs.auth.COOKIE_NAME`:
|
|
137
97
|
|
|
138
|
-
|
|
139
|
-
router.post("/auth/refresh", async (req, res) => {
|
|
140
|
-
try {
|
|
141
|
-
const result = await auth.refreshTokenUseCase.execute({
|
|
142
|
-
refreshToken: req.cookies.refreshToken,
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
res.cookie("refreshToken", result.refreshToken, {
|
|
146
|
-
httpOnly: true,
|
|
147
|
-
sameSite: "lax",
|
|
148
|
-
path: "/auth/refresh",
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
return res.json({ accessToken: result.accessToken });
|
|
152
|
-
} catch {
|
|
153
|
-
return res.status(401).json({ error: "INVALID_REFRESH_TOKEN" });
|
|
154
|
-
}
|
|
155
|
-
});
|
|
156
|
-
```
|
|
98
|
+
- `X-${envs.auth.COOKIE_NAME}`
|
|
157
99
|
|
|
158
|
-
|
|
100
|
+
#### ✅ Password Reset and Verify Email link generation
|
|
159
101
|
|
|
160
|
-
|
|
102
|
+
The `host` generates links by combining `base + path` and passing the token via `URL.searchParams`:
|
|
161
103
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
await auth.logoutUseCase.execute({
|
|
165
|
-
refreshToken: req.cookies.refreshToken,
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
res.clearCookie("refreshToken", { path: "/auth/refresh" });
|
|
169
|
-
return res.json({ ok: true });
|
|
170
|
-
});
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
---
|
|
104
|
+
- Reset password: `{FRONTEND_BASE_URL}{FRONTEND_RESET_PASSWORD_PATH}?token=...`
|
|
105
|
+
- Verify email: `{LINK_API_BASE_URL}{LINK_API_VERIFY_EMAIL_PATH}?token=...`
|
|
174
106
|
|
|
175
|
-
##
|
|
107
|
+
## ✅ Checklist (quick steps)
|
|
176
108
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
if (!token) {
|
|
184
|
-
return res.status(401).json({ error: "UNAUTHORIZED" });
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
try {
|
|
188
|
-
req.auth = await tokenService.verifyAccessToken(token);
|
|
189
|
-
next();
|
|
190
|
-
} catch {
|
|
191
|
-
return res.status(401).json({ error: "INVALID_TOKEN" });
|
|
192
|
-
}
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
```
|
|
109
|
+
- [Install](#51-installation)
|
|
110
|
+
- [Implement ports in your host](./docs/en/configuration.md#ports-que-tu-host-debe-implementar)
|
|
111
|
+
- [Build container with AuthServiceFactory](./docs/en/configuration.md#construcción-del-contenedor-authservicefactorycreate)
|
|
112
|
+
- [Integrate with Express](./docs/en/integration-express.md)
|
|
113
|
+
- [Configure headers/cookies and links](./docs/en/integration-express.md#refresh-token-cookie--header-fallback)
|
|
114
|
+
- [Troubleshooting](./docs/en/troubleshooting.md)
|
|
196
115
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
## 🔒 Middleware de Autorización por Permission
|
|
200
|
-
|
|
201
|
-
```ts
|
|
202
|
-
import { Permission, Id } from "@jmlq/auth";
|
|
203
|
-
|
|
204
|
-
export function requirePermission(userRepository, permission: string) {
|
|
205
|
-
return async (req, res, next) => {
|
|
206
|
-
const userId = req.auth?.sub;
|
|
207
|
-
if (!userId) {
|
|
208
|
-
return res.status(401).json({ error: "UNAUTHENTICATED" });
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
const user = await userRepository.findById(new Id(userId));
|
|
212
|
-
const allowed = user.roles.some((r) =>
|
|
213
|
-
r.hasPermission(new Permission(permission))
|
|
214
|
-
);
|
|
215
|
-
|
|
216
|
-
if (!allowed) {
|
|
217
|
-
return res.status(403).json({ error: "FORBIDDEN" });
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
next();
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
```
|
|
116
|
+
## 📌 Menu
|
|
224
117
|
|
|
225
|
-
|
|
118
|
+
- [Architecture](./docs/architecture.md)
|
|
119
|
+
- [Configuration](./docs/en/configuration.md)
|
|
120
|
+
- [Express Integration](./docs/en/integration-express.md)
|
|
121
|
+
- [Troubleshooting](./docs/en/troubleshooting.md)
|
|
226
122
|
|
|
227
|
-
##
|
|
123
|
+
## 🔗 References
|
|
228
124
|
|
|
229
|
-
|
|
230
|
-
Register → Login → Access → Refresh → Logout → Authorization
|
|
231
|
-
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
- **Register**: crea el agregado User
|
|
235
|
-
- **Login**: valida credenciales y crea sesión
|
|
236
|
-
- **Access**: access token por request
|
|
237
|
-
- **Refresh**: rotación de refresh token
|
|
238
|
-
- **Logout**: revocación de sesión
|
|
239
|
-
- **Authorization**: permisos evaluados en dominio
|
|
240
|
-
|
|
241
|
-
---
|
|
242
|
-
|
|
243
|
-
## 🔧 Variables de Entorno Recomendadas
|
|
244
|
-
|
|
245
|
-
```bash
|
|
246
|
-
JWT_ACCESS_SECRET=super-secret
|
|
247
|
-
JWT_REFRESH_SECRET=super-refresh-secret
|
|
248
|
-
JWT_ACCESS_TTL=15m
|
|
249
|
-
JWT_REFRESH_TTL=7d
|
|
250
|
-
JWT_ISSUER=my-api
|
|
251
|
-
JWT_AUDIENCE=my-api-clients
|
|
252
|
-
BCRYPT_SALT_ROUNDS=10
|
|
253
|
-
```
|
|
125
|
+
- [`@jmlq/auth-plugin-jose`](../auth-plugin-jose/README.md)
|
|
254
126
|
|
|
255
|
-
|
|
127
|
+
- [`@jmlq/auth`](https://github.com/MLahuasi/jmlq-auth#readme)
|
|
128
|
+
- Related ecosystem plugins:
|
|
129
|
+
- [`@jmlq/auth-plugin-jose`](https://github.com/MLahuasi/jmlq-auth-plugin-jose#readme)
|
|
256
130
|
|
|
257
|
-
##
|
|
131
|
+
## ⬅️ 🌐 Ecosystem
|
|
258
132
|
|
|
259
|
-
|
|
133
|
+
- [`@jmlq`](https://github.com/MLahuasi/jmlq-ecosystem#readme)
|
|
@@ -16,4 +16,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./request"), exports);
|
|
18
18
|
__exportStar(require("./response"), exports);
|
|
19
|
-
__exportStar(require("./
|
|
19
|
+
__exportStar(require("./types"), exports);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cambiar password desde formulario
|
|
3
|
+
*/
|
|
4
|
+
export interface ChangePasswordRequest {
|
|
5
|
+
userId: string;
|
|
6
|
+
sessionId: string;
|
|
7
|
+
currentPassword: string;
|
|
8
|
+
newPassword: string;
|
|
9
|
+
confirmNewPassword: string;
|
|
10
|
+
/**
|
|
11
|
+
* Si es true, revoca todas las sesiones del usuario.
|
|
12
|
+
* Si es false, revoca solo la sesión actual (sessionId).
|
|
13
|
+
*/
|
|
14
|
+
logoutAllDevices: boolean;
|
|
15
|
+
}
|
|
@@ -2,3 +2,8 @@ export * from "./login.request";
|
|
|
2
2
|
export * from "./logout.request";
|
|
3
3
|
export * from "./refresh-token.request";
|
|
4
4
|
export * from "./register-user.request";
|
|
5
|
+
export * from "./request-password-reset.request";
|
|
6
|
+
export * from "./reset-password.request";
|
|
7
|
+
export * from "./change-password.request";
|
|
8
|
+
export * from "./verify-email.request";
|
|
9
|
+
export * from "./me.request";
|
|
@@ -18,3 +18,8 @@ __exportStar(require("./login.request"), exports);
|
|
|
18
18
|
__exportStar(require("./logout.request"), exports);
|
|
19
19
|
__exportStar(require("./refresh-token.request"), exports);
|
|
20
20
|
__exportStar(require("./register-user.request"), exports);
|
|
21
|
+
__exportStar(require("./request-password-reset.request"), exports);
|
|
22
|
+
__exportStar(require("./reset-password.request"), exports);
|
|
23
|
+
__exportStar(require("./change-password.request"), exports);
|
|
24
|
+
__exportStar(require("./verify-email.request"), exports);
|
|
25
|
+
__exportStar(require("./me.request"), exports);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Actualizar password usando un token una vez que se envía link a email
|
|
3
|
+
*/
|
|
4
|
+
export interface ResetPasswordRequest {
|
|
5
|
+
resetToken: string;
|
|
6
|
+
newPassword: string;
|
|
7
|
+
confirmNewPassword: string;
|
|
8
|
+
/**
|
|
9
|
+
* Política de sesiones post-reset:
|
|
10
|
+
* - true: logout global (recomendado)
|
|
11
|
+
* - false: mantener sesiones (si lo permites)
|
|
12
|
+
*/
|
|
13
|
+
logoutAllDevices?: boolean;
|
|
14
|
+
}
|
|
@@ -2,3 +2,8 @@ export * from "./login.response";
|
|
|
2
2
|
export * from "./logout.response";
|
|
3
3
|
export * from "./refresh-token.response";
|
|
4
4
|
export * from "./register-user.response";
|
|
5
|
+
export * from "./reset-password.response";
|
|
6
|
+
export * from "./request-password-reset.response";
|
|
7
|
+
export * from "./change-password.response";
|
|
8
|
+
export * from "./verify-email.response";
|
|
9
|
+
export * from "./me.response";
|
|
@@ -18,3 +18,8 @@ __exportStar(require("./login.response"), exports);
|
|
|
18
18
|
__exportStar(require("./logout.response"), exports);
|
|
19
19
|
__exportStar(require("./refresh-token.response"), exports);
|
|
20
20
|
__exportStar(require("./register-user.response"), exports);
|
|
21
|
+
__exportStar(require("./reset-password.response"), exports);
|
|
22
|
+
__exportStar(require("./request-password-reset.response"), exports);
|
|
23
|
+
__exportStar(require("./change-password.response"), exports);
|
|
24
|
+
__exportStar(require("./verify-email.response"), exports);
|
|
25
|
+
__exportStar(require("./me.response"), exports);
|