@jmlq/auth-plugin-jose 0.0.1-alpha.7 → 0.0.1-alpha.9
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/dist/application/factories/create-jose-token-service.d.ts +2 -2
- package/dist/application/factories/create-jose-token-service.js +5 -15
- package/dist/application/types/index.d.ts +0 -2
- package/dist/application/types/index.js +0 -5
- package/dist/application/types/jose-token-service-options.type.d.ts +8 -6
- package/dist/infrastructure/services/internal/index.d.ts +1 -0
- package/dist/infrastructure/services/internal/index.js +1 -0
- package/dist/infrastructure/services/internal/strip-sensitive-custom-claims.d.ts +5 -0
- package/dist/infrastructure/services/internal/strip-sensitive-custom-claims.js +16 -0
- package/dist/infrastructure/services/jose-token.service.d.ts +37 -5
- package/dist/infrastructure/services/jose-token.service.js +83 -26
- package/package.json +2 -2
- package/dist/application/types/get-expiration-policy.type.d.ts +0 -9
- package/dist/application/types/get-expiration-policy.type.js +0 -7
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { JoseTokenService } from "../../infrastructure/services";
|
|
2
2
|
import type { CreateAuthErrorFn } from "../../infrastructure/services/types";
|
|
3
3
|
import { JoseTokenServiceOptions } from "../types";
|
|
4
4
|
/**
|
|
@@ -11,4 +11,4 @@ import { JoseTokenServiceOptions } from "../types";
|
|
|
11
11
|
*/
|
|
12
12
|
export declare function createJoseTokenService(options: JoseTokenServiceOptions, deps: {
|
|
13
13
|
createAuthError: CreateAuthErrorFn;
|
|
14
|
-
}):
|
|
14
|
+
}): JoseTokenService;
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createJoseTokenService = createJoseTokenService;
|
|
4
|
-
const auth_1 = require("@jmlq/auth");
|
|
5
4
|
const services_1 = require("../../infrastructure/services");
|
|
6
5
|
const internal_1 = require("./internal");
|
|
7
|
-
const types_1 = require("../types");
|
|
8
6
|
/**
|
|
9
7
|
* Factory para construir un `ITokenServicePort` basado en `jose`.
|
|
10
8
|
*
|
|
@@ -16,21 +14,13 @@ const types_1 = require("../types");
|
|
|
16
14
|
function createJoseTokenService(options, deps) {
|
|
17
15
|
(0, internal_1.assert)(options, "JoseTokenServiceOptions is required");
|
|
18
16
|
(0, internal_1.assert)(deps?.createAuthError, "createAuthError dependency is required");
|
|
19
|
-
const keyMaterial = (0, internal_1.validateKeyMaterial)(options.keyMaterial);
|
|
20
|
-
// Normalización mínima local (string trim -> undefined) OK en application
|
|
21
|
-
const issuer = (0, auth_1.readNonEmptyString)(options.issuer);
|
|
22
|
-
// IMPORTANTE:
|
|
23
|
-
// - clockSkewSeconds y defaultExpiresIn se delegan a infraestructura para
|
|
24
|
-
// aplicar normalización estándar desde @jmlq/auth.
|
|
25
|
-
const clockSkewSeconds = options.clockSkewSeconds;
|
|
26
|
-
const defaultExpiresIn = options.defaultExpiresIn;
|
|
27
17
|
return new services_1.JoseTokenService({
|
|
28
18
|
options: {
|
|
29
|
-
keyMaterial,
|
|
30
|
-
issuer,
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
19
|
+
keyMaterial: options.keyMaterial,
|
|
20
|
+
issuer: options.issuer,
|
|
21
|
+
audience: options.audience,
|
|
22
|
+
clockSkewSeconds: options.clockSkewSeconds,
|
|
23
|
+
defaultExpiresIn: options.defaultExpiresIn,
|
|
34
24
|
},
|
|
35
25
|
createAuthError: deps.createAuthError,
|
|
36
26
|
});
|
|
@@ -14,11 +14,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.DEFAULT_GET_EXPIRATION_POLICY = void 0;
|
|
18
17
|
__exportStar(require("./jose-token-service-options.type"), exports);
|
|
19
18
|
__exportStar(require("./jose-key-material.type"), exports);
|
|
20
19
|
__exportStar(require("./default-expires-in.type"), exports);
|
|
21
|
-
__exportStar(require("./get-expiration-policy.type"), exports);
|
|
22
|
-
// Constantes públicas
|
|
23
|
-
var get_expiration_policy_type_1 = require("./get-expiration-policy.type");
|
|
24
|
-
Object.defineProperty(exports, "DEFAULT_GET_EXPIRATION_POLICY", { enumerable: true, get: function () { return get_expiration_policy_type_1.DEFAULT_GET_EXPIRATION_POLICY; } });
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { JoseKeyMaterial } from "./jose-key-material.type";
|
|
2
2
|
import type { DefaultExpiresIn } from "./default-expires-in.type";
|
|
3
|
-
import type { GetExpirationPolicy } from "./get-expiration-policy.type";
|
|
4
3
|
/**
|
|
5
4
|
* Opciones públicas para construir el token service basado en jose.
|
|
6
5
|
* Responsabilidad: configuración neutral, sin acoplar al consumidor a jose.
|
|
@@ -8,6 +7,14 @@ import type { GetExpirationPolicy } from "./get-expiration-policy.type";
|
|
|
8
7
|
export interface JoseTokenServiceOptions {
|
|
9
8
|
keyMaterial: JoseKeyMaterial;
|
|
10
9
|
issuer?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Audience opcional para firmar (claim `aud`).
|
|
12
|
+
* Puede ser string o string[].
|
|
13
|
+
*
|
|
14
|
+
* Nota: esto NO es validación de audience contra el token entrante.
|
|
15
|
+
* Es solo configuración para emisión (firmado).
|
|
16
|
+
*/
|
|
17
|
+
audience?: string | string[];
|
|
11
18
|
/**
|
|
12
19
|
* Clock skew en segundos para validaciones temporales (iat/nbf/exp).
|
|
13
20
|
*/
|
|
@@ -16,9 +23,4 @@ export interface JoseTokenServiceOptions {
|
|
|
16
23
|
* Expiraciones default si el token no define otra (por kind).
|
|
17
24
|
*/
|
|
18
25
|
defaultExpiresIn?: DefaultExpiresIn;
|
|
19
|
-
/**
|
|
20
|
-
* Política acordada del plugin.
|
|
21
|
-
* Se fuerza a "verify-first" desde la factory.
|
|
22
|
-
*/
|
|
23
|
-
getExpirationPolicy?: GetExpirationPolicy;
|
|
24
26
|
}
|
|
@@ -18,3 +18,4 @@ __exportStar(require("./normalize-key-material"), exports);
|
|
|
18
18
|
__exportStar(require("./jwt-expiration-reader"), exports);
|
|
19
19
|
__exportStar(require("./get-alg-from-key-material"), exports);
|
|
20
20
|
__exportStar(require("./build-jose-ctx"), exports);
|
|
21
|
+
__exportStar(require("./strip-sensitive-custom-claims"), exports);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.stripSensitiveCustomClaims = stripSensitiveCustomClaims;
|
|
4
|
+
/**
|
|
5
|
+
* Elimina claims sensibles que NO deben viajar en JWT.
|
|
6
|
+
* - permissions: deben resolverse en BDD en cada request.
|
|
7
|
+
*/
|
|
8
|
+
function stripSensitiveCustomClaims(input) {
|
|
9
|
+
const out = {};
|
|
10
|
+
for (const [k, v] of Object.entries(input)) {
|
|
11
|
+
if (k === "permissions")
|
|
12
|
+
continue;
|
|
13
|
+
out[k] = v;
|
|
14
|
+
}
|
|
15
|
+
return out;
|
|
16
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type IGenerateAccessTokenProps, type IGenerateRefreshTokenProps, type IJWTPayload, type ITokenServicePort } from "@jmlq/auth";
|
|
2
2
|
import type { JoseTokenServiceOptions } from "../../application/types";
|
|
3
3
|
import type { CreateAuthErrorFn } from "./types";
|
|
4
4
|
/**
|
|
@@ -6,20 +6,24 @@ import type { CreateAuthErrorFn } from "./types";
|
|
|
6
6
|
*
|
|
7
7
|
* Responsabilidad única:
|
|
8
8
|
* - Firmar/verificar JWT
|
|
9
|
-
* - Delegar validación
|
|
9
|
+
* - Delegar validación/normalización del payload al core (normalizeJwtPayload)
|
|
10
10
|
*
|
|
11
11
|
* Clean Architecture (decisión del proyecto):
|
|
12
|
-
* -
|
|
13
|
-
* para evitar duplicidad en cada plugin.
|
|
12
|
+
* - En infraestructura sí consumimos utilidades estándar desde @jmlq/auth
|
|
13
|
+
* (reglas canónicas), para evitar duplicidad en cada plugin.
|
|
14
14
|
*/
|
|
15
15
|
export declare class JoseTokenService implements ITokenServicePort {
|
|
16
16
|
private readonly options;
|
|
17
17
|
private readonly createAuthError;
|
|
18
|
+
private readonly keyMaterial;
|
|
18
19
|
/**
|
|
19
20
|
* Config normalizada (estandarizada) para uso interno.
|
|
20
|
-
* Se deriva 1 sola vez para evitar repetir lógica.
|
|
21
|
+
* Se deriva 1 sola vez para evitar repetir lógica y asegurar consistencia.
|
|
21
22
|
*/
|
|
22
23
|
private readonly eff;
|
|
24
|
+
/**
|
|
25
|
+
* Cache lazy de llaves normalizadas (evita repetir trabajo por request).
|
|
26
|
+
*/
|
|
23
27
|
private keysPromise;
|
|
24
28
|
constructor(cfg: {
|
|
25
29
|
options: JoseTokenServiceOptions;
|
|
@@ -29,9 +33,37 @@ export declare class JoseTokenService implements ITokenServicePort {
|
|
|
29
33
|
generateRefreshToken(props: IGenerateRefreshTokenProps): Promise<string>;
|
|
30
34
|
verifyAccessToken(token: string): Promise<IJWTPayload>;
|
|
31
35
|
verifyRefreshToken(token: string): Promise<IJWTPayload>;
|
|
36
|
+
/**
|
|
37
|
+
* Obtiene la fecha de expiración del token.
|
|
38
|
+
*
|
|
39
|
+
* Estrategia:
|
|
40
|
+
* - Primero intenta verificarlo como access.
|
|
41
|
+
* - Si falla con error “retryable”, intenta verificarlo como refresh.
|
|
42
|
+
* - Si está expirado pero se puede leer exp vía decode (sin verificación),
|
|
43
|
+
* retorna esa exp para fines informativos.
|
|
44
|
+
*/
|
|
32
45
|
getTokenExpiration(token: string): Promise<Date>;
|
|
46
|
+
/**
|
|
47
|
+
* Construye contexto mínimo (no sensible) para mapear errores.
|
|
48
|
+
*
|
|
49
|
+
* ¿Por qué existe?
|
|
50
|
+
* - Hace diagnósticos más fáciles (operación, tokenKind, alg, issuer).
|
|
51
|
+
* - Evita exponer token, claims completos o material criptográfico.
|
|
52
|
+
*
|
|
53
|
+
* Nota:
|
|
54
|
+
* - No incluimos audience en el contexto porque la audience en este plugin
|
|
55
|
+
* es SOLO para emisión y no participa en verificación (por decisión de diseño).
|
|
56
|
+
*/
|
|
33
57
|
private ctx;
|
|
58
|
+
/**
|
|
59
|
+
* Wrapper estándar:
|
|
60
|
+
* - Ejecuta fn
|
|
61
|
+
* - En caso de error, lo traduce a AuthDomainError usando el mapper del plugin
|
|
62
|
+
*/
|
|
34
63
|
private withAuthError;
|
|
64
|
+
/**
|
|
65
|
+
* Normaliza/carga llaves de forma lazy y cacheada.
|
|
66
|
+
*/
|
|
35
67
|
private getNormalizedKeys;
|
|
36
68
|
private generateToken;
|
|
37
69
|
private verifyToken;
|
|
@@ -1,29 +1,38 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
// src/infrastructure/services/jose-token.service.ts
|
|
2
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
4
|
exports.JoseTokenService = void 0;
|
|
4
|
-
const auth_1 = require("@jmlq/auth");
|
|
5
5
|
const jose_1 = require("jose");
|
|
6
|
+
const auth_1 = require("@jmlq/auth");
|
|
7
|
+
const internal_1 = require("../../application/factories/internal");
|
|
6
8
|
const mappers_1 = require("../mappers");
|
|
7
|
-
const
|
|
9
|
+
const internal_2 = require("./internal");
|
|
8
10
|
/**
|
|
9
11
|
* Implementación de `ITokenServicePort` usando la librería `jose`.
|
|
10
12
|
*
|
|
11
13
|
* Responsabilidad única:
|
|
12
14
|
* - Firmar/verificar JWT
|
|
13
|
-
* - Delegar validación
|
|
15
|
+
* - Delegar validación/normalización del payload al core (normalizeJwtPayload)
|
|
14
16
|
*
|
|
15
17
|
* Clean Architecture (decisión del proyecto):
|
|
16
|
-
* -
|
|
17
|
-
* para evitar duplicidad en cada plugin.
|
|
18
|
+
* - En infraestructura sí consumimos utilidades estándar desde @jmlq/auth
|
|
19
|
+
* (reglas canónicas), para evitar duplicidad en cada plugin.
|
|
18
20
|
*/
|
|
19
21
|
class JoseTokenService {
|
|
20
22
|
constructor(cfg) {
|
|
23
|
+
/**
|
|
24
|
+
* Cache lazy de llaves normalizadas (evita repetir trabajo por request).
|
|
25
|
+
*/
|
|
21
26
|
this.keysPromise = null;
|
|
22
27
|
this.options = cfg.options;
|
|
23
28
|
this.createAuthError = cfg.createAuthError;
|
|
24
|
-
//
|
|
29
|
+
// Valida estructura de keyMaterial (alg / secret / keys etc.).
|
|
30
|
+
this.keyMaterial = (0, internal_1.validateKeyMaterial)(this.options.keyMaterial);
|
|
31
|
+
// Normalización canónica (core) aplicada en infraestructura.
|
|
32
|
+
// Nota: si el usuario envía strings con espacios, se estandariza aquí.
|
|
25
33
|
this.eff = {
|
|
26
|
-
issuer: cfg.options.issuer,
|
|
34
|
+
issuer: (0, auth_1.readNonEmptyString)(cfg.options.issuer), // " a " => "a", " " => undefined
|
|
35
|
+
audience: (0, auth_1.optionalAudience)(cfg.options.audience), // trim / dedupe+sort / errores canónicos
|
|
27
36
|
clockSkewSeconds: (0, auth_1.normalizeClockSkewSeconds)(cfg.options.clockSkewSeconds),
|
|
28
37
|
defaultExpiresIn: (0, auth_1.normalizeDefaultExpiresIn)(cfg.options.defaultExpiresIn),
|
|
29
38
|
};
|
|
@@ -43,15 +52,16 @@ class JoseTokenService {
|
|
|
43
52
|
async verifyRefreshToken(token) {
|
|
44
53
|
return this.verifyToken("refresh", "verifyRefreshToken", token);
|
|
45
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Obtiene la fecha de expiración del token.
|
|
57
|
+
*
|
|
58
|
+
* Estrategia:
|
|
59
|
+
* - Primero intenta verificarlo como access.
|
|
60
|
+
* - Si falla con error “retryable”, intenta verificarlo como refresh.
|
|
61
|
+
* - Si está expirado pero se puede leer exp vía decode (sin verificación),
|
|
62
|
+
* retorna esa exp para fines informativos.
|
|
63
|
+
*/
|
|
46
64
|
async getTokenExpiration(token) {
|
|
47
|
-
const policy = this.options.getExpirationPolicy ?? "verify-first";
|
|
48
|
-
if (policy !== "verify-first") {
|
|
49
|
-
throw this.createAuthError({
|
|
50
|
-
code: "JWT_ERROR",
|
|
51
|
-
message: "Unsupported expiration policy",
|
|
52
|
-
meta: { operation: "getTokenExpiration", tokenKind: "unknown" },
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
65
|
const firstTry = await this.tryGetExpirationByVerify("access", token);
|
|
56
66
|
if (firstTry.ok)
|
|
57
67
|
return firstTry.value;
|
|
@@ -65,14 +75,29 @@ class JoseTokenService {
|
|
|
65
75
|
// ---------------------------------------------------------------------------
|
|
66
76
|
// Internals - ctx + error wrapper
|
|
67
77
|
// ---------------------------------------------------------------------------
|
|
78
|
+
/**
|
|
79
|
+
* Construye contexto mínimo (no sensible) para mapear errores.
|
|
80
|
+
*
|
|
81
|
+
* ¿Por qué existe?
|
|
82
|
+
* - Hace diagnósticos más fáciles (operación, tokenKind, alg, issuer).
|
|
83
|
+
* - Evita exponer token, claims completos o material criptográfico.
|
|
84
|
+
*
|
|
85
|
+
* Nota:
|
|
86
|
+
* - No incluimos audience en el contexto porque la audience en este plugin
|
|
87
|
+
* es SOLO para emisión y no participa en verificación (por decisión de diseño).
|
|
88
|
+
*/
|
|
68
89
|
ctx(operation, kind) {
|
|
69
|
-
const alg = (0,
|
|
70
|
-
|
|
71
|
-
return (0, internal_1.buildJoseCtx)(operation, kind, {
|
|
90
|
+
const alg = (0, internal_2.getAlgFromKeyMaterial)(this.keyMaterial);
|
|
91
|
+
return (0, internal_2.buildJoseCtx)(operation, kind, {
|
|
72
92
|
issuer: this.eff.issuer,
|
|
73
93
|
alg,
|
|
74
94
|
});
|
|
75
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* Wrapper estándar:
|
|
98
|
+
* - Ejecuta fn
|
|
99
|
+
* - En caso de error, lo traduce a AuthDomainError usando el mapper del plugin
|
|
100
|
+
*/
|
|
76
101
|
async withAuthError(operation, kind, fn) {
|
|
77
102
|
try {
|
|
78
103
|
return await fn();
|
|
@@ -84,9 +109,12 @@ class JoseTokenService {
|
|
|
84
109
|
// ---------------------------------------------------------------------------
|
|
85
110
|
// Internals - keys
|
|
86
111
|
// ---------------------------------------------------------------------------
|
|
112
|
+
/**
|
|
113
|
+
* Normaliza/carga llaves de forma lazy y cacheada.
|
|
114
|
+
*/
|
|
87
115
|
getNormalizedKeys() {
|
|
88
116
|
if (!this.keysPromise) {
|
|
89
|
-
this.keysPromise = (0,
|
|
117
|
+
this.keysPromise = (0, internal_2.normalizeKeyMaterial)(this.keyMaterial);
|
|
90
118
|
}
|
|
91
119
|
return this.keysPromise;
|
|
92
120
|
}
|
|
@@ -95,6 +123,7 @@ class JoseTokenService {
|
|
|
95
123
|
// ---------------------------------------------------------------------------
|
|
96
124
|
async generateToken(kind, operation, props) {
|
|
97
125
|
return this.withAuthError(operation, kind, async () => {
|
|
126
|
+
// 1) Expiración: usar regla canónica del core (props > default).
|
|
98
127
|
const expiresInFromProps = (0, auth_1.readExpiresIn)(props.expiresIn);
|
|
99
128
|
const defaultExpiresIn = kind === "access"
|
|
100
129
|
? this.eff.defaultExpiresIn?.accessToken
|
|
@@ -104,9 +133,12 @@ class JoseTokenService {
|
|
|
104
133
|
defaultExpiresIn,
|
|
105
134
|
operation,
|
|
106
135
|
});
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
136
|
+
// 2) Claims estándar
|
|
137
|
+
// - NO emitimos `roles` en el JWT.
|
|
138
|
+
// - Mantenemos customClaims, pero filtramos `permissions`.
|
|
139
|
+
const customClaimsInput = (0, auth_1.readCustomClaims)(props.customClaims) ?? {};
|
|
140
|
+
const customClaims = (0, internal_2.stripSensitiveCustomClaims)(customClaimsInput);
|
|
141
|
+
// 3) Session Id (sid)
|
|
110
142
|
const sid = (0, auth_1.readSessionId)(props.sessionId);
|
|
111
143
|
if (!sid) {
|
|
112
144
|
throw this.createAuthError({
|
|
@@ -115,15 +147,25 @@ class JoseTokenService {
|
|
|
115
147
|
meta: { operation, tokenKind: kind, field: "sessionId" },
|
|
116
148
|
});
|
|
117
149
|
}
|
|
150
|
+
// 4) Firmar
|
|
118
151
|
const keys = await this.getNormalizedKeys();
|
|
119
|
-
const
|
|
152
|
+
const body = { sid };
|
|
153
|
+
if (Object.keys(customClaims).length > 0) {
|
|
154
|
+
body.customClaims = customClaims;
|
|
155
|
+
}
|
|
156
|
+
const jwt = new jose_1.SignJWT(body)
|
|
120
157
|
.setProtectedHeader({ alg: keys.alg })
|
|
121
158
|
.setSubject(props.user.id)
|
|
122
159
|
.setJti((0, auth_1.createJwtId)())
|
|
123
160
|
.setIssuedAt()
|
|
124
161
|
.setExpirationTime(expiresIn);
|
|
162
|
+
// Issuer opcional (si viene configurado y es no-vacío)
|
|
125
163
|
if (this.eff.issuer)
|
|
126
164
|
jwt.setIssuer(this.eff.issuer);
|
|
165
|
+
// Audience opcional SOLO para emisión (claim `aud`).
|
|
166
|
+
// Importante: NO se usa en verificación para no volverlo requisito.
|
|
167
|
+
if (this.eff.audience)
|
|
168
|
+
jwt.setAudience(this.eff.audience);
|
|
127
169
|
return keys.alg === "HS256"
|
|
128
170
|
? jwt.sign(keys.secret)
|
|
129
171
|
: jwt.sign(keys.privateKey);
|
|
@@ -133,11 +175,21 @@ class JoseTokenService {
|
|
|
133
175
|
return this.withAuthError(operation, kind, async () => {
|
|
134
176
|
const keys = await this.getNormalizedKeys();
|
|
135
177
|
const key = keys.alg === "HS256" ? keys.secret : keys.publicKey;
|
|
136
|
-
|
|
178
|
+
/**
|
|
179
|
+
* Verificación:
|
|
180
|
+
* - issuer: se aplica si está configurado (si no, se omite)
|
|
181
|
+
* - clockTolerance: ya normalizado (clock skew seguro)
|
|
182
|
+
*
|
|
183
|
+
* Nota: NO pasamos `audience` a jwtVerify.
|
|
184
|
+
* - La audiencia en este plugin es SOLO para emisión.
|
|
185
|
+
* - Pasarla aquí convertiría audience en una restricción (“must match”)
|
|
186
|
+
* y rompería compatibilidad con tokens válidos sin `aud`.
|
|
187
|
+
*/
|
|
137
188
|
const result = await (0, jose_1.jwtVerify)(token, key, {
|
|
138
189
|
issuer: this.eff.issuer,
|
|
139
190
|
clockTolerance: this.eff.clockSkewSeconds,
|
|
140
191
|
});
|
|
192
|
+
// Delegar a la regla canónica del core: valida + normaliza payload.
|
|
141
193
|
return (0, auth_1.normalizeJwtPayload)(result.payload);
|
|
142
194
|
});
|
|
143
195
|
}
|
|
@@ -147,11 +199,15 @@ class JoseTokenService {
|
|
|
147
199
|
return { ok: true, value: (0, auth_1.toDateFromUnixSeconds)(payload.exp) };
|
|
148
200
|
}
|
|
149
201
|
catch (err) {
|
|
202
|
+
// Si el error ya es un AuthDomainError, aplicamos reglas de retry/fallback.
|
|
150
203
|
if (auth_1.AuthDomainError.isAuthError(err)) {
|
|
204
|
+
// Caso especial: si expiró, podemos leer exp por decode (sin verificar)
|
|
205
|
+
// para devolver la fecha de expiración con fines informativos.
|
|
151
206
|
if (err.code === "TOKEN_EXPIRED") {
|
|
152
|
-
const exp = (0,
|
|
153
|
-
if (exp !== null)
|
|
207
|
+
const exp = (0, internal_2.tryReadExpByDecode)(token);
|
|
208
|
+
if (exp !== null) {
|
|
154
209
|
return { ok: true, value: (0, auth_1.toDateFromUnixSeconds)(exp) };
|
|
210
|
+
}
|
|
155
211
|
}
|
|
156
212
|
return {
|
|
157
213
|
ok: false,
|
|
@@ -159,6 +215,7 @@ class JoseTokenService {
|
|
|
159
215
|
error: err,
|
|
160
216
|
};
|
|
161
217
|
}
|
|
218
|
+
// Si es un error no estándar, lo envolvemos para mantener consistencia.
|
|
162
219
|
const wrapped = (0, mappers_1.toAuthDomainError)(this.createAuthError, err, this.ctx("getTokenExpiration", kind));
|
|
163
220
|
return { ok: false, retryable: false, error: wrapped };
|
|
164
221
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jmlq/auth-plugin-jose",
|
|
3
3
|
"description": "Infrastructure plugin that integrates the jose library with @jmlq/auth, providing JWT token generation and verification following Clean Architecture principles.",
|
|
4
|
-
"version": "0.0.1-alpha.
|
|
4
|
+
"version": "0.0.1-alpha.9",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"author": "MLahuasi",
|
|
30
30
|
"license": "MIT",
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@jmlq/auth": "^0.0.1-alpha.
|
|
32
|
+
"@jmlq/auth": "^0.0.1-alpha.30",
|
|
33
33
|
"jose": "^6.1.3"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Política de expiración del plugin.
|
|
3
|
-
* - "verify-first": verifica el token y si no tiene exp, aplica default.
|
|
4
|
-
*/
|
|
5
|
-
export type GetExpirationPolicy = "verify-first";
|
|
6
|
-
/**
|
|
7
|
-
* Política por defecto del plugin (estándar acordado).
|
|
8
|
-
*/
|
|
9
|
-
export declare const DEFAULT_GET_EXPIRATION_POLICY: GetExpirationPolicy;
|