@jmlq/auth-plugin-jose 0.0.1-alpha.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.md +228 -0
- package/dist/application/factories/create-jose-token-service.d.ts +28 -0
- package/dist/application/factories/create-jose-token-service.js +76 -0
- package/dist/application/factories/index.d.ts +1 -0
- package/dist/application/factories/index.js +17 -0
- package/dist/application/factories/internal/assert.util.d.ts +9 -0
- package/dist/application/factories/internal/assert.util.js +16 -0
- package/dist/application/factories/internal/clock-skew-normalizer.util.d.ts +14 -0
- package/dist/application/factories/internal/clock-skew-normalizer.util.js +24 -0
- package/dist/application/factories/internal/expires-in.util.d.ts +21 -0
- package/dist/application/factories/internal/expires-in.util.js +31 -0
- package/dist/application/factories/internal/index.d.ts +5 -0
- package/dist/application/factories/internal/index.js +21 -0
- package/dist/application/factories/internal/key-material.validator.d.ts +15 -0
- package/dist/application/factories/internal/key-material.validator.js +26 -0
- package/dist/application/factories/internal/string-normalizers.util.d.ts +18 -0
- package/dist/application/factories/internal/string-normalizers.util.js +31 -0
- package/dist/application/types/expires-in.types.d.ts +33 -0
- package/dist/application/types/expires-in.types.js +3 -0
- package/dist/application/types/index.d.ts +2 -0
- package/dist/application/types/index.js +18 -0
- package/dist/application/types/jose-token-service.options.d.ts +81 -0
- package/dist/application/types/jose-token-service.options.js +9 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +9 -0
- package/dist/infrastructure/mappers/index.d.ts +1 -0
- package/dist/infrastructure/mappers/index.js +17 -0
- package/dist/infrastructure/mappers/jose-error.mapper.d.ts +35 -0
- package/dist/infrastructure/mappers/jose-error.mapper.js +219 -0
- package/dist/infrastructure/mappers/types/index.d.ts +4 -0
- package/dist/infrastructure/mappers/types/index.js +20 -0
- package/dist/infrastructure/mappers/types/jose-error-context.type.d.ts +32 -0
- package/dist/infrastructure/mappers/types/jose-error-context.type.js +3 -0
- package/dist/infrastructure/mappers/types/mapped-auth-error.type.d.ts +24 -0
- package/dist/infrastructure/mappers/types/mapped-auth-error.type.js +3 -0
- package/dist/infrastructure/mappers/types/token-kind.type.d.ts +7 -0
- package/dist/infrastructure/mappers/types/token-kind.type.js +3 -0
- package/dist/infrastructure/mappers/types/token-operation.type.d.ts +7 -0
- package/dist/infrastructure/mappers/types/token-operation.type.js +3 -0
- package/dist/infrastructure/services/index.d.ts +1 -0
- package/dist/infrastructure/services/index.js +17 -0
- package/dist/infrastructure/services/internal/expires-in.util.d.ts +21 -0
- package/dist/infrastructure/services/internal/expires-in.util.js +35 -0
- package/dist/infrastructure/services/internal/index.d.ts +7 -0
- package/dist/infrastructure/services/internal/index.js +23 -0
- package/dist/infrastructure/services/internal/jose-context.util.d.ts +35 -0
- package/dist/infrastructure/services/internal/jose-context.util.js +51 -0
- package/dist/infrastructure/services/internal/jose-error.util.d.ts +16 -0
- package/dist/infrastructure/services/internal/jose-error.util.js +27 -0
- package/dist/infrastructure/services/internal/jose-keys.normalizer.d.ts +25 -0
- package/dist/infrastructure/services/internal/jose-keys.normalizer.js +35 -0
- package/dist/infrastructure/services/internal/jti.util.d.ts +8 -0
- package/dist/infrastructure/services/internal/jti.util.js +25 -0
- package/dist/infrastructure/services/internal/jwt-expiration-reader.d.ts +9 -0
- package/dist/infrastructure/services/internal/jwt-expiration-reader.js +23 -0
- package/dist/infrastructure/services/internal/jwt-payload.normalizer.d.ts +11 -0
- package/dist/infrastructure/services/internal/jwt-payload.normalizer.js +56 -0
- package/dist/infrastructure/services/jose-token.service.d.ts +192 -0
- package/dist/infrastructure/services/jose-token.service.js +309 -0
- package/dist/infrastructure/services/types/create-auth-error-fn.type.d.ts +27 -0
- package/dist/infrastructure/services/types/create-auth-error-fn.type.js +2 -0
- package/dist/infrastructure/services/types/index.d.ts +1 -0
- package/dist/infrastructure/services/types/index.js +17 -0
- package/package.json +48 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Opciones públicas del adapter jose que implementa ITokenServicePort.
|
|
3
|
+
*
|
|
4
|
+
* Objetivos:
|
|
5
|
+
* - Config explícita (sin magia).
|
|
6
|
+
* - Permitir configuración común + overrides por tipo (access/refresh).
|
|
7
|
+
* - Tipar keys según algoritmo (HS vs RSA/EC).
|
|
8
|
+
*
|
|
9
|
+
* NOTA: la validación de estas options se hace en la factory (Etapa 5),
|
|
10
|
+
* aquí solo se definen tipos.
|
|
11
|
+
*/
|
|
12
|
+
export type JoseJwtAlg = "HS256" | "RS256" | "ES256";
|
|
13
|
+
/**
|
|
14
|
+
* Para HS256 se usa un secreto simétrico.
|
|
15
|
+
*/
|
|
16
|
+
export interface JoseHmacKeyMaterial {
|
|
17
|
+
alg: "HS256";
|
|
18
|
+
secret: string | Uint8Array;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Para RS256 / ES256 se usa par de claves asimétricas.
|
|
22
|
+
* Se acepta string PEM/JWK serializado o cualquier representación ya resuelta por la app.
|
|
23
|
+
*
|
|
24
|
+
* Nota: el tipo exacto de KeyLike/JWK depende de jose. Para mantener
|
|
25
|
+
* desacoplado el dominio del plugin, aquí se usa `unknown` como "KeyInput".
|
|
26
|
+
* La factory/adapters se encargan de normalizar.
|
|
27
|
+
*/
|
|
28
|
+
export interface JoseAsymmetricKeyMaterial {
|
|
29
|
+
alg: "RS256" | "ES256";
|
|
30
|
+
privateKey: unknown;
|
|
31
|
+
publicKey: unknown;
|
|
32
|
+
}
|
|
33
|
+
export type JoseKeyMaterial = JoseHmacKeyMaterial | JoseAsymmetricKeyMaterial;
|
|
34
|
+
export interface JoseStandardClaimsValidationOptions {
|
|
35
|
+
/**
|
|
36
|
+
* Si se define, se exige coincidencia exacta con el claim `iss`.
|
|
37
|
+
* Si no se define, no se valida issuer.
|
|
38
|
+
*/
|
|
39
|
+
issuer?: string;
|
|
40
|
+
/**
|
|
41
|
+
* Si se define, se exige coincidencia exacta con el claim `aud`.
|
|
42
|
+
* Si no se define, no se valida audience.
|
|
43
|
+
*/
|
|
44
|
+
audience?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Tolerancia de reloj en segundos para validación temporal (exp/nbf/iat según aplique).
|
|
47
|
+
* Default recomendado en factory: 0 o 5.
|
|
48
|
+
*/
|
|
49
|
+
clockSkewSeconds?: number;
|
|
50
|
+
}
|
|
51
|
+
export interface JoseTokenTypeOptions extends JoseStandardClaimsValidationOptions {
|
|
52
|
+
/**
|
|
53
|
+
* Algoritmo + material de clave.
|
|
54
|
+
*/
|
|
55
|
+
keys: JoseKeyMaterial;
|
|
56
|
+
/**
|
|
57
|
+
* ExpiresIn por defecto si en props.expiresIn no se envía.
|
|
58
|
+
* Formato: string estilo "15m", "7d", "3600s".
|
|
59
|
+
* La interpretación exacta se define en el parser del plugin (Etapa 2/4).
|
|
60
|
+
*/
|
|
61
|
+
defaultExpiresIn?: string;
|
|
62
|
+
}
|
|
63
|
+
export interface JoseTokenServiceOptions extends JoseStandardClaimsValidationOptions {
|
|
64
|
+
/**
|
|
65
|
+
* Configuración específica para access tokens.
|
|
66
|
+
*/
|
|
67
|
+
access: JoseTokenTypeOptions;
|
|
68
|
+
/**
|
|
69
|
+
* Configuración específica para refresh tokens.
|
|
70
|
+
*/
|
|
71
|
+
refresh: JoseTokenTypeOptions;
|
|
72
|
+
/**
|
|
73
|
+
* Política para getTokenExpiration:
|
|
74
|
+
* - "verify-first": verifica firma antes de leer exp (Opción A).
|
|
75
|
+
*
|
|
76
|
+
* Este proyecto acordó Opción A.
|
|
77
|
+
*/
|
|
78
|
+
getExpirationPolicy?: "verify-first";
|
|
79
|
+
}
|
|
80
|
+
export declare const DEFAULT_CLOCK_SKEW_SECONDS: 0;
|
|
81
|
+
export declare const DEFAULT_GET_EXPIRATION_POLICY: "verify-first";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// src/application/types/jose-token-service.options.ts
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.DEFAULT_GET_EXPIRATION_POLICY = exports.DEFAULT_CLOCK_SKEW_SECONDS = void 0;
|
|
5
|
+
// -----------------------------------------------------------------------------
|
|
6
|
+
// Defaults recomendados (constantes de referencia; la factory aplica defaults)
|
|
7
|
+
// -----------------------------------------------------------------------------
|
|
8
|
+
exports.DEFAULT_CLOCK_SKEW_SECONDS = 0;
|
|
9
|
+
exports.DEFAULT_GET_EXPIRATION_POLICY = "verify-first";
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { createJoseTokenService } from "./application/factories";
|
|
2
|
+
export type { JoseJwtAlg, JoseKeyMaterial, JoseHmacKeyMaterial, JoseAsymmetricKeyMaterial, JoseStandardClaimsValidationOptions, JoseTokenTypeOptions, JoseTokenServiceOptions, } from "./application/types";
|
|
3
|
+
export type { ExpiresInUnit, ExpiresInString, ExpiresIn, } from "./application/types";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// src/index.ts
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.createJoseTokenService = void 0;
|
|
5
|
+
// -----------------------------------------------------------------------------
|
|
6
|
+
// Public factory
|
|
7
|
+
// -----------------------------------------------------------------------------
|
|
8
|
+
var factories_1 = require("./application/factories");
|
|
9
|
+
Object.defineProperty(exports, "createJoseTokenService", { enumerable: true, get: function () { return factories_1.createJoseTokenService; } });
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./jose-error.mapper";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./jose-error.mapper"), exports);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { JoseErrorContext, MappedAuthError } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Mapea un error técnico a un código estable del core.
|
|
4
|
+
*
|
|
5
|
+
* La estrategia es conservadora:
|
|
6
|
+
* - Primero intenta mapear por `err.name` (más estable en `jose`).
|
|
7
|
+
* - Luego usa heurísticas por `message` como fallback.
|
|
8
|
+
* - Finalmente devuelve JWT_ERROR (catch-all) si no calza con nada.
|
|
9
|
+
*
|
|
10
|
+
* @param err Error original (normalmente de `jose`, pero puede ser cualquiera).
|
|
11
|
+
* @param ctx Contexto técnico mínimo para enriquecer meta y mejorar clasificación.
|
|
12
|
+
* @returns MappedAuthError con código del core + meta segura + causa opcional.
|
|
13
|
+
*/
|
|
14
|
+
export declare function mapJoseErrorToAuthError(err: unknown, ctx: JoseErrorContext): MappedAuthError;
|
|
15
|
+
/**
|
|
16
|
+
* Convierte un error técnico a un Error del core (AuthDomainError u otro),
|
|
17
|
+
* sin acoplar el plugin a una implementación concreta.
|
|
18
|
+
*
|
|
19
|
+
* Esta función es útil porque:
|
|
20
|
+
* - El mapper produce un objeto “agnóstico” (MappedAuthError).
|
|
21
|
+
* - La creación del Error real depende del core o de la app (inyección).
|
|
22
|
+
*
|
|
23
|
+
* @template TAuthError Tipo de error final que devuelve el core.
|
|
24
|
+
*
|
|
25
|
+
* @param createAuthError Función provista por el core/app para crear el error final.
|
|
26
|
+
* @param err Error original que proviene de `jose` u otra fuente.
|
|
27
|
+
* @param ctx Contexto técnico (operación, tokenKind, issuer, audience, alg).
|
|
28
|
+
* @returns Error del core ya construido con code/message/meta/cause.
|
|
29
|
+
*/
|
|
30
|
+
export declare function toAuthDomainError<TAuthError extends Error>(createAuthError: (args: {
|
|
31
|
+
code: MappedAuthError["code"];
|
|
32
|
+
message: string;
|
|
33
|
+
cause?: unknown;
|
|
34
|
+
meta?: Record<string, unknown>;
|
|
35
|
+
}) => TAuthError, err: unknown, ctx: JoseErrorContext): TAuthError;
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// src/infrastructure/mappers/jose-error.mapper.ts
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.mapJoseErrorToAuthError = mapJoseErrorToAuthError;
|
|
5
|
+
exports.toAuthDomainError = toAuthDomainError;
|
|
6
|
+
/**
|
|
7
|
+
* Mapper de errores de `jose` → error “entendible” por el core (@jmlq/auth).
|
|
8
|
+
*
|
|
9
|
+
* Características clave:
|
|
10
|
+
* - NO lanza errores: solo traduce un error recibido a un código estable del core.
|
|
11
|
+
* - NO expone datos sensibles (no incluye token ni material de claves).
|
|
12
|
+
* - Incluye `meta` mínima para troubleshooting (issuer/audience/alg/operación).
|
|
13
|
+
*
|
|
14
|
+
* Objetivo:
|
|
15
|
+
* Evitar acoplamiento de la aplicación al detalle de `jose`.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Extrae el "name" del error de forma segura.
|
|
19
|
+
* En `jose` el `name` suele identificar clases como JWTExpired, JWTInvalid, etc.
|
|
20
|
+
*
|
|
21
|
+
* @param err Error desconocido (puede ser cualquier cosa: Error, string, etc.).
|
|
22
|
+
* @returns Nombre del error o "UnknownError" si no se puede leer.
|
|
23
|
+
*/
|
|
24
|
+
function getErrorName(err) {
|
|
25
|
+
if (err &&
|
|
26
|
+
typeof err === "object" &&
|
|
27
|
+
"name" in err &&
|
|
28
|
+
typeof err.name === "string") {
|
|
29
|
+
return err.name;
|
|
30
|
+
}
|
|
31
|
+
return "UnknownError";
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Extrae el "message" del error de forma segura.
|
|
35
|
+
*
|
|
36
|
+
* @param err Error desconocido.
|
|
37
|
+
* @returns Mensaje del error o un mensaje genérico si no existe.
|
|
38
|
+
*/
|
|
39
|
+
function getErrorMessage(err) {
|
|
40
|
+
if (err &&
|
|
41
|
+
typeof err === "object" &&
|
|
42
|
+
"message" in err &&
|
|
43
|
+
typeof err.message === "string") {
|
|
44
|
+
return err.message;
|
|
45
|
+
}
|
|
46
|
+
return "Unexpected token error";
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Construye metadatos mínimos para debugging.
|
|
50
|
+
* Importante: no se incluyen tokens ni claves.
|
|
51
|
+
*
|
|
52
|
+
* @param joseErrorName Nombre del error (según `err.name`).
|
|
53
|
+
* @param ctx Contexto técnico (operación, tipo de token, issuer, audience, alg).
|
|
54
|
+
* @returns Meta segura para logging / troubleshooting.
|
|
55
|
+
*/
|
|
56
|
+
function buildSafeMeta(joseErrorName, ctx) {
|
|
57
|
+
return {
|
|
58
|
+
joseErrorName,
|
|
59
|
+
operation: ctx.operation,
|
|
60
|
+
tokenKind: ctx.tokenKind ?? "unknown",
|
|
61
|
+
issuer: ctx.issuer,
|
|
62
|
+
audience: ctx.audience,
|
|
63
|
+
alg: ctx.alg,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Mapea un error técnico a un código estable del core.
|
|
68
|
+
*
|
|
69
|
+
* La estrategia es conservadora:
|
|
70
|
+
* - Primero intenta mapear por `err.name` (más estable en `jose`).
|
|
71
|
+
* - Luego usa heurísticas por `message` como fallback.
|
|
72
|
+
* - Finalmente devuelve JWT_ERROR (catch-all) si no calza con nada.
|
|
73
|
+
*
|
|
74
|
+
* @param err Error original (normalmente de `jose`, pero puede ser cualquiera).
|
|
75
|
+
* @param ctx Contexto técnico mínimo para enriquecer meta y mejorar clasificación.
|
|
76
|
+
* @returns MappedAuthError con código del core + meta segura + causa opcional.
|
|
77
|
+
*/
|
|
78
|
+
function mapJoseErrorToAuthError(err, ctx) {
|
|
79
|
+
const name = getErrorName(err);
|
|
80
|
+
const msg = getErrorMessage(err);
|
|
81
|
+
const meta = buildSafeMeta(name, ctx);
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
// Mapeos preferentes por "name" (casos típicos en verificación JWT)
|
|
84
|
+
// ---------------------------------------------------------------------------
|
|
85
|
+
// Token expirado: exp < now
|
|
86
|
+
if (name === "JWTExpired") {
|
|
87
|
+
return {
|
|
88
|
+
code: "TOKEN_EXPIRED",
|
|
89
|
+
message: "Token has expired",
|
|
90
|
+
meta: { ...meta },
|
|
91
|
+
cause: err,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
// Token aún no válido: nbf (not before) en el futuro o validación temporal similar
|
|
95
|
+
if (name === "JWTNotBefore" || name === "JWTNotYetValid") {
|
|
96
|
+
return {
|
|
97
|
+
code: "TOKEN_NOT_YET_VALID",
|
|
98
|
+
message: "Token is not yet valid",
|
|
99
|
+
meta: { ...meta },
|
|
100
|
+
cause: err,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
// Firma inválida / verificación de firma fallida
|
|
104
|
+
// Nota: algunos nombres pueden variar según versión/caso, por eso agrupamos.
|
|
105
|
+
if (name === "JWSSignatureVerificationFailed" ||
|
|
106
|
+
name === "JWSInvalid" ||
|
|
107
|
+
name === "JWSError") {
|
|
108
|
+
return {
|
|
109
|
+
code: "SIGNATURE_INVALID",
|
|
110
|
+
message: "Token signature is invalid",
|
|
111
|
+
meta: { ...meta },
|
|
112
|
+
cause: err,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
// Claims inválidos (issuer/audience/subject/etc.)
|
|
116
|
+
if (name === "JWTClaimValidationFailed") {
|
|
117
|
+
return {
|
|
118
|
+
code: "CLAIMS_VALIDATION_ERROR",
|
|
119
|
+
message: "Token claims validation failed",
|
|
120
|
+
meta: { ...meta },
|
|
121
|
+
cause: err,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
// Token inválido (estructura o contenido no aceptado)
|
|
125
|
+
if (name === "JWTInvalid") {
|
|
126
|
+
return {
|
|
127
|
+
code: "TOKEN_INVALID",
|
|
128
|
+
message: "Token is invalid",
|
|
129
|
+
meta: { ...meta },
|
|
130
|
+
cause: err,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
// Token malformado (no cumple formato compacto "header.payload.signature", etc.)
|
|
134
|
+
if (name === "JWTMalformed" ||
|
|
135
|
+
name === "JWSMalformed" ||
|
|
136
|
+
name === "JOSEError") {
|
|
137
|
+
return {
|
|
138
|
+
code: "TOKEN_MALFORMED",
|
|
139
|
+
message: "Token is malformed",
|
|
140
|
+
meta: { ...meta },
|
|
141
|
+
cause: err,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
// Algoritmo no soportado o no permitido
|
|
145
|
+
if (name === "JOSENotSupported" || name === "JWTAlgorithmNotAllowed") {
|
|
146
|
+
return {
|
|
147
|
+
code: "ALGORITHM_UNSUPPORTED",
|
|
148
|
+
message: "Token algorithm is not supported",
|
|
149
|
+
meta: { ...meta },
|
|
150
|
+
cause: err,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
// Material de clave inválido o incompatible con algoritmo
|
|
154
|
+
if (name === "JWKInvalid" || name === "JWKInvalidFormat") {
|
|
155
|
+
return {
|
|
156
|
+
code: "KEY_MISMATCH",
|
|
157
|
+
message: "Key material is invalid or does not match the algorithm",
|
|
158
|
+
meta: { ...meta },
|
|
159
|
+
cause: err,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
// ---------------------------------------------------------------------------
|
|
163
|
+
// Fallbacks por mensaje (heurísticas conservadoras)
|
|
164
|
+
// ---------------------------------------------------------------------------
|
|
165
|
+
const lower = msg.toLowerCase();
|
|
166
|
+
// Clave ausente / no encontrada
|
|
167
|
+
if (lower.includes("key") &&
|
|
168
|
+
(lower.includes("not found") || lower.includes("missing"))) {
|
|
169
|
+
return {
|
|
170
|
+
code: "KEY_NOT_FOUND",
|
|
171
|
+
message: "Key not found for token verification",
|
|
172
|
+
meta: { ...meta },
|
|
173
|
+
cause: err,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
// Clave inválida o mismatch
|
|
177
|
+
if (lower.includes("key") &&
|
|
178
|
+
(lower.includes("mismatch") || lower.includes("invalid"))) {
|
|
179
|
+
return {
|
|
180
|
+
code: "KEY_MISMATCH",
|
|
181
|
+
message: "Key does not match token requirements",
|
|
182
|
+
meta: { ...meta },
|
|
183
|
+
cause: err,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
// ---------------------------------------------------------------------------
|
|
187
|
+
// Catch-all
|
|
188
|
+
// ---------------------------------------------------------------------------
|
|
189
|
+
return {
|
|
190
|
+
code: "JWT_ERROR",
|
|
191
|
+
message: "JWT operation failed",
|
|
192
|
+
meta: { ...meta },
|
|
193
|
+
cause: err,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Convierte un error técnico a un Error del core (AuthDomainError u otro),
|
|
198
|
+
* sin acoplar el plugin a una implementación concreta.
|
|
199
|
+
*
|
|
200
|
+
* Esta función es útil porque:
|
|
201
|
+
* - El mapper produce un objeto “agnóstico” (MappedAuthError).
|
|
202
|
+
* - La creación del Error real depende del core o de la app (inyección).
|
|
203
|
+
*
|
|
204
|
+
* @template TAuthError Tipo de error final que devuelve el core.
|
|
205
|
+
*
|
|
206
|
+
* @param createAuthError Función provista por el core/app para crear el error final.
|
|
207
|
+
* @param err Error original que proviene de `jose` u otra fuente.
|
|
208
|
+
* @param ctx Contexto técnico (operación, tokenKind, issuer, audience, alg).
|
|
209
|
+
* @returns Error del core ya construido con code/message/meta/cause.
|
|
210
|
+
*/
|
|
211
|
+
function toAuthDomainError(createAuthError, err, ctx) {
|
|
212
|
+
const mapped = mapJoseErrorToAuthError(err, ctx);
|
|
213
|
+
return createAuthError({
|
|
214
|
+
code: mapped.code,
|
|
215
|
+
message: mapped.message,
|
|
216
|
+
cause: mapped.cause,
|
|
217
|
+
meta: mapped.meta,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./jose-error-context.type"), exports);
|
|
18
|
+
__exportStar(require("./mapped-auth-error.type"), exports);
|
|
19
|
+
__exportStar(require("./token-kind.type"), exports);
|
|
20
|
+
__exportStar(require("./token-operation.type"), exports);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { TokenKind, TokenOperation } from ".";
|
|
2
|
+
/**
|
|
3
|
+
* Contexto técnico mínimo para mapear errores de `jose` a errores del core.
|
|
4
|
+
*
|
|
5
|
+
* Importante:
|
|
6
|
+
* - NO incluir tokens ni claves aquí (evitar datos sensibles).
|
|
7
|
+
* - Solo información útil para debugging y clasificación.
|
|
8
|
+
*/
|
|
9
|
+
export interface JoseErrorContext {
|
|
10
|
+
/**
|
|
11
|
+
* Operación que estaba ejecutándose cuando falló.
|
|
12
|
+
*/
|
|
13
|
+
operation: TokenOperation;
|
|
14
|
+
/**
|
|
15
|
+
* Tipo de token esperado.
|
|
16
|
+
* Si no se conoce, usar "unknown".
|
|
17
|
+
*/
|
|
18
|
+
tokenKind?: TokenKind;
|
|
19
|
+
/**
|
|
20
|
+
* Issuer esperado/configurado (si aplica).
|
|
21
|
+
* Sirve para entender fallos de validación de claims.
|
|
22
|
+
*/
|
|
23
|
+
issuer?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Audience esperada/configurada (si aplica).
|
|
26
|
+
*/
|
|
27
|
+
audience?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Algoritmo configurado/esperado (HS256/RS256/ES256...).
|
|
30
|
+
*/
|
|
31
|
+
alg?: string;
|
|
32
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resultado agnóstico del mapper.
|
|
3
|
+
* Representa “la forma” del error que entiende el core (por código),
|
|
4
|
+
* pero sin acoplarse a una clase concreta de error.
|
|
5
|
+
*/
|
|
6
|
+
export interface MappedAuthError {
|
|
7
|
+
/**
|
|
8
|
+
* Código de error compatible con el core (@jmlq/auth).
|
|
9
|
+
*/
|
|
10
|
+
code: "TOKEN_EXPIRED" | "TOKEN_NOT_YET_VALID" | "SIGNATURE_INVALID" | "TOKEN_MALFORMED" | "TOKEN_INVALID" | "CLAIMS_VALIDATION_ERROR" | "ALGORITHM_UNSUPPORTED" | "KEY_NOT_FOUND" | "KEY_MISMATCH" | "JWT_ERROR" | "AUTHENTICATION_FAILED";
|
|
11
|
+
/**
|
|
12
|
+
* Mensaje técnico simple (orientado a debugging).
|
|
13
|
+
* No debe incluir datos sensibles.
|
|
14
|
+
*/
|
|
15
|
+
message: string;
|
|
16
|
+
/**
|
|
17
|
+
* Metadatos para troubleshooting (sin secretos).
|
|
18
|
+
*/
|
|
19
|
+
meta: Record<string, unknown>;
|
|
20
|
+
/**
|
|
21
|
+
* Error original como causa, si se desea conservar.
|
|
22
|
+
*/
|
|
23
|
+
cause?: unknown;
|
|
24
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tipo de token esperado por el core.
|
|
3
|
+
* - access: token de acceso (corto, para autorización).
|
|
4
|
+
* - refresh: token de renovación (largo, para renovar access).
|
|
5
|
+
* - unknown: se usa cuando el contexto no sabe qué tipo es (ej: lectura de exp).
|
|
6
|
+
*/
|
|
7
|
+
export type TokenKind = "access" | "refresh" | "unknown";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Operaciones públicas soportadas por el servicio de tokens.
|
|
3
|
+
* Se usa principalmente para:
|
|
4
|
+
* - enriquecer meta de errores
|
|
5
|
+
* - mejorar trazabilidad
|
|
6
|
+
*/
|
|
7
|
+
export type TokenOperation = "generateAccessToken" | "generateRefreshToken" | "verifyAccessToken" | "verifyRefreshToken" | "getTokenExpiration";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./jose-token.service";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./jose-token.service"), exports);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { TokenOperation } from "../../../infrastructure/mappers/types";
|
|
2
|
+
import type { ExpiresInString } from "../../../application/types";
|
|
3
|
+
/**
|
|
4
|
+
* Verifica si un valor cumple el formato de expiración humana.
|
|
5
|
+
* Formatos válidos: "15m", "7d", "3600s", "12h".
|
|
6
|
+
*
|
|
7
|
+
* @param value Valor a validar.
|
|
8
|
+
* @returns true si cumple el formato ExpiresInString.
|
|
9
|
+
*/
|
|
10
|
+
export declare function isExpiresInString(value: unknown): value is ExpiresInString;
|
|
11
|
+
/**
|
|
12
|
+
* Resuelve el expiresIn efectivo para una operación.
|
|
13
|
+
* - Si `provided` no existe, usa `fallback`.
|
|
14
|
+
* - Si ninguno es válido, lanza error técnico (será mapeado por el wrapper).
|
|
15
|
+
*
|
|
16
|
+
* @param provided Expiración enviada en el props (puede ser undefined).
|
|
17
|
+
* @param fallback Expiración por defecto desde options.
|
|
18
|
+
* @param op Operación (para mensajes de error claros).
|
|
19
|
+
* @returns ExpiresInString válido.
|
|
20
|
+
*/
|
|
21
|
+
export declare function resolveExpiresIn(provided: unknown, fallback: unknown, op: TokenOperation): ExpiresInString;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// src/infrastructure/services/internal/expires-in.util.ts
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.isExpiresInString = isExpiresInString;
|
|
5
|
+
exports.resolveExpiresIn = resolveExpiresIn;
|
|
6
|
+
/**
|
|
7
|
+
* Verifica si un valor cumple el formato de expiración humana.
|
|
8
|
+
* Formatos válidos: "15m", "7d", "3600s", "12h".
|
|
9
|
+
*
|
|
10
|
+
* @param value Valor a validar.
|
|
11
|
+
* @returns true si cumple el formato ExpiresInString.
|
|
12
|
+
*/
|
|
13
|
+
function isExpiresInString(value) {
|
|
14
|
+
return typeof value === "string" && /^[0-9]+[smhd]$/.test(value);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Resuelve el expiresIn efectivo para una operación.
|
|
18
|
+
* - Si `provided` no existe, usa `fallback`.
|
|
19
|
+
* - Si ninguno es válido, lanza error técnico (será mapeado por el wrapper).
|
|
20
|
+
*
|
|
21
|
+
* @param provided Expiración enviada en el props (puede ser undefined).
|
|
22
|
+
* @param fallback Expiración por defecto desde options.
|
|
23
|
+
* @param op Operación (para mensajes de error claros).
|
|
24
|
+
* @returns ExpiresInString válido.
|
|
25
|
+
*/
|
|
26
|
+
function resolveExpiresIn(provided, fallback, op) {
|
|
27
|
+
if (provided === undefined || provided === null) {
|
|
28
|
+
if (isExpiresInString(fallback))
|
|
29
|
+
return fallback;
|
|
30
|
+
throw new Error(`[JoseTokenService] Missing expiresIn for ${op}. Provide props.expiresIn or defaultExpiresIn.`);
|
|
31
|
+
}
|
|
32
|
+
if (isExpiresInString(provided))
|
|
33
|
+
return provided;
|
|
34
|
+
throw new Error(`[JoseTokenService] Invalid expiresIn for ${op}. Expected format like "15m", "7d", "3600s".`);
|
|
35
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export * from "./expires-in.util";
|
|
2
|
+
export * from "./jose-context.util";
|
|
3
|
+
export * from "./jose-error.util";
|
|
4
|
+
export * from "./jose-keys.normalizer";
|
|
5
|
+
export * from "./jti.util";
|
|
6
|
+
export * from "./jwt-expiration-reader";
|
|
7
|
+
export * from "./jwt-payload.normalizer";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./expires-in.util"), exports);
|
|
18
|
+
__exportStar(require("./jose-context.util"), exports);
|
|
19
|
+
__exportStar(require("./jose-error.util"), exports);
|
|
20
|
+
__exportStar(require("./jose-keys.normalizer"), exports);
|
|
21
|
+
__exportStar(require("./jti.util"), exports);
|
|
22
|
+
__exportStar(require("./jwt-expiration-reader"), exports);
|
|
23
|
+
__exportStar(require("./jwt-payload.normalizer"), exports);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { JoseTokenServiceOptions } from "../../../application/types";
|
|
2
|
+
import type { JoseErrorContext, TokenKind, TokenOperation } from "../../mappers/types";
|
|
3
|
+
/**
|
|
4
|
+
* Devuelve string si el valor es un string no vacío.
|
|
5
|
+
*
|
|
6
|
+
* @param value Valor a convertir.
|
|
7
|
+
* @returns string o undefined.
|
|
8
|
+
*/
|
|
9
|
+
export declare function safeString(value: unknown): string | undefined;
|
|
10
|
+
/**
|
|
11
|
+
* Calcula configuración efectiva por tipo de token (access/refresh).
|
|
12
|
+
*
|
|
13
|
+
* @param options Options del JoseTokenService.
|
|
14
|
+
* @param kind Tipo de token.
|
|
15
|
+
* @returns issuer/audience/clockSkewSeconds/alg normalizados.
|
|
16
|
+
*/
|
|
17
|
+
export declare function getEffectiveConfig(options: JoseTokenServiceOptions, kind: "access" | "refresh"): {
|
|
18
|
+
issuer: string | undefined;
|
|
19
|
+
audience: string | undefined;
|
|
20
|
+
clockSkewSeconds: number | undefined;
|
|
21
|
+
alg: "HS256" | "RS256" | "ES256";
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Construye un contexto técnico para mapear errores de jose a errores del core.
|
|
25
|
+
*
|
|
26
|
+
* @param operation Operación (generate/verify/getExpiration).
|
|
27
|
+
* @param tokenKind Tipo de token (access/refresh/unknown).
|
|
28
|
+
* @param opts issuer/audience/alg ya calculados.
|
|
29
|
+
* @returns JoseErrorContext.
|
|
30
|
+
*/
|
|
31
|
+
export declare function buildJoseCtx(operation: TokenOperation, tokenKind: TokenKind, opts: {
|
|
32
|
+
issuer?: string;
|
|
33
|
+
audience?: string;
|
|
34
|
+
alg?: string;
|
|
35
|
+
}): JoseErrorContext;
|