@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.
Files changed (64) hide show
  1. package/README.md +228 -0
  2. package/dist/application/factories/create-jose-token-service.d.ts +28 -0
  3. package/dist/application/factories/create-jose-token-service.js +76 -0
  4. package/dist/application/factories/index.d.ts +1 -0
  5. package/dist/application/factories/index.js +17 -0
  6. package/dist/application/factories/internal/assert.util.d.ts +9 -0
  7. package/dist/application/factories/internal/assert.util.js +16 -0
  8. package/dist/application/factories/internal/clock-skew-normalizer.util.d.ts +14 -0
  9. package/dist/application/factories/internal/clock-skew-normalizer.util.js +24 -0
  10. package/dist/application/factories/internal/expires-in.util.d.ts +21 -0
  11. package/dist/application/factories/internal/expires-in.util.js +31 -0
  12. package/dist/application/factories/internal/index.d.ts +5 -0
  13. package/dist/application/factories/internal/index.js +21 -0
  14. package/dist/application/factories/internal/key-material.validator.d.ts +15 -0
  15. package/dist/application/factories/internal/key-material.validator.js +26 -0
  16. package/dist/application/factories/internal/string-normalizers.util.d.ts +18 -0
  17. package/dist/application/factories/internal/string-normalizers.util.js +31 -0
  18. package/dist/application/types/expires-in.types.d.ts +33 -0
  19. package/dist/application/types/expires-in.types.js +3 -0
  20. package/dist/application/types/index.d.ts +2 -0
  21. package/dist/application/types/index.js +18 -0
  22. package/dist/application/types/jose-token-service.options.d.ts +81 -0
  23. package/dist/application/types/jose-token-service.options.js +9 -0
  24. package/dist/index.d.ts +3 -0
  25. package/dist/index.js +9 -0
  26. package/dist/infrastructure/mappers/index.d.ts +1 -0
  27. package/dist/infrastructure/mappers/index.js +17 -0
  28. package/dist/infrastructure/mappers/jose-error.mapper.d.ts +35 -0
  29. package/dist/infrastructure/mappers/jose-error.mapper.js +219 -0
  30. package/dist/infrastructure/mappers/types/index.d.ts +4 -0
  31. package/dist/infrastructure/mappers/types/index.js +20 -0
  32. package/dist/infrastructure/mappers/types/jose-error-context.type.d.ts +32 -0
  33. package/dist/infrastructure/mappers/types/jose-error-context.type.js +3 -0
  34. package/dist/infrastructure/mappers/types/mapped-auth-error.type.d.ts +24 -0
  35. package/dist/infrastructure/mappers/types/mapped-auth-error.type.js +3 -0
  36. package/dist/infrastructure/mappers/types/token-kind.type.d.ts +7 -0
  37. package/dist/infrastructure/mappers/types/token-kind.type.js +3 -0
  38. package/dist/infrastructure/mappers/types/token-operation.type.d.ts +7 -0
  39. package/dist/infrastructure/mappers/types/token-operation.type.js +3 -0
  40. package/dist/infrastructure/services/index.d.ts +1 -0
  41. package/dist/infrastructure/services/index.js +17 -0
  42. package/dist/infrastructure/services/internal/expires-in.util.d.ts +21 -0
  43. package/dist/infrastructure/services/internal/expires-in.util.js +35 -0
  44. package/dist/infrastructure/services/internal/index.d.ts +7 -0
  45. package/dist/infrastructure/services/internal/index.js +23 -0
  46. package/dist/infrastructure/services/internal/jose-context.util.d.ts +35 -0
  47. package/dist/infrastructure/services/internal/jose-context.util.js +51 -0
  48. package/dist/infrastructure/services/internal/jose-error.util.d.ts +16 -0
  49. package/dist/infrastructure/services/internal/jose-error.util.js +27 -0
  50. package/dist/infrastructure/services/internal/jose-keys.normalizer.d.ts +25 -0
  51. package/dist/infrastructure/services/internal/jose-keys.normalizer.js +35 -0
  52. package/dist/infrastructure/services/internal/jti.util.d.ts +8 -0
  53. package/dist/infrastructure/services/internal/jti.util.js +25 -0
  54. package/dist/infrastructure/services/internal/jwt-expiration-reader.d.ts +9 -0
  55. package/dist/infrastructure/services/internal/jwt-expiration-reader.js +23 -0
  56. package/dist/infrastructure/services/internal/jwt-payload.normalizer.d.ts +11 -0
  57. package/dist/infrastructure/services/internal/jwt-payload.normalizer.js +56 -0
  58. package/dist/infrastructure/services/jose-token.service.d.ts +192 -0
  59. package/dist/infrastructure/services/jose-token.service.js +309 -0
  60. package/dist/infrastructure/services/types/create-auth-error-fn.type.d.ts +27 -0
  61. package/dist/infrastructure/services/types/create-auth-error-fn.type.js +2 -0
  62. package/dist/infrastructure/services/types/index.d.ts +1 -0
  63. package/dist/infrastructure/services/types/index.js +17 -0
  64. package/package.json +48 -0
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ // src/infrastructure/services/internal/jose-context.util.ts
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.safeString = safeString;
5
+ exports.getEffectiveConfig = getEffectiveConfig;
6
+ exports.buildJoseCtx = buildJoseCtx;
7
+ /**
8
+ * Devuelve string si el valor es un string no vacío.
9
+ *
10
+ * @param value Valor a convertir.
11
+ * @returns string o undefined.
12
+ */
13
+ function safeString(value) {
14
+ return typeof value === "string" && value.length > 0 ? value : undefined;
15
+ }
16
+ /**
17
+ * Calcula configuración efectiva por tipo de token (access/refresh).
18
+ *
19
+ * @param options Options del JoseTokenService.
20
+ * @param kind Tipo de token.
21
+ * @returns issuer/audience/clockSkewSeconds/alg normalizados.
22
+ */
23
+ function getEffectiveConfig(options, kind) {
24
+ const issuer = safeString(options[kind].issuer ?? options.issuer);
25
+ const audience = safeString(options[kind].audience ?? options.audience);
26
+ const clockSkewRaw = options[kind].clockSkewSeconds ?? options.clockSkewSeconds;
27
+ const clockSkewSeconds = typeof clockSkewRaw === "number" &&
28
+ Number.isFinite(clockSkewRaw) &&
29
+ clockSkewRaw >= 0
30
+ ? clockSkewRaw
31
+ : undefined;
32
+ const alg = options[kind].keys.alg;
33
+ return { issuer, audience, clockSkewSeconds, alg };
34
+ }
35
+ /**
36
+ * Construye un contexto técnico para mapear errores de jose a errores del core.
37
+ *
38
+ * @param operation Operación (generate/verify/getExpiration).
39
+ * @param tokenKind Tipo de token (access/refresh/unknown).
40
+ * @param opts issuer/audience/alg ya calculados.
41
+ * @returns JoseErrorContext.
42
+ */
43
+ function buildJoseCtx(operation, tokenKind, opts) {
44
+ return {
45
+ operation,
46
+ tokenKind,
47
+ issuer: opts.issuer,
48
+ audience: opts.audience,
49
+ alg: opts.alg,
50
+ };
51
+ }
@@ -0,0 +1,16 @@
1
+ import { mapJoseErrorToAuthError } from "../../mappers/jose-error.mapper";
2
+ /**
3
+ * Determina si un error mapeado es "retryable" para intentar verificar
4
+ * con otro set de keys (ej: access -> refresh).
5
+ *
6
+ * @param code Código de error del core (resultado del mapper).
7
+ * @returns true si vale la pena reintentar.
8
+ */
9
+ export declare function isRetryableMappedCode(code: ReturnType<typeof mapJoseErrorToAuthError>["code"]): boolean;
10
+ /**
11
+ * Convierte segundos Unix a Date.
12
+ *
13
+ * @param expSeconds `exp` en segundos Unix.
14
+ * @returns Date correspondiente.
15
+ */
16
+ export declare function toDateFromUnixSeconds(expSeconds: number): Date;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ // src/infrastructure/services/internal/jose-error.util.ts
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.isRetryableMappedCode = isRetryableMappedCode;
5
+ exports.toDateFromUnixSeconds = toDateFromUnixSeconds;
6
+ /**
7
+ * Determina si un error mapeado es "retryable" para intentar verificar
8
+ * con otro set de keys (ej: access -> refresh).
9
+ *
10
+ * @param code Código de error del core (resultado del mapper).
11
+ * @returns true si vale la pena reintentar.
12
+ */
13
+ function isRetryableMappedCode(code) {
14
+ return (code === "SIGNATURE_INVALID" ||
15
+ code === "ALGORITHM_UNSUPPORTED" ||
16
+ code === "KEY_MISMATCH" ||
17
+ code === "KEY_NOT_FOUND");
18
+ }
19
+ /**
20
+ * Convierte segundos Unix a Date.
21
+ *
22
+ * @param expSeconds `exp` en segundos Unix.
23
+ * @returns Date correspondiente.
24
+ */
25
+ function toDateFromUnixSeconds(expSeconds) {
26
+ return new Date(expSeconds * 1000);
27
+ }
@@ -0,0 +1,25 @@
1
+ import type { JoseKeyMaterial } from "../../../application/types";
2
+ /**
3
+ * Keys normalizadas listas para firmar/verificar.
4
+ */
5
+ export type NormalizedKeys = {
6
+ alg: JoseKeyMaterial["alg"];
7
+ privateKey?: any;
8
+ publicKey?: any;
9
+ secret?: Uint8Array;
10
+ };
11
+ /**
12
+ * Normaliza el material de claves para uso con `jose`.
13
+ *
14
+ * Reglas:
15
+ * - HS256: convierte secret string a Uint8Array (TextEncoder).
16
+ * - RS256/ES256:
17
+ * - Soporta PEM string:
18
+ * - privateKey: PKCS8
19
+ * - publicKey: SPKI
20
+ * - Soporta keys ya importadas (KeyLike)
21
+ *
22
+ * @param keys Configuración de claves del plugin.
23
+ * @returns Objeto NormalizedKeys.
24
+ */
25
+ export declare function normalizeKeyMaterial(keys: JoseKeyMaterial): Promise<NormalizedKeys>;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ // src/infrastructure/services/internal/jose-keys.normalizer.ts
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.normalizeKeyMaterial = normalizeKeyMaterial;
5
+ const jose_1 = require("jose");
6
+ /**
7
+ * Normaliza el material de claves para uso con `jose`.
8
+ *
9
+ * Reglas:
10
+ * - HS256: convierte secret string a Uint8Array (TextEncoder).
11
+ * - RS256/ES256:
12
+ * - Soporta PEM string:
13
+ * - privateKey: PKCS8
14
+ * - publicKey: SPKI
15
+ * - Soporta keys ya importadas (KeyLike)
16
+ *
17
+ * @param keys Configuración de claves del plugin.
18
+ * @returns Objeto NormalizedKeys.
19
+ */
20
+ async function normalizeKeyMaterial(keys) {
21
+ if (keys.alg === "HS256") {
22
+ const secret = typeof keys.secret === "string"
23
+ ? new TextEncoder().encode(keys.secret)
24
+ : keys.secret;
25
+ return { alg: "HS256", secret };
26
+ }
27
+ const alg = keys.alg;
28
+ const privateKey = typeof keys.privateKey === "string"
29
+ ? await (0, jose_1.importPKCS8)(keys.privateKey, alg)
30
+ : keys.privateKey;
31
+ const publicKey = typeof keys.publicKey === "string"
32
+ ? await (0, jose_1.importSPKI)(keys.publicKey, alg)
33
+ : keys.publicKey;
34
+ return { alg, privateKey, publicKey };
35
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Genera un identificador único para el claim `jti`.
3
+ * - Preferencia: crypto.randomUUID (cuando está disponible).
4
+ * - Fallback: string con timestamp + random (no crypto-strong, útil en dev).
5
+ *
6
+ * @returns jti como string.
7
+ */
8
+ export declare function createJti(): string;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ // src/infrastructure/services/internal/jti.util.ts
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.createJti = createJti;
5
+ /**
6
+ * Obtiene el tiempo actual en segundos Unix.
7
+ *
8
+ * @returns Timestamp Unix (segundos).
9
+ */
10
+ function nowUnixSeconds() {
11
+ return Math.floor(Date.now() / 1000);
12
+ }
13
+ /**
14
+ * Genera un identificador único para el claim `jti`.
15
+ * - Preferencia: crypto.randomUUID (cuando está disponible).
16
+ * - Fallback: string con timestamp + random (no crypto-strong, útil en dev).
17
+ *
18
+ * @returns jti como string.
19
+ */
20
+ function createJti() {
21
+ const anyCrypto = globalThis.crypto;
22
+ if (anyCrypto?.randomUUID)
23
+ return anyCrypto.randomUUID();
24
+ return `jti_${nowUnixSeconds()}_${Math.random().toString(16).slice(2)}`;
25
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Intenta leer `exp` sin verificar firma (solo decode).
3
+ * Se usa como fallback cuando el token está expirado y el verify falla,
4
+ * pero aún queremos devolver la fecha de expiración.
5
+ *
6
+ * @param token JWT compact (string "header.payload.signature").
7
+ * @returns exp (segundos Unix) o null si no existe / no se puede leer.
8
+ */
9
+ export declare function tryReadExpByDecode(token: string): number | null;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ // src/infrastructure/services/internal/jwt-expiration-reader.ts
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.tryReadExpByDecode = tryReadExpByDecode;
5
+ const jose_1 = require("jose");
6
+ /**
7
+ * Intenta leer `exp` sin verificar firma (solo decode).
8
+ * Se usa como fallback cuando el token está expirado y el verify falla,
9
+ * pero aún queremos devolver la fecha de expiración.
10
+ *
11
+ * @param token JWT compact (string "header.payload.signature").
12
+ * @returns exp (segundos Unix) o null si no existe / no se puede leer.
13
+ */
14
+ function tryReadExpByDecode(token) {
15
+ try {
16
+ const decoded = (0, jose_1.decodeJwt)(token);
17
+ const exp = decoded?.exp;
18
+ return typeof exp === "number" ? exp : null;
19
+ }
20
+ catch {
21
+ return null;
22
+ }
23
+ }
@@ -0,0 +1,11 @@
1
+ import type { IJWTPayload } from "@jmlq/auth";
2
+ /**
3
+ * Normaliza el payload verificado por `jose` a `IJWTPayload` del core.
4
+ * Esta función asegura presencia y tipos de claims mínimos para tu plataforma.
5
+ *
6
+ * @param payload Payload retornado por jose (Record).
7
+ * @param issuer Issuer efectivo (si el claim iss no está presente).
8
+ * @param audience Audience efectivo (si el claim aud no está presente).
9
+ * @returns IJWTPayload listo para consumo por el core/aplicación.
10
+ */
11
+ export declare function normalizeJwtPayload(payload: Record<string, any>, issuer?: string, audience?: string): IJWTPayload;
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ // src/infrastructure/services/internal/jwt-payload.normalizer.ts
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.normalizeJwtPayload = normalizeJwtPayload;
5
+ const jose_context_util_1 = require("./jose-context.util");
6
+ /**
7
+ * Valida que el claim roles sea un arreglo de objetos { role: string }.
8
+ *
9
+ * @param value Claim roles.
10
+ * @returns true si cumple el formato.
11
+ */
12
+ function isRoleArray(value) {
13
+ return (Array.isArray(value) &&
14
+ value.every((x) => x && typeof x === "object" && typeof x.role === "string"));
15
+ }
16
+ /**
17
+ * Valida que el claim sea un objeto plano (no null, no array).
18
+ *
19
+ * @param value Valor a validar.
20
+ * @returns true si es objeto plano.
21
+ */
22
+ function isPlainObject(value) {
23
+ return !!value && typeof value === "object" && !Array.isArray(value);
24
+ }
25
+ /**
26
+ * Normaliza el payload verificado por `jose` a `IJWTPayload` del core.
27
+ * Esta función asegura presencia y tipos de claims mínimos para tu plataforma.
28
+ *
29
+ * @param payload Payload retornado por jose (Record).
30
+ * @param issuer Issuer efectivo (si el claim iss no está presente).
31
+ * @param audience Audience efectivo (si el claim aud no está presente).
32
+ * @returns IJWTPayload listo para consumo por el core/aplicación.
33
+ */
34
+ function normalizeJwtPayload(payload, issuer, audience) {
35
+ const sub = (0, jose_context_util_1.safeString)(payload.sub);
36
+ const jti = (0, jose_context_util_1.safeString)(payload.jti);
37
+ const roles = payload.roles;
38
+ const customClaims = payload.customClaims;
39
+ const iat = payload.iat;
40
+ const exp = payload.exp;
41
+ const iss = (0, jose_context_util_1.safeString)(payload.iss) ?? issuer;
42
+ const aud = (0, jose_context_util_1.safeString)(payload.aud) ?? audience;
43
+ if (!sub || !jti) {
44
+ throw new Error("[JoseTokenService] Missing required claims: sub/jti");
45
+ }
46
+ if (!isRoleArray(roles)) {
47
+ throw new Error("[JoseTokenService] Invalid roles claim");
48
+ }
49
+ if (!isPlainObject(customClaims)) {
50
+ throw new Error("[JoseTokenService] Invalid customClaims claim");
51
+ }
52
+ if (typeof iat !== "number" || typeof exp !== "number") {
53
+ throw new Error("[JoseTokenService] Missing required numeric claims: iat/exp");
54
+ }
55
+ return { sub, roles, customClaims, jti, iss, aud, iat, exp };
56
+ }
@@ -0,0 +1,192 @@
1
+ import type { ITokenServicePort, IJWTPayload, IGenerateAccessTokenProps, IGenerateRefreshTokenProps } from "@jmlq/auth";
2
+ import type { JoseTokenServiceOptions } from "../../application/types";
3
+ import { CreateAuthErrorFn } from "./types";
4
+ /**
5
+ * Implementación de `ITokenServicePort` usando la librería `jose`.
6
+ *
7
+ * ### ¿Qué hace esta clase?
8
+ * Orquesta operaciones de JWT para el core:
9
+ * - Generar tokens (access/refresh)
10
+ * - Verificar tokens (access/refresh)
11
+ * - Obtener expiración (exp) con política "verify-first"
12
+ *
13
+ * ### ¿Qué NO hace esta clase?
14
+ * - No contiene lógica de negocio (usuarios, sesiones, permisos, etc.)
15
+ * - No define errores propios del plugin
16
+ *
17
+ * ### Claims relevantes (explicación simple)
18
+ * - `sub`: Subject. Aquí se usa como `user.id`.
19
+ * - `jti`: Token ID. Identificador único del token.
20
+ * - `iat`: Issued At. Momento de creación del token (segundos Unix).
21
+ * - `exp`: Expiration. Momento de expiración (segundos Unix).
22
+ * - `iss`: Issuer. Emisor (opcional, configurable).
23
+ * - `aud`: Audience. Audiencia (opcional, configurable).
24
+ *
25
+ * ### Manejo de errores
26
+ * Cualquier error técnico de `jose` se captura y traduce a un error del core
27
+ * mediante `createAuthError` + el mapper `toAuthDomainError`.
28
+ *
29
+ * @template TAuthError Tipo concreto de Error del core.
30
+ */
31
+ export declare class JoseTokenService<TAuthError extends Error> implements ITokenServicePort {
32
+ /**
33
+ * Configuración técnica del plugin:
34
+ * - keys por tipo de token (access/refresh)
35
+ * - issuer/audience
36
+ * - clockSkew
37
+ * - defaultExpiresIn
38
+ */
39
+ private readonly options;
40
+ /**
41
+ * Factory de error del core. El plugin no crea errores propios.
42
+ */
43
+ private readonly createAuthError;
44
+ /**
45
+ * Cache (lazy) de keys normalizadas para access.
46
+ * Se resuelve una sola vez y se reutiliza.
47
+ */
48
+ private accessKeysPromise?;
49
+ /**
50
+ * Cache (lazy) de keys normalizadas para refresh.
51
+ * Se resuelve una sola vez y se reutiliza.
52
+ */
53
+ private refreshKeysPromise?;
54
+ /**
55
+ * Crea el servicio.
56
+ *
57
+ * @param options Configuración del plugin (keys/issuer/audience/clockSkew).
58
+ * @param createAuthError Función para construir errores del core.
59
+ */
60
+ constructor(options: JoseTokenServiceOptions, createAuthError: CreateAuthErrorFn<TAuthError>);
61
+ /**
62
+ * Genera un Access Token.
63
+ *
64
+ * @param props Props definidos por el core:
65
+ * - user.id se asigna al claim `sub`
66
+ * - user.roles se incluye en el payload
67
+ * - customClaims opcional en payload (si el core lo define en props)
68
+ * - expiresIn opcional (si se incluye, sobreescribe defaultExpiresIn)
69
+ * @returns JWT compacto (string: "header.payload.signature")
70
+ */
71
+ generateAccessToken(props: IGenerateAccessTokenProps): Promise<string>;
72
+ /**
73
+ * Genera un Refresh Token.
74
+ *
75
+ * @param props Props definidos por el core:
76
+ * - user.id se asigna al claim `sub`
77
+ * - user.roles se incluye en el payload
78
+ * - customClaims opcional en payload (si el core lo define en props)
79
+ * - expiresIn opcional (si se incluye, sobreescribe defaultExpiresIn)
80
+ * @returns JWT compacto (string: "header.payload.signature")
81
+ */
82
+ generateRefreshToken(props: IGenerateRefreshTokenProps): Promise<string>;
83
+ /**
84
+ * Verifica un Access Token.
85
+ *
86
+ * Verificación incluye:
87
+ * - Firma válida según keys + algoritmo
88
+ * - `iss` y `aud` si están configurados
89
+ * - `exp` y `nbf` (si existe) considerando clockSkew
90
+ *
91
+ * @param token JWT compacto (string).
92
+ * @returns Payload normalizado al tipo `IJWTPayload` del core.
93
+ */
94
+ verifyAccessToken(token: string): Promise<IJWTPayload>;
95
+ /**
96
+ * Verifica un Refresh Token.
97
+ *
98
+ * @param token JWT compacto (string).
99
+ * @returns Payload normalizado al tipo `IJWTPayload` del core.
100
+ */
101
+ verifyRefreshToken(token: string): Promise<IJWTPayload>;
102
+ /**
103
+ * Devuelve la fecha de expiración (`exp`) del token.
104
+ *
105
+ * Política aplicada: **verify-first** (obligatoria en este proyecto)
106
+ *
107
+ * Estrategia práctica:
108
+ * 1) Intenta verificar como access:
109
+ * - Si verifica, devuelve `payload.exp`.
110
+ * - Si falla y el error es "retryable", intenta refresh.
111
+ * - Si falla por expiración, intenta leer `exp` por decode (sin verificar firma).
112
+ *
113
+ * 2) Intenta verificar como refresh:
114
+ * - Mismo comportamiento para el caso expirado.
115
+ *
116
+ * @param token JWT compacto (string).
117
+ * @returns Date correspondiente a `exp`.
118
+ * @throws Error del core (TAuthError) cuando no se puede determinar la expiración.
119
+ */
120
+ getTokenExpiration(token: string): Promise<Date>;
121
+ /**
122
+ * Construye un contexto técnico para mapear errores.
123
+ *
124
+ * El contexto agrega información útil:
125
+ * - operación (generate/verify/getExpiration)
126
+ * - tipo de token (access/refresh)
127
+ * - issuer/audience/alg efectivos
128
+ *
129
+ * Esto permite que el mapper traduzca un error de `jose` a un código del core.
130
+ *
131
+ * @param operation Operación que se está ejecutando.
132
+ * @param kind Tipo de token al que aplica la operación.
133
+ * @returns Contexto técnico para el mapper de errores.
134
+ */
135
+ private ctx;
136
+ /**
137
+ * Wrapper de errores: captura errores técnicos y los convierte a errores del core.
138
+ *
139
+ * Esta función garantiza que la API pública del plugin nunca “escape” errores de jose.
140
+ *
141
+ * @param operation Operación actual (para el contexto de error).
142
+ * @param kind Tipo de token (access/refresh).
143
+ * @param fn Función async que ejecuta la operación real.
144
+ * @returns Resultado de la operación si todo sale bien.
145
+ * @throws Error del core (TAuthError) si algo falla.
146
+ */
147
+ private withAuthError;
148
+ /**
149
+ * Obtiene las keys normalizadas para firmar/verificar tokens.
150
+ *
151
+ * La normalización sucede una sola vez (lazy) para evitar:
152
+ * - importación repetida de PEM
153
+ * - creación repetida de Uint8Array para HS256
154
+ *
155
+ * @param kind Tipo de token (access/refresh).
156
+ * @returns Keys normalizadas según algoritmo.
157
+ */
158
+ private getNormalizedKeys;
159
+ /**
160
+ * Genera un token JWT (access o refresh).
161
+ *
162
+ * Qué hace internamente (explicación simple):
163
+ * - Calcula config efectiva (issuer/audience/clockSkew/alg)
164
+ * - Resuelve expiresIn (props o default)
165
+ * - Construye payload con roles + customClaims
166
+ * - Establece claims estándar: sub, jti, iat, exp, iss, aud
167
+ * - Firma el token con:
168
+ * - HS256: secret
169
+ * - RS256/ES256: privateKey
170
+ *
171
+ * @param kind Tipo de token a generar.
172
+ * @param operation Nombre lógico de operación (para errores).
173
+ * @param props Props del core para generación de token.
174
+ * @returns JWT compacto firmado.
175
+ */
176
+ private generateToken;
177
+ /**
178
+ * Verifica un token JWT (access o refresh) y normaliza el payload al tipo del core.
179
+ *
180
+ * Qué valida `jwtVerify`:
181
+ * - Firma correcta según key + algoritmo
182
+ * - exp/nbf/iat (según reglas estándar)
183
+ * - issuer/audience si se configuran
184
+ * - clockTolerance para tolerar pequeños desajustes de reloj
185
+ *
186
+ * @param kind Tipo de token esperado (access/refresh).
187
+ * @param operation Operación lógica (para contexto de error).
188
+ * @param token JWT compacto (string).
189
+ * @returns Payload normalizado (IJWTPayload).
190
+ */
191
+ private verifyToken;
192
+ }