@eva_solutions/auth-sdk 0.0.0-stage → 3.0.0-dev-20261107051125

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 (205) hide show
  1. package/CHANGELOG.md +290 -0
  2. package/LICENSE +21 -0
  3. package/README.md +481 -2
  4. package/dist/admin/index.cjs +4 -0
  5. package/dist/admin/index.d.cts +2 -0
  6. package/dist/admin/index.d.ts +2 -0
  7. package/dist/admin/index.js +1 -0
  8. package/dist/admin-DjvuvuI8.js +408 -0
  9. package/dist/admin-DjvuvuI8.js.map +1 -0
  10. package/dist/admin-Q6lbWqLM.cjs +419 -0
  11. package/dist/admin-Q6lbWqLM.cjs.map +1 -0
  12. package/dist/api-path-2Ulruz7R.cjs +34 -0
  13. package/dist/api-path-2Ulruz7R.cjs.map +1 -0
  14. package/dist/api-path-B-vSkL2H.js +29 -0
  15. package/dist/api-path-B-vSkL2H.js.map +1 -0
  16. package/dist/auth-19r-Q6X2.js +84 -0
  17. package/dist/auth-19r-Q6X2.js.map +1 -0
  18. package/dist/auth-DX1N5JA4.cjs +131 -0
  19. package/dist/auth-DX1N5JA4.cjs.map +1 -0
  20. package/dist/auth-handlers-B3iJaPln.js +343 -0
  21. package/dist/auth-handlers-B3iJaPln.js.map +1 -0
  22. package/dist/auth-handlers-BTbXKJms.d.ts +15 -0
  23. package/dist/auth-handlers-BTbXKJms.d.ts.map +1 -0
  24. package/dist/auth-handlers-CDzGFDTu.cjs +404 -0
  25. package/dist/auth-handlers-CDzGFDTu.cjs.map +1 -0
  26. package/dist/auth-handlers-DRUUTEtW.d.cts +15 -0
  27. package/dist/auth-handlers-DRUUTEtW.d.cts.map +1 -0
  28. package/dist/catalog-CHPqldcj.cjs +172 -0
  29. package/dist/catalog-CHPqldcj.cjs.map +1 -0
  30. package/dist/catalog-CIqpzgsM.d.cts +75 -0
  31. package/dist/catalog-CIqpzgsM.d.cts.map +1 -0
  32. package/dist/catalog-CIqpzgsM.d.ts +75 -0
  33. package/dist/catalog-CIqpzgsM.d.ts.map +1 -0
  34. package/dist/catalog-DqPhtCKZ.js +95 -0
  35. package/dist/catalog-DqPhtCKZ.js.map +1 -0
  36. package/dist/config-D6Tr7ev6.d.cts +95 -0
  37. package/dist/config-D6Tr7ev6.d.cts.map +1 -0
  38. package/dist/config-rl4_-VAq.d.ts +95 -0
  39. package/dist/config-rl4_-VAq.d.ts.map +1 -0
  40. package/dist/constants-BE1_9Tod.cjs +52 -0
  41. package/dist/constants-BE1_9Tod.cjs.map +1 -0
  42. package/dist/constants-BY7QZokc.js +29 -0
  43. package/dist/constants-BY7QZokc.js.map +1 -0
  44. package/dist/constants-CcbhOaAP.cjs +153 -0
  45. package/dist/constants-CcbhOaAP.cjs.map +1 -0
  46. package/dist/constants-rNuD5qJn.js +94 -0
  47. package/dist/constants-rNuD5qJn.js.map +1 -0
  48. package/dist/contracts/index.cjs +1006 -0
  49. package/dist/contracts/index.cjs.map +1 -0
  50. package/dist/contracts/index.d.cts +488 -0
  51. package/dist/contracts/index.d.cts.map +1 -0
  52. package/dist/contracts/index.d.ts +488 -0
  53. package/dist/contracts/index.d.ts.map +1 -0
  54. package/dist/contracts/index.js +817 -0
  55. package/dist/contracts/index.js.map +1 -0
  56. package/dist/cookies-DCIcr7uy.cjs +94 -0
  57. package/dist/cookies-DCIcr7uy.cjs.map +1 -0
  58. package/dist/cookies-DKEC7AWv.js +71 -0
  59. package/dist/cookies-DKEC7AWv.js.map +1 -0
  60. package/dist/delegated-token-CVNbMNfy.js +426 -0
  61. package/dist/delegated-token-CVNbMNfy.js.map +1 -0
  62. package/dist/delegated-token-DHSK4rHI.cjs +461 -0
  63. package/dist/delegated-token-DHSK4rHI.cjs.map +1 -0
  64. package/dist/error-helpers-BenWu-_u.d.ts +105 -0
  65. package/dist/error-helpers-BenWu-_u.d.ts.map +1 -0
  66. package/dist/error-helpers-KBHUbkOM.d.cts +105 -0
  67. package/dist/error-helpers-KBHUbkOM.d.cts.map +1 -0
  68. package/dist/error-helpers-XCh4ZJ-g.cjs +282 -0
  69. package/dist/error-helpers-XCh4ZJ-g.cjs.map +1 -0
  70. package/dist/error-helpers-lnwgNOw9.js +145 -0
  71. package/dist/error-helpers-lnwgNOw9.js.map +1 -0
  72. package/dist/error-messages-CGpW1fsg.d.cts +48 -0
  73. package/dist/error-messages-CGpW1fsg.d.cts.map +1 -0
  74. package/dist/error-messages-CGpW1fsg.d.ts +48 -0
  75. package/dist/error-messages-CGpW1fsg.d.ts.map +1 -0
  76. package/dist/event-codes-BBJHon-I.cjs +48 -0
  77. package/dist/event-codes-BBJHon-I.cjs.map +1 -0
  78. package/dist/event-codes-BgcJWsov.d.cts +42 -0
  79. package/dist/event-codes-BgcJWsov.d.cts.map +1 -0
  80. package/dist/event-codes-BgcJWsov.d.ts +42 -0
  81. package/dist/event-codes-BgcJWsov.d.ts.map +1 -0
  82. package/dist/event-codes-DR5_VlaR.js +43 -0
  83. package/dist/event-codes-DR5_VlaR.js.map +1 -0
  84. package/dist/generic/index.cjs +91 -0
  85. package/dist/generic/index.cjs.map +1 -0
  86. package/dist/generic/index.d.cts +27 -0
  87. package/dist/generic/index.d.cts.map +1 -0
  88. package/dist/generic/index.d.ts +27 -0
  89. package/dist/generic/index.d.ts.map +1 -0
  90. package/dist/generic/index.js +80 -0
  91. package/dist/generic/index.js.map +1 -0
  92. package/dist/hono/index.cjs +309 -0
  93. package/dist/hono/index.cjs.map +1 -0
  94. package/dist/hono/index.d.cts +272 -0
  95. package/dist/hono/index.d.cts.map +1 -0
  96. package/dist/hono/index.d.ts +272 -0
  97. package/dist/hono/index.d.ts.map +1 -0
  98. package/dist/hono/index.js +290 -0
  99. package/dist/hono/index.js.map +1 -0
  100. package/dist/hono-openapi/index.cjs +326 -0
  101. package/dist/hono-openapi/index.cjs.map +1 -0
  102. package/dist/hono-openapi/index.d.cts +14 -0
  103. package/dist/hono-openapi/index.d.cts.map +1 -0
  104. package/dist/hono-openapi/index.d.ts +14 -0
  105. package/dist/hono-openapi/index.d.ts.map +1 -0
  106. package/dist/hono-openapi/index.js +307 -0
  107. package/dist/hono-openapi/index.js.map +1 -0
  108. package/dist/http-client-BVF3iktR.cjs +211 -0
  109. package/dist/http-client-BVF3iktR.cjs.map +1 -0
  110. package/dist/http-client-Da0-OMfc.js +206 -0
  111. package/dist/http-client-Da0-OMfc.js.map +1 -0
  112. package/dist/index-BYzDaMR9.d.ts +312 -0
  113. package/dist/index-BYzDaMR9.d.ts.map +1 -0
  114. package/dist/index-CNNMCrdl.d.ts +66 -0
  115. package/dist/index-CNNMCrdl.d.ts.map +1 -0
  116. package/dist/index-DBZoLU4E.d.ts +240 -0
  117. package/dist/index-DBZoLU4E.d.ts.map +1 -0
  118. package/dist/index-DcvQWByo.d.cts +66 -0
  119. package/dist/index-DcvQWByo.d.cts.map +1 -0
  120. package/dist/index-Dold-Ycb.d.cts +1711 -0
  121. package/dist/index-Dold-Ycb.d.cts.map +1 -0
  122. package/dist/index-Dold-Ycb.d.ts +1711 -0
  123. package/dist/index-Dold-Ycb.d.ts.map +1 -0
  124. package/dist/index-jAO62-OD.d.cts +240 -0
  125. package/dist/index-jAO62-OD.d.cts.map +1 -0
  126. package/dist/index-o7nXcl7z.d.cts +312 -0
  127. package/dist/index-o7nXcl7z.d.cts.map +1 -0
  128. package/dist/index.cjs +89 -0
  129. package/dist/index.cjs.map +1 -0
  130. package/dist/index.d.cts +114 -0
  131. package/dist/index.d.cts.map +1 -0
  132. package/dist/index.d.ts +114 -0
  133. package/dist/index.d.ts.map +1 -0
  134. package/dist/index.js +28 -0
  135. package/dist/index.js.map +1 -0
  136. package/dist/jwt-BBNqk0TV.cjs +155 -0
  137. package/dist/jwt-BBNqk0TV.cjs.map +1 -0
  138. package/dist/jwt-DhqgH94B.js +150 -0
  139. package/dist/jwt-DhqgH94B.js.map +1 -0
  140. package/dist/key-resolver-CESqj4-P.cjs +45 -0
  141. package/dist/key-resolver-CESqj4-P.cjs.map +1 -0
  142. package/dist/key-resolver-D56I2Zpz.js +34 -0
  143. package/dist/key-resolver-D56I2Zpz.js.map +1 -0
  144. package/dist/parse-error-response-6qOQS5y9.cjs +316 -0
  145. package/dist/parse-error-response-6qOQS5y9.cjs.map +1 -0
  146. package/dist/parse-error-response-BM9-kjs0.js +239 -0
  147. package/dist/parse-error-response-BM9-kjs0.js.map +1 -0
  148. package/dist/path-segment-C25i6aaH.cjs +29 -0
  149. package/dist/path-segment-C25i6aaH.cjs.map +1 -0
  150. package/dist/path-segment-CyqnaFrP.js +24 -0
  151. package/dist/path-segment-CyqnaFrP.js.map +1 -0
  152. package/dist/react/index.cjs +336 -0
  153. package/dist/react/index.cjs.map +1 -0
  154. package/dist/react/index.d.cts +151 -0
  155. package/dist/react/index.d.cts.map +1 -0
  156. package/dist/react/index.d.ts +151 -0
  157. package/dist/react/index.d.ts.map +1 -0
  158. package/dist/react/index.js +300 -0
  159. package/dist/react/index.js.map +1 -0
  160. package/dist/refresh-dedup-CKaHHe7m.js +14 -0
  161. package/dist/refresh-dedup-CKaHHe7m.js.map +1 -0
  162. package/dist/refresh-dedup-CLdACQXR.cjs +19 -0
  163. package/dist/refresh-dedup-CLdACQXR.cjs.map +1 -0
  164. package/dist/rolldown-runtime-CmQyd0Gu.cjs +27 -0
  165. package/dist/routes-DpAzgY1V.cjs +424 -0
  166. package/dist/routes-DpAzgY1V.cjs.map +1 -0
  167. package/dist/routes-F1g5aVqP.js +347 -0
  168. package/dist/routes-F1g5aVqP.js.map +1 -0
  169. package/dist/s2s/index.cjs +24 -0
  170. package/dist/s2s/index.d.cts +5 -0
  171. package/dist/s2s/index.d.ts +5 -0
  172. package/dist/s2s/index.js +5 -0
  173. package/dist/s2s-6wbotr78.cjs +926 -0
  174. package/dist/s2s-6wbotr78.cjs.map +1 -0
  175. package/dist/s2s-B_0SIQzn.js +897 -0
  176. package/dist/s2s-B_0SIQzn.js.map +1 -0
  177. package/dist/sign-C7y6xdvT.cjs +324 -0
  178. package/dist/sign-C7y6xdvT.cjs.map +1 -0
  179. package/dist/sign-HFtcYwa-.js +259 -0
  180. package/dist/sign-HFtcYwa-.js.map +1 -0
  181. package/dist/tokens-C1nzkn21.cjs +232 -0
  182. package/dist/tokens-C1nzkn21.cjs.map +1 -0
  183. package/dist/tokens-C3Z40qd7.js +107 -0
  184. package/dist/tokens-C3Z40qd7.js.map +1 -0
  185. package/dist/types-B5sf7kKE.d.cts +52 -0
  186. package/dist/types-B5sf7kKE.d.cts.map +1 -0
  187. package/dist/types-CLOIHzRu.d.ts +96 -0
  188. package/dist/types-CLOIHzRu.d.ts.map +1 -0
  189. package/dist/types-CQTZdZIF.d.ts +52 -0
  190. package/dist/types-CQTZdZIF.d.ts.map +1 -0
  191. package/dist/types-DGeQ8j4k.d.cts +538 -0
  192. package/dist/types-DGeQ8j4k.d.cts.map +1 -0
  193. package/dist/types-DIUWza9-.d.ts +538 -0
  194. package/dist/types-DIUWza9-.d.ts.map +1 -0
  195. package/dist/types-qh6ANBCV.d.cts +96 -0
  196. package/dist/types-qh6ANBCV.d.cts.map +1 -0
  197. package/dist/webhooks/index.cjs +8 -0
  198. package/dist/webhooks/index.d.cts +5 -0
  199. package/dist/webhooks/index.d.ts +5 -0
  200. package/dist/webhooks/index.js +4 -0
  201. package/dist/webhooks-B5sAWC9W.js +74 -0
  202. package/dist/webhooks-B5sAWC9W.js.map +1 -0
  203. package/dist/webhooks-Cx11psg1.cjs +79 -0
  204. package/dist/webhooks-Cx11psg1.cjs.map +1 -0
  205. package/package.json +192 -3
@@ -0,0 +1,259 @@
1
+ import { o as INTERNAL_HEADERS } from "./constants-rNuD5qJn.js";
2
+ // src/s2s/constants.ts
3
+ /**
4
+ * Constantes del módulo S2S (service-to-service).
5
+ *
6
+ * REQ-S2S-05 LOCKED: la ventana de tiempo para el timestamp S2S es de 120 segundos.
7
+ */
8
+ /**
9
+ * Ventana máxima (en segundos) para aceptar un request S2S.
10
+ * Si |serverTime - timestamp| > S2S_TIMESTAMP_WINDOW_SECONDS → firma rechazada.
11
+ */
12
+ const S2S_TIMESTAMP_WINDOW_SECONDS = 120;
13
+ /**
14
+ * Formato canónico del nonce S2S (`x-eva-nonce`): 16 bytes aleatorios como 32 hex en minúsculas.
15
+ * Sin flag `/i`: el verificador rechaza variantes no canónicas en vez de normalizarlas. Es el
16
+ * contrato canónico y defensa en profundidad: una implementación que normalizara el valor
17
+ * podría derivar claves de replay distintas del valor realmente firmado. (Reescribirlo en
18
+ * mayúsculas no evade nada por sí solo: el nonce va en el canonical firmado y rompería el HMAC.)
19
+ * Uso interno: no se exporta desde el barrel.
20
+ */
21
+ const S2S_NONCE_REGEX = /^[0-9a-f]{32}$/;
22
+ /**
23
+ * Permisos de la audiencia `auth-api`, tal como los concede el Auth Service a un service client.
24
+ *
25
+ * Se mantiene como objeto del SDK (`S2S_SCOPES.USERS_READ`) pero sus valores deben ser miembros del
26
+ * catálogo `SERVICE_AUDIENCE_SCOPES['auth-api']` del contrato: `satisfies` lo comprueba en
27
+ * compilación. `admin` no está: la superficie `/admin` de Auth se firma, no usa tokens.
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * import { S2S_SCOPES } from '@eva_solutions/auth-sdk/s2s'
32
+ *
33
+ * const scope = [S2S_SCOPES.USERS_READ, S2S_SCOPES.EMPRESAS_ESCRIBIR].join(' ')
34
+ * ```
35
+ */
36
+ const S2S_SCOPES = {
37
+ USERS_READ: "users:read",
38
+ WEBHOOKS_READ: "webhooks:read",
39
+ WEBHOOKS_WRITE: "webhooks:write",
40
+ EMPRESAS_LEER: "empresas:leer",
41
+ EMPRESAS_ESCRIBIR: "empresas:escribir",
42
+ TOKENS_EXCHANGE: "tokens:exchange",
43
+ CONTRATACIONES_PEDIR: "contrataciones:pedir",
44
+ CONTRATACIONES_ESCRIBIR: "contrataciones:escribir",
45
+ CONTRATACIONES_LEER: "contrataciones:leer",
46
+ EMPRESAS_BAJA: "empresas:baja",
47
+ AUTORIZACIONES_ESCRIBIR: "autorizaciones:escribir",
48
+ AUTORIZACIONES_LEER: "autorizaciones:leer",
49
+ DIRECTORIO_LEER: "directorio:leer"
50
+ };
51
+ /**
52
+ * Header de respuesta que el Auth Service incluye en cada respuesta S2S
53
+ * con la hora del servidor (Unix timestamp en segundos como string).
54
+ *
55
+ * @example
56
+ * ```ts
57
+ * import { S2S_RESPONSE_HEADERS } from '@eva_solutions/auth-sdk/s2s'
58
+ *
59
+ * const serverTime = response.headers.get(S2S_RESPONSE_HEADERS.SERVER_TIME)
60
+ * ```
61
+ */
62
+ const S2S_RESPONSE_HEADERS = { SERVER_TIME: INTERNAL_HEADERS.X_EVA_SERVER_TIME };
63
+ /**
64
+ * Vida en milisegundos del caché de `checkAutorizacion` en el cliente S2S (30 s). Una revocación o
65
+ * la baja de una empresa tardan como máximo esto en notarse en un servicio que verifica; así
66
+ * está declarado en el diseño.
67
+ */
68
+ const AUTORIZACION_CACHE_TTL_MS = 3e4;
69
+ // src/s2s/errors.ts
70
+ /**
71
+ * Errores internos del módulo S2S. No se exportan desde el barrel público.
72
+ */
73
+ /**
74
+ * El query string tiene percent-encoding malformado (p. ej. `%ZZ`) y no se puede
75
+ * canonicalizar. El firmante la deja propagar con su mensaje claro; el verificador es el
76
+ * único que la captura (la trata como `signature_invalid`) y relanza cualquier otro error.
77
+ */
78
+ var S2SMalformedQueryError = class extends Error {
79
+ constructor() {
80
+ super("[eva-auth-sdk] s2s: rawQuery inválido (percent-encoding malformado)");
81
+ this.name = "S2SMalformedQueryError";
82
+ }
83
+ };
84
+ // src/s2s/sign.ts
85
+ /**
86
+ * Helpers de firma HMAC-SHA-256 SigV4-style para requests S2S.
87
+ *
88
+ * REQ-S2S-02, REQ-S2S-03 LOCKED.
89
+ *
90
+ * Algoritmo canónico (este SDK es el dueño del contrato; el servidor lo verifica con
91
+ * `verifyS2SRequest`):
92
+ * canonical = [METHOD, PATH, CANONICAL_QUERY, TIMESTAMP, NONCE, CLIENT_ID, BODY_HASH].join('\n')
93
+ *
94
+ * Usa Web Crypto API (`crypto.subtle`) — isomorfo (browser + worker + Node 20+).
95
+ *
96
+ * D-12 LOCKED: hexToBytes y sha256Hex se duplican aquí (NO se extraen a shared)
97
+ * para que el entry point ./s2s sea completamente tree-shakeable.
98
+ */
99
+ const encoder = new TextEncoder();
100
+ const HEX_REGEX = /^[0-9a-f]+$/i;
101
+ /**
102
+ * Decodifica hex string a Uint8Array.
103
+ * Retorna null si la longitud es impar o contiene chars no-hex.
104
+ */
105
+ function hexToBytes(hex) {
106
+ if (hex.length === 0 || hex.length % 2 !== 0 || !HEX_REGEX.test(hex)) return null;
107
+ const bytes = new Uint8Array(hex.length / 2);
108
+ for (let i = 0; i < hex.length; i += 2) bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16);
109
+ return bytes;
110
+ }
111
+ /**
112
+ * SHA-256 hex lowercase de un string o Uint8Array.
113
+ * Acepta string (encodea como UTF-8) o Uint8Array (bytes raw — preferido para body).
114
+ */
115
+ async function sha256Hex(data) {
116
+ const bytes = typeof data === "string" ? encoder.encode(data) : data;
117
+ const digest = await crypto.subtle.digest("SHA-256", bytes);
118
+ return Array.from(new Uint8Array(digest)).map((b) => b.toString(16).padStart(2, "0")).join("");
119
+ }
120
+ /**
121
+ * Encoding RFC 3986 estricto.
122
+ * `encodeURIComponent` no codifica `! * ' ( )` — esta función sí.
123
+ */
124
+ function uriEncodeRFC3986(input) {
125
+ return encodeURIComponent(input).replace(/[!*'()]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);
126
+ }
127
+ /**
128
+ * Canonicaliza el query string:
129
+ * 1. Split por `&`.
130
+ * 2. Decodificar name/value con `decodeURIComponent`.
131
+ * 3. Ordenar por (name, value) alfabético.
132
+ * 4. Re-encodear con `uriEncodeRFC3986`.
133
+ * 5. Join con `=` y `&`.
134
+ * Query vacío → `""`.
135
+ */
136
+ function canonicalizeQuery(rawQuery) {
137
+ if (!rawQuery) return "";
138
+ const pairs = [];
139
+ for (const pair of rawQuery.split("&")) {
140
+ if (pair === "") continue;
141
+ const idx = pair.indexOf("=");
142
+ if (idx === -1) pairs.push({
143
+ name: decodeURIComponent(pair),
144
+ value: ""
145
+ });
146
+ else pairs.push({
147
+ name: decodeURIComponent(pair.slice(0, idx)),
148
+ value: decodeURIComponent(pair.slice(idx + 1))
149
+ });
150
+ }
151
+ pairs.sort((a, b) => {
152
+ if (a.name < b.name) return -1;
153
+ if (a.name > b.name) return 1;
154
+ if (a.value < b.value) return -1;
155
+ if (a.value > b.value) return 1;
156
+ return 0;
157
+ });
158
+ return pairs.map(({ name, value }) => `${uriEncodeRFC3986(name)}=${uriEncodeRFC3986(value)}`).join("&");
159
+ }
160
+ /**
161
+ * SHA-256 hex de string vacío (precomputado).
162
+ * Constante usada cuando el body es vacío — evita hash innecesario.
163
+ * Exportado para uso externo (REQ-S2S-02 LOCKED).
164
+ */
165
+ const EMPTY_BODY_SHA256_HEX = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
166
+ /**
167
+ * Genera un nonce S2S: 16 bytes de `crypto.getRandomValues` como 32 hex en minúsculas.
168
+ * Es el valor del header `x-eva-nonce`; cada request debe llevar uno nuevo.
169
+ */
170
+ function generateS2SNonce() {
171
+ const bytes = crypto.getRandomValues(/* @__PURE__ */ new Uint8Array(16));
172
+ return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
173
+ }
174
+ /**
175
+ * Construye el canonical string de 7 líneas (SigV4-style).
176
+ *
177
+ * Formato EXACTO:
178
+ * {METHOD}\n{PATH}\n{CANONICAL_QUERY}\n{TIMESTAMP}\n{NONCE}\n{CLIENT_ID}\n{BODY_HASH}
179
+ *
180
+ * @param parts - Componentes del request a firmar.
181
+ */
182
+ async function buildS2SCanonicalString(parts) {
183
+ const METHOD = parts.method.toUpperCase();
184
+ const PATH = parts.path;
185
+ const TIMESTAMP = parts.timestamp;
186
+ const NONCE = parts.nonce;
187
+ const CLIENT_ID = parts.clientId;
188
+ const BODY_HASH = parts.bodyBytes.length === 0 ? EMPTY_BODY_SHA256_HEX : await sha256Hex(parts.bodyBytes);
189
+ let CANONICAL_QUERY;
190
+ try {
191
+ CANONICAL_QUERY = canonicalizeQuery(parts.rawQuery);
192
+ } catch (err) {
193
+ if (err instanceof URIError) throw new S2SMalformedQueryError();
194
+ throw err;
195
+ }
196
+ return [
197
+ METHOD,
198
+ PATH,
199
+ CANONICAL_QUERY,
200
+ TIMESTAMP,
201
+ NONCE,
202
+ CLIENT_ID,
203
+ BODY_HASH
204
+ ].join("\n");
205
+ }
206
+ /**
207
+ * Genera la firma HMAC-SHA-256 del canonical string.
208
+ *
209
+ * @returns String con formato `"sha256=${hexLowercase}"`.
210
+ * @throws Si `secretHex` tiene formato inválido (longitud impar o chars no-hex).
211
+ * @throws Si `parts.nonce` no es un nonce canónico (32 hex en minúsculas).
212
+ */
213
+ async function signS2SRequest({ parts, secretHex }) {
214
+ if (!S2S_NONCE_REGEX.test(parts.nonce)) throw new Error("[eva-auth-sdk] s2s: nonce inválido (se requieren 32 hex en minúsculas)");
215
+ const canonical = await buildS2SCanonicalString(parts);
216
+ const keyBytes = hexToBytes(secretHex);
217
+ if (keyBytes === null) throw new Error("[eva-auth-sdk] s2s: secretHex inválido (formato hex requerido)");
218
+ const cryptoKey = await crypto.subtle.importKey("raw", keyBytes.buffer, {
219
+ name: "HMAC",
220
+ hash: "SHA-256"
221
+ }, false, ["sign"]);
222
+ const sig = await crypto.subtle.sign("HMAC", cryptoKey, encoder.encode(canonical));
223
+ return `sha256=${Array.from(new Uint8Array(sig)).map((b) => b.toString(16).padStart(2, "0")).join("")}`;
224
+ }
225
+ /**
226
+ * Genera los 4 headers de autenticación S2S para un request: client id, timestamp (segundos),
227
+ * nonce y firma. Es el único punto que genera timestamp + nonce y firma; `createS2SClient` lo
228
+ * usa y los firmantes manuales deben usarlo en vez de armar los headers a mano.
229
+ *
230
+ * El nonce es nuevo en cada llamada: no reutilices los headers devueltos en otro request.
231
+ *
232
+ * @param rawQuery - Query string crudo sin `?`. Default `''`.
233
+ * @param bodyBytes - Bytes EXACTOS que se enviarán como body. Default: vacío.
234
+ * @throws Si `secretHex` tiene formato inválido.
235
+ */
236
+ async function signS2SHeaders({ method, path, rawQuery = "", bodyBytes = /* @__PURE__ */ new Uint8Array(0), clientId, secretHex }) {
237
+ const timestamp = String(Math.floor(Date.now() / 1e3));
238
+ const nonce = generateS2SNonce();
239
+ return {
240
+ "x-eva-client-id": clientId,
241
+ "x-eva-timestamp": timestamp,
242
+ "x-eva-nonce": nonce,
243
+ "x-eva-signature": await signS2SRequest({
244
+ parts: {
245
+ method,
246
+ path,
247
+ rawQuery,
248
+ timestamp,
249
+ nonce,
250
+ clientId,
251
+ bodyBytes
252
+ },
253
+ secretHex
254
+ })
255
+ };
256
+ }
257
+ export { signS2SRequest as a, S2S_NONCE_REGEX as c, S2S_TIMESTAMP_WINDOW_SECONDS as d, signS2SHeaders as i, S2S_RESPONSE_HEADERS as l, buildS2SCanonicalString as n, S2SMalformedQueryError as o, generateS2SNonce as r, AUTORIZACION_CACHE_TTL_MS as s, EMPTY_BODY_SHA256_HEX as t, S2S_SCOPES as u };
258
+
259
+ //# sourceMappingURL=sign-HFtcYwa-.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sign-HFtcYwa-.js","names":[],"sources":["../src/s2s/constants.ts","../src/s2s/errors.ts","../src/s2s/sign.ts"],"sourcesContent":["/**\n * Constantes del módulo S2S (service-to-service).\n *\n * REQ-S2S-05 LOCKED: la ventana de tiempo para el timestamp S2S es de 120 segundos.\n */\n\nimport { INTERNAL_HEADERS } from '@eva_solutions/auth-contracts'\nimport type { ServiceScope } from '@eva_solutions/auth-contracts'\n\n/**\n * Ventana máxima (en segundos) para aceptar un request S2S.\n * Si |serverTime - timestamp| > S2S_TIMESTAMP_WINDOW_SECONDS → firma rechazada.\n */\nexport const S2S_TIMESTAMP_WINDOW_SECONDS = 120\n\n/**\n * Formato canónico del nonce S2S (`x-eva-nonce`): 16 bytes aleatorios como 32 hex en minúsculas.\n * Sin flag `/i`: el verificador rechaza variantes no canónicas en vez de normalizarlas. Es el\n * contrato canónico y defensa en profundidad: una implementación que normalizara el valor\n * podría derivar claves de replay distintas del valor realmente firmado. (Reescribirlo en\n * mayúsculas no evade nada por sí solo: el nonce va en el canonical firmado y rompería el HMAC.)\n * Uso interno: no se exporta desde el barrel.\n */\nexport const S2S_NONCE_REGEX = /^[0-9a-f]{32}$/\n\n/**\n * Máximo de IDs permitidos por llamada a `batchUsers`.\n * Si se superan, el cliente retorna un error sin hacer fetch al API.\n *\n * Re-export del contrato compartido: el tope NO está en el schema del request (un máximo ahí\n * cambiaría el documento OpenAPI publicado), lo aplica quien lo consume leyendo esta constante.\n */\nexport { USERS_BATCH_MAX_IDS } from '@eva_solutions/auth-contracts'\n\n/**\n * Permisos de la audiencia `auth-api`, tal como los concede el Auth Service a un service client.\n *\n * Se mantiene como objeto del SDK (`S2S_SCOPES.USERS_READ`) pero sus valores deben ser miembros del\n * catálogo `SERVICE_AUDIENCE_SCOPES['auth-api']` del contrato: `satisfies` lo comprueba en\n * compilación. `admin` no está: la superficie `/admin` de Auth se firma, no usa tokens.\n *\n * @example\n * ```ts\n * import { S2S_SCOPES } from '@eva_solutions/auth-sdk/s2s'\n *\n * const scope = [S2S_SCOPES.USERS_READ, S2S_SCOPES.EMPRESAS_ESCRIBIR].join(' ')\n * ```\n */\nexport const S2S_SCOPES = {\n USERS_READ: 'users:read',\n WEBHOOKS_READ: 'webhooks:read',\n WEBHOOKS_WRITE: 'webhooks:write',\n EMPRESAS_LEER: 'empresas:leer',\n EMPRESAS_ESCRIBIR: 'empresas:escribir',\n TOKENS_EXCHANGE: 'tokens:exchange',\n CONTRATACIONES_PEDIR: 'contrataciones:pedir',\n CONTRATACIONES_ESCRIBIR: 'contrataciones:escribir',\n CONTRATACIONES_LEER: 'contrataciones:leer',\n EMPRESAS_BAJA: 'empresas:baja',\n AUTORIZACIONES_ESCRIBIR: 'autorizaciones:escribir',\n AUTORIZACIONES_LEER: 'autorizaciones:leer',\n DIRECTORIO_LEER: 'directorio:leer',\n} as const satisfies Record<string, ServiceScope<'auth-api'>>\n\n/** Unión de literales de todos los permisos de la audiencia `auth-api`. */\nexport type S2SScope = (typeof S2S_SCOPES)[keyof typeof S2S_SCOPES]\n\n/**\n * Header de respuesta que el Auth Service incluye en cada respuesta S2S\n * con la hora del servidor (Unix timestamp en segundos como string).\n *\n * @example\n * ```ts\n * import { S2S_RESPONSE_HEADERS } from '@eva_solutions/auth-sdk/s2s'\n *\n * const serverTime = response.headers.get(S2S_RESPONSE_HEADERS.SERVER_TIME)\n * ```\n */\nexport const S2S_RESPONSE_HEADERS = {\n SERVER_TIME: INTERNAL_HEADERS.X_EVA_SERVER_TIME,\n} as const\n\n/**\n * Vida en milisegundos del caché de `checkAutorizacion` en el cliente S2S (30 s). Una revocación o\n * la baja de una empresa tardan como máximo esto en notarse en un servicio que verifica; así\n * está declarado en el diseño.\n */\nexport const AUTORIZACION_CACHE_TTL_MS = 30_000\n","/**\n * Errores internos del módulo S2S. No se exportan desde el barrel público.\n */\n\n/**\n * El query string tiene percent-encoding malformado (p. ej. `%ZZ`) y no se puede\n * canonicalizar. El firmante la deja propagar con su mensaje claro; el verificador es el\n * único que la captura (la trata como `signature_invalid`) y relanza cualquier otro error.\n */\nexport class S2SMalformedQueryError extends Error {\n constructor() {\n super('[eva-auth-sdk] s2s: rawQuery inválido (percent-encoding malformado)')\n this.name = 'S2SMalformedQueryError'\n }\n}\n","/**\n * Helpers de firma HMAC-SHA-256 SigV4-style para requests S2S.\n *\n * REQ-S2S-02, REQ-S2S-03 LOCKED.\n *\n * Algoritmo canónico (este SDK es el dueño del contrato; el servidor lo verifica con\n * `verifyS2SRequest`):\n * canonical = [METHOD, PATH, CANONICAL_QUERY, TIMESTAMP, NONCE, CLIENT_ID, BODY_HASH].join('\\n')\n *\n * Usa Web Crypto API (`crypto.subtle`) — isomorfo (browser + worker + Node 20+).\n *\n * D-12 LOCKED: hexToBytes y sha256Hex se duplican aquí (NO se extraen a shared)\n * para que el entry point ./s2s sea completamente tree-shakeable.\n */\n\nimport { S2S_NONCE_REGEX } from './constants'\nimport { S2SMalformedQueryError } from './errors'\nimport type { S2SCanonicalParts } from './types'\n\n// ---------------------------------------------------------------------------\n// Helpers criptográficos locales (D-12 LOCKED — no exportar, no extraer)\n// ---------------------------------------------------------------------------\n\nconst encoder = new TextEncoder()\nconst HEX_REGEX = /^[0-9a-f]+$/i\n\n/**\n * Decodifica hex string a Uint8Array.\n * Retorna null si la longitud es impar o contiene chars no-hex.\n */\nfunction hexToBytes(hex: string): Uint8Array | null {\n if (hex.length === 0 || hex.length % 2 !== 0 || !HEX_REGEX.test(hex)) {\n return null\n }\n const bytes = new Uint8Array(hex.length / 2)\n for (let i = 0; i < hex.length; i += 2) {\n bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16)\n }\n return bytes\n}\n\n/**\n * SHA-256 hex lowercase de un string o Uint8Array.\n * Acepta string (encodea como UTF-8) o Uint8Array (bytes raw — preferido para body).\n */\nasync function sha256Hex(data: string | Uint8Array): Promise<string> {\n const bytes = typeof data === 'string' ? encoder.encode(data) : data\n const digest = await crypto.subtle.digest('SHA-256', bytes as BufferSource)\n return Array.from(new Uint8Array(digest))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')\n}\n\n/**\n * Encoding RFC 3986 estricto.\n * `encodeURIComponent` no codifica `! * ' ( )` — esta función sí.\n */\nfunction uriEncodeRFC3986(input: string): string {\n return encodeURIComponent(input).replace(\n /[!*'()]/g,\n (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`,\n )\n}\n\n/**\n * Canonicaliza el query string:\n * 1. Split por `&`.\n * 2. Decodificar name/value con `decodeURIComponent`.\n * 3. Ordenar por (name, value) alfabético.\n * 4. Re-encodear con `uriEncodeRFC3986`.\n * 5. Join con `=` y `&`.\n * Query vacío → `\"\"`.\n */\nfunction canonicalizeQuery(rawQuery: string): string {\n if (!rawQuery) return ''\n\n const pairs: Array<{ name: string; value: string }> = []\n for (const pair of rawQuery.split('&')) {\n if (pair === '') continue\n const idx = pair.indexOf('=')\n if (idx === -1) {\n pairs.push({ name: decodeURIComponent(pair), value: '' })\n } else {\n pairs.push({\n name: decodeURIComponent(pair.slice(0, idx)),\n value: decodeURIComponent(pair.slice(idx + 1)),\n })\n }\n }\n\n pairs.sort((a, b) => {\n if (a.name < b.name) return -1\n if (a.name > b.name) return 1\n if (a.value < b.value) return -1\n if (a.value > b.value) return 1\n return 0\n })\n\n return pairs\n .map(\n ({ name, value }) =>\n `${uriEncodeRFC3986(name)}=${uriEncodeRFC3986(value)}`,\n )\n .join('&')\n}\n\n// ---------------------------------------------------------------------------\n// API pública\n// ---------------------------------------------------------------------------\n\n/**\n * SHA-256 hex de string vacío (precomputado).\n * Constante usada cuando el body es vacío — evita hash innecesario.\n * Exportado para uso externo (REQ-S2S-02 LOCKED).\n */\nexport const EMPTY_BODY_SHA256_HEX =\n 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'\n\n/**\n * Genera un nonce S2S: 16 bytes de `crypto.getRandomValues` como 32 hex en minúsculas.\n * Es el valor del header `x-eva-nonce`; cada request debe llevar uno nuevo.\n */\nexport function generateS2SNonce(): string {\n const bytes = crypto.getRandomValues(new Uint8Array(16))\n return Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('')\n}\n\n/**\n * Construye el canonical string de 7 líneas (SigV4-style).\n *\n * Formato EXACTO:\n * {METHOD}\\n{PATH}\\n{CANONICAL_QUERY}\\n{TIMESTAMP}\\n{NONCE}\\n{CLIENT_ID}\\n{BODY_HASH}\n *\n * @param parts - Componentes del request a firmar.\n */\nexport async function buildS2SCanonicalString(\n parts: S2SCanonicalParts,\n): Promise<string> {\n const METHOD = parts.method.toUpperCase()\n const PATH = parts.path\n const TIMESTAMP = parts.timestamp\n const NONCE = parts.nonce\n const CLIENT_ID = parts.clientId\n // El body se hashea ANTES de canonicalizar el query: si el query es inválido, el\n // verificador ya hizo el mismo trabajo que en una petición válida (tiempo comparable).\n const BODY_HASH =\n parts.bodyBytes.length === 0\n ? EMPTY_BODY_SHA256_HEX\n : await sha256Hex(parts.bodyBytes)\n let CANONICAL_QUERY: string\n try {\n CANONICAL_QUERY = canonicalizeQuery(parts.rawQuery)\n } catch (err) {\n if (err instanceof URIError) {\n throw new S2SMalformedQueryError()\n }\n throw err\n }\n\n return [\n METHOD,\n PATH,\n CANONICAL_QUERY,\n TIMESTAMP,\n NONCE,\n CLIENT_ID,\n BODY_HASH,\n ].join('\\n')\n}\n\n/**\n * Genera la firma HMAC-SHA-256 del canonical string.\n *\n * @returns String con formato `\"sha256=${hexLowercase}\"`.\n * @throws Si `secretHex` tiene formato inválido (longitud impar o chars no-hex).\n * @throws Si `parts.nonce` no es un nonce canónico (32 hex en minúsculas).\n */\nexport async function signS2SRequest({\n parts,\n secretHex,\n}: {\n parts: S2SCanonicalParts\n secretHex: string\n}): Promise<string> {\n if (!S2S_NONCE_REGEX.test(parts.nonce)) {\n throw new Error(\n '[eva-auth-sdk] s2s: nonce inválido (se requieren 32 hex en minúsculas)',\n )\n }\n\n const canonical = await buildS2SCanonicalString(parts)\n\n const keyBytes = hexToBytes(secretHex)\n if (keyBytes === null) {\n throw new Error(\n '[eva-auth-sdk] s2s: secretHex inválido (formato hex requerido)',\n )\n }\n\n const cryptoKey = await crypto.subtle.importKey(\n 'raw',\n keyBytes.buffer as BufferSource,\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign'],\n )\n\n const sig = await crypto.subtle.sign(\n 'HMAC',\n cryptoKey,\n encoder.encode(canonical) as BufferSource,\n )\n\n const hexSig = Array.from(new Uint8Array(sig))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')\n\n return `sha256=${hexSig}`\n}\n\n/**\n * Genera los 4 headers de autenticación S2S para un request: client id, timestamp (segundos),\n * nonce y firma. Es el único punto que genera timestamp + nonce y firma; `createS2SClient` lo\n * usa y los firmantes manuales deben usarlo en vez de armar los headers a mano.\n *\n * El nonce es nuevo en cada llamada: no reutilices los headers devueltos en otro request.\n *\n * @param rawQuery - Query string crudo sin `?`. Default `''`.\n * @param bodyBytes - Bytes EXACTOS que se enviarán como body. Default: vacío.\n * @throws Si `secretHex` tiene formato inválido.\n */\nexport async function signS2SHeaders({\n method,\n path,\n rawQuery = '',\n bodyBytes = new Uint8Array(0),\n clientId,\n secretHex,\n}: {\n method: string\n path: string\n rawQuery?: string\n bodyBytes?: Uint8Array\n clientId: string\n secretHex: string\n}): Promise<Record<string, string>> {\n const timestamp = String(Math.floor(Date.now() / 1000))\n const nonce = generateS2SNonce()\n const signature = await signS2SRequest({\n parts: { method, path, rawQuery, timestamp, nonce, clientId, bodyBytes },\n secretHex,\n })\n\n return {\n 'x-eva-client-id': clientId,\n 'x-eva-timestamp': timestamp,\n 'x-eva-nonce': nonce,\n 'x-eva-signature': signature,\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,232 @@
1
+ // ../auth-contracts/dist/tokens.js
2
+ /**
3
+ * PURE module: it must never reference `zod` or any schema module of this package (see
4
+ * `constants.ts`). Token vocabulary shared by the Auth service and every consumer: issuer, token
5
+ * types, key prefixes, lifetimes and the token endpoint error codes.
6
+ */
7
+ /** Issuer (`iss`) of every token the Auth service signs. */
8
+ const TOKEN_ISSUER = "auth-service";
9
+ /**
10
+ * Service client slugs nobody can create: the token issuer name (an `iss`-like value would let a
11
+ * client pass for the service itself).
12
+ */
13
+ const RESERVED_SERVICE_CLIENT_SLUGS = [TOKEN_ISSUER];
14
+ /** True when `slug` is reserved and cannot be used as a service client slug. */
15
+ function isReservedServiceClientSlug(slug) {
16
+ return RESERVED_SERVICE_CLIENT_SLUGS.includes(slug);
17
+ }
18
+ /**
19
+ * Fixed id (`sub`) of the Auth service itself when it mints its own service tokens (the OTP send).
20
+ * Receivers register it like any other service client id.
21
+ */
22
+ const AUTH_SERVICE_SUB = "00000000-0000-4000-8000-000000000001";
23
+ /** Header `typ` of a user access token (RFC 9068). */
24
+ const USER_TOKEN_TYP = "at+jwt";
25
+ /** Header `typ` of a service access token. Distinct from the user one on purpose (RFC 8725 3.11). */
26
+ const SERVICE_TOKEN_TYP = "svc-at+jwt";
27
+ /** The `kid` of a user signing key starts with this prefix. */
28
+ const USER_KID_PREFIX = "usr-";
29
+ /** The `kid` of a service signing key starts with this prefix. */
30
+ const SERVICE_KID_PREFIX = "svc-";
31
+ /** Lifetime in seconds of a service token obtained from the token endpoint. */
32
+ const SERVICE_TOKEN_LIFETIME_SECONDS = 300;
33
+ /** Lifetime in seconds of the single-use service token Auth mints in-process per OTP send. */
34
+ const INTERNAL_SERVICE_TOKEN_LIFETIME_SECONDS = 60;
35
+ /**
36
+ * Error codes of the token endpoint (RFC 6749 5.2 and RFC 8707 2). Throttling a client has no
37
+ * code of its own: it answers `429` with `temporarily_unavailable` and a `Retry-After` header (the
38
+ * SDK token provider reads both).
39
+ */
40
+ const SERVICE_TOKEN_ERROR_CODES = [
41
+ "invalid_request",
42
+ "invalid_client",
43
+ "invalid_target",
44
+ "invalid_scope",
45
+ "temporarily_unavailable"
46
+ ];
47
+ /**
48
+ * Header `typ` of a delegated access token (token exchange, RFC 8693). A third type, distinct from
49
+ * the user and service ones: it is signed with a SERVICE key (`svc-` kid) but no service verifier
50
+ * accepts it, and the delegated verifier accepts nothing else.
51
+ */
52
+ const DELEGATED_TOKEN_TYP = "dlg-at+jwt";
53
+ /** Lifetime in seconds of a delegated token (`exp` never exceeds the one of the subject token). */
54
+ const DELEGATED_TOKEN_LIFETIME_SECONDS = 120;
55
+ /**
56
+ * Most levels the `act` (actor) chain of a delegated token can have. A delegated token that
57
+ * already has this many levels cannot be exchanged again.
58
+ */
59
+ const DELEGATED_TOKEN_MAX_DEPTH = 3;
60
+ /** `grant_type` of the token exchange request (RFC 8693 2.1). */
61
+ const TOKEN_EXCHANGE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:token-exchange";
62
+ /**
63
+ * Token type identifier for `subject_token_type` (what is exchanged) and `issued_token_type` (what
64
+ * comes back): both are JWT access tokens (RFC 8693 3).
65
+ */
66
+ const ACCESS_TOKEN_TYPE = "urn:ietf:params:oauth:token-type:access_token";
67
+ /**
68
+ * Header with which a service sends the access token of a person on the requests that cannot carry
69
+ * a body (the `GET` that needs a person's role). Every other person-bound request carries it as
70
+ * `subjectToken` in the body.
71
+ */
72
+ const SUBJECT_TOKEN_HEADER = "x-eva-subject-token";
73
+ /**
74
+ * Error codes of the token exchange endpoint (RFC 6749 5.2, RFC 8693 2.2.2 and RFC 8707 2).
75
+ * `invalid_grant`: the subject token or what it depends on (session, user, membership, company,
76
+ * contract, depth, cycle) is not valid. Throttling answers `429` with `temporarily_unavailable`.
77
+ */
78
+ const TOKEN_EXCHANGE_ERROR_CODES = [
79
+ "invalid_request",
80
+ "invalid_client",
81
+ "invalid_grant",
82
+ "invalid_target",
83
+ "invalid_scope",
84
+ "temporarily_unavailable"
85
+ ];
86
+ /**
87
+ * Failure of the PERSON's token (`subjectToken`) on a person-bound request: invalid, expired, of
88
+ * another product, or its session/user is gone. It answers `403` with this code, never `401`: a
89
+ * `401` on `/internal/*` means the service Bearer was rejected (the S2S client then drops its
90
+ * service token and retries once), and a bad person token must not trigger that.
91
+ */
92
+ const SUBJECT_TOKEN_INVALID_STATUS = 403;
93
+ const SUBJECT_TOKEN_INVALID_CODE = "subject_token_invalid";
94
+ /**
95
+ * Keys that carry a person or service token in bodies, headers and token endpoint answers. The
96
+ * Auth API redacts them in logs and audit records. It is ADDED to the consumer's own redaction
97
+ * list (which already covers `refresh_token`, `authorization` and the like); it does not replace it.
98
+ */
99
+ const TOKEN_BEARING_KEYS = [
100
+ "subjectToken",
101
+ "subject_token",
102
+ "x-eva-subject-token",
103
+ "access_token"
104
+ ];
105
+ Object.defineProperty(exports, "ACCESS_TOKEN_TYPE", {
106
+ enumerable: true,
107
+ get: function() {
108
+ return ACCESS_TOKEN_TYPE;
109
+ }
110
+ });
111
+ Object.defineProperty(exports, "AUTH_SERVICE_SUB", {
112
+ enumerable: true,
113
+ get: function() {
114
+ return AUTH_SERVICE_SUB;
115
+ }
116
+ });
117
+ Object.defineProperty(exports, "DELEGATED_TOKEN_LIFETIME_SECONDS", {
118
+ enumerable: true,
119
+ get: function() {
120
+ return DELEGATED_TOKEN_LIFETIME_SECONDS;
121
+ }
122
+ });
123
+ Object.defineProperty(exports, "DELEGATED_TOKEN_MAX_DEPTH", {
124
+ enumerable: true,
125
+ get: function() {
126
+ return DELEGATED_TOKEN_MAX_DEPTH;
127
+ }
128
+ });
129
+ Object.defineProperty(exports, "DELEGATED_TOKEN_TYP", {
130
+ enumerable: true,
131
+ get: function() {
132
+ return DELEGATED_TOKEN_TYP;
133
+ }
134
+ });
135
+ Object.defineProperty(exports, "INTERNAL_SERVICE_TOKEN_LIFETIME_SECONDS", {
136
+ enumerable: true,
137
+ get: function() {
138
+ return INTERNAL_SERVICE_TOKEN_LIFETIME_SECONDS;
139
+ }
140
+ });
141
+ Object.defineProperty(exports, "RESERVED_SERVICE_CLIENT_SLUGS", {
142
+ enumerable: true,
143
+ get: function() {
144
+ return RESERVED_SERVICE_CLIENT_SLUGS;
145
+ }
146
+ });
147
+ Object.defineProperty(exports, "SERVICE_KID_PREFIX", {
148
+ enumerable: true,
149
+ get: function() {
150
+ return SERVICE_KID_PREFIX;
151
+ }
152
+ });
153
+ Object.defineProperty(exports, "SERVICE_TOKEN_ERROR_CODES", {
154
+ enumerable: true,
155
+ get: function() {
156
+ return SERVICE_TOKEN_ERROR_CODES;
157
+ }
158
+ });
159
+ Object.defineProperty(exports, "SERVICE_TOKEN_LIFETIME_SECONDS", {
160
+ enumerable: true,
161
+ get: function() {
162
+ return SERVICE_TOKEN_LIFETIME_SECONDS;
163
+ }
164
+ });
165
+ Object.defineProperty(exports, "SERVICE_TOKEN_TYP", {
166
+ enumerable: true,
167
+ get: function() {
168
+ return SERVICE_TOKEN_TYP;
169
+ }
170
+ });
171
+ Object.defineProperty(exports, "SUBJECT_TOKEN_HEADER", {
172
+ enumerable: true,
173
+ get: function() {
174
+ return SUBJECT_TOKEN_HEADER;
175
+ }
176
+ });
177
+ Object.defineProperty(exports, "SUBJECT_TOKEN_INVALID_CODE", {
178
+ enumerable: true,
179
+ get: function() {
180
+ return SUBJECT_TOKEN_INVALID_CODE;
181
+ }
182
+ });
183
+ Object.defineProperty(exports, "SUBJECT_TOKEN_INVALID_STATUS", {
184
+ enumerable: true,
185
+ get: function() {
186
+ return SUBJECT_TOKEN_INVALID_STATUS;
187
+ }
188
+ });
189
+ Object.defineProperty(exports, "TOKEN_BEARING_KEYS", {
190
+ enumerable: true,
191
+ get: function() {
192
+ return TOKEN_BEARING_KEYS;
193
+ }
194
+ });
195
+ Object.defineProperty(exports, "TOKEN_EXCHANGE_ERROR_CODES", {
196
+ enumerable: true,
197
+ get: function() {
198
+ return TOKEN_EXCHANGE_ERROR_CODES;
199
+ }
200
+ });
201
+ Object.defineProperty(exports, "TOKEN_EXCHANGE_GRANT_TYPE", {
202
+ enumerable: true,
203
+ get: function() {
204
+ return TOKEN_EXCHANGE_GRANT_TYPE;
205
+ }
206
+ });
207
+ Object.defineProperty(exports, "TOKEN_ISSUER", {
208
+ enumerable: true,
209
+ get: function() {
210
+ return TOKEN_ISSUER;
211
+ }
212
+ });
213
+ Object.defineProperty(exports, "USER_KID_PREFIX", {
214
+ enumerable: true,
215
+ get: function() {
216
+ return USER_KID_PREFIX;
217
+ }
218
+ });
219
+ Object.defineProperty(exports, "USER_TOKEN_TYP", {
220
+ enumerable: true,
221
+ get: function() {
222
+ return USER_TOKEN_TYP;
223
+ }
224
+ });
225
+ Object.defineProperty(exports, "isReservedServiceClientSlug", {
226
+ enumerable: true,
227
+ get: function() {
228
+ return isReservedServiceClientSlug;
229
+ }
230
+ });
231
+
232
+ //# sourceMappingURL=tokens-C1nzkn21.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens-C1nzkn21.cjs","names":[],"sources":["../../auth-contracts/dist/tokens.js"],"sourcesContent":["// src/tokens.ts\n/**\n* PURE module: it must never reference `zod` or any schema module of this package (see\n* `constants.ts`). Token vocabulary shared by the Auth service and every consumer: issuer, token\n* types, key prefixes, lifetimes and the token endpoint error codes.\n*/\n/** Issuer (`iss`) of every token the Auth service signs. */\nconst TOKEN_ISSUER = \"auth-service\";\n/**\n* Service client slugs nobody can create: the token issuer name (an `iss`-like value would let a\n* client pass for the service itself).\n*/\nconst RESERVED_SERVICE_CLIENT_SLUGS = [TOKEN_ISSUER];\n/** True when `slug` is reserved and cannot be used as a service client slug. */\nfunction isReservedServiceClientSlug(slug) {\n\treturn RESERVED_SERVICE_CLIENT_SLUGS.includes(slug);\n}\n/**\n* Fixed id (`sub`) of the Auth service itself when it mints its own service tokens (the OTP send).\n* Receivers register it like any other service client id.\n*/\nconst AUTH_SERVICE_SUB = \"00000000-0000-4000-8000-000000000001\";\n/** Header `typ` of a user access token (RFC 9068). */\nconst USER_TOKEN_TYP = \"at+jwt\";\n/** Header `typ` of a service access token. Distinct from the user one on purpose (RFC 8725 3.11). */\nconst SERVICE_TOKEN_TYP = \"svc-at+jwt\";\n/** The `kid` of a user signing key starts with this prefix. */\nconst USER_KID_PREFIX = \"usr-\";\n/** The `kid` of a service signing key starts with this prefix. */\nconst SERVICE_KID_PREFIX = \"svc-\";\n/** Lifetime in seconds of a service token obtained from the token endpoint. */\nconst SERVICE_TOKEN_LIFETIME_SECONDS = 300;\n/** Lifetime in seconds of the single-use service token Auth mints in-process per OTP send. */\nconst INTERNAL_SERVICE_TOKEN_LIFETIME_SECONDS = 60;\n/**\n* Error codes of the token endpoint (RFC 6749 5.2 and RFC 8707 2). Throttling a client has no\n* code of its own: it answers `429` with `temporarily_unavailable` and a `Retry-After` header (the\n* SDK token provider reads both).\n*/\nconst SERVICE_TOKEN_ERROR_CODES = [\n\t\"invalid_request\",\n\t\"invalid_client\",\n\t\"invalid_target\",\n\t\"invalid_scope\",\n\t\"temporarily_unavailable\"\n];\n/**\n* Header `typ` of a delegated access token (token exchange, RFC 8693). A third type, distinct from\n* the user and service ones: it is signed with a SERVICE key (`svc-` kid) but no service verifier\n* accepts it, and the delegated verifier accepts nothing else.\n*/\nconst DELEGATED_TOKEN_TYP = \"dlg-at+jwt\";\n/** Lifetime in seconds of a delegated token (`exp` never exceeds the one of the subject token). */\nconst DELEGATED_TOKEN_LIFETIME_SECONDS = 120;\n/**\n* Most levels the `act` (actor) chain of a delegated token can have. A delegated token that\n* already has this many levels cannot be exchanged again.\n*/\nconst DELEGATED_TOKEN_MAX_DEPTH = 3;\n/** `grant_type` of the token exchange request (RFC 8693 2.1). */\nconst TOKEN_EXCHANGE_GRANT_TYPE = \"urn:ietf:params:oauth:grant-type:token-exchange\";\n/**\n* Token type identifier for `subject_token_type` (what is exchanged) and `issued_token_type` (what\n* comes back): both are JWT access tokens (RFC 8693 3).\n*/\nconst ACCESS_TOKEN_TYPE = \"urn:ietf:params:oauth:token-type:access_token\";\n/**\n* Header with which a service sends the access token of a person on the requests that cannot carry\n* a body (the `GET` that needs a person's role). Every other person-bound request carries it as\n* `subjectToken` in the body.\n*/\nconst SUBJECT_TOKEN_HEADER = \"x-eva-subject-token\";\n/**\n* Error codes of the token exchange endpoint (RFC 6749 5.2, RFC 8693 2.2.2 and RFC 8707 2).\n* `invalid_grant`: the subject token or what it depends on (session, user, membership, company,\n* contract, depth, cycle) is not valid. Throttling answers `429` with `temporarily_unavailable`.\n*/\nconst TOKEN_EXCHANGE_ERROR_CODES = [\n\t\"invalid_request\",\n\t\"invalid_client\",\n\t\"invalid_grant\",\n\t\"invalid_target\",\n\t\"invalid_scope\",\n\t\"temporarily_unavailable\"\n];\n/**\n* Failure of the PERSON's token (`subjectToken`) on a person-bound request: invalid, expired, of\n* another product, or its session/user is gone. It answers `403` with this code, never `401`: a\n* `401` on `/internal/*` means the service Bearer was rejected (the S2S client then drops its\n* service token and retries once), and a bad person token must not trigger that.\n*/\nconst SUBJECT_TOKEN_INVALID_STATUS = 403;\nconst SUBJECT_TOKEN_INVALID_CODE = \"subject_token_invalid\";\n/**\n* Keys that carry a person or service token in bodies, headers and token endpoint answers. The\n* Auth API redacts them in logs and audit records. It is ADDED to the consumer's own redaction\n* list (which already covers `refresh_token`, `authorization` and the like); it does not replace it.\n*/\nconst TOKEN_BEARING_KEYS = [\n\t\"subjectToken\",\n\t\"subject_token\",\n\t\"x-eva-subject-token\",\n\t\"access_token\"\n];\nexport { ACCESS_TOKEN_TYPE, AUTH_SERVICE_SUB, DELEGATED_TOKEN_LIFETIME_SECONDS, DELEGATED_TOKEN_MAX_DEPTH, DELEGATED_TOKEN_TYP, INTERNAL_SERVICE_TOKEN_LIFETIME_SECONDS, RESERVED_SERVICE_CLIENT_SLUGS, SERVICE_KID_PREFIX, SERVICE_TOKEN_ERROR_CODES, SERVICE_TOKEN_LIFETIME_SECONDS, SERVICE_TOKEN_TYP, SUBJECT_TOKEN_HEADER, SUBJECT_TOKEN_INVALID_CODE, SUBJECT_TOKEN_INVALID_STATUS, TOKEN_BEARING_KEYS, TOKEN_EXCHANGE_ERROR_CODES, TOKEN_EXCHANGE_GRANT_TYPE, TOKEN_ISSUER, USER_KID_PREFIX, USER_TOKEN_TYP, isReservedServiceClientSlug };\n\n//# sourceMappingURL=tokens.js.map"],"mappings":";;;;;;;AAOA,MAAM,eAAe;;;;;AAKrB,MAAM,gCAAgC,CAAC,YAAY;;AAEnD,SAAS,4BAA4B,MAAM;CAC1C,OAAO,8BAA8B,SAAS,IAAI;AACnD;;;;;AAKA,MAAM,mBAAmB;;AAEzB,MAAM,iBAAiB;;AAEvB,MAAM,oBAAoB;;AAE1B,MAAM,kBAAkB;;AAExB,MAAM,qBAAqB;;AAE3B,MAAM,iCAAiC;;AAEvC,MAAM,0CAA0C;;;;;;AAMhD,MAAM,4BAA4B;CACjC;CACA;CACA;CACA;CACA;AACD;;;;;;AAMA,MAAM,sBAAsB;;AAE5B,MAAM,mCAAmC;;;;;AAKzC,MAAM,4BAA4B;;AAElC,MAAM,4BAA4B;;;;;AAKlC,MAAM,oBAAoB;;;;;;AAM1B,MAAM,uBAAuB;;;;;;AAM7B,MAAM,6BAA6B;CAClC;CACA;CACA;CACA;CACA;CACA;AACD;;;;;;;AAOA,MAAM,+BAA+B;AACrC,MAAM,6BAA6B;;;;;;AAMnC,MAAM,qBAAqB;CAC1B;CACA;CACA;CACA;AACD"}
@@ -0,0 +1,107 @@
1
+ // ../auth-contracts/dist/tokens.js
2
+ /**
3
+ * PURE module: it must never reference `zod` or any schema module of this package (see
4
+ * `constants.ts`). Token vocabulary shared by the Auth service and every consumer: issuer, token
5
+ * types, key prefixes, lifetimes and the token endpoint error codes.
6
+ */
7
+ /** Issuer (`iss`) of every token the Auth service signs. */
8
+ const TOKEN_ISSUER = "auth-service";
9
+ /**
10
+ * Service client slugs nobody can create: the token issuer name (an `iss`-like value would let a
11
+ * client pass for the service itself).
12
+ */
13
+ const RESERVED_SERVICE_CLIENT_SLUGS = [TOKEN_ISSUER];
14
+ /** True when `slug` is reserved and cannot be used as a service client slug. */
15
+ function isReservedServiceClientSlug(slug) {
16
+ return RESERVED_SERVICE_CLIENT_SLUGS.includes(slug);
17
+ }
18
+ /**
19
+ * Fixed id (`sub`) of the Auth service itself when it mints its own service tokens (the OTP send).
20
+ * Receivers register it like any other service client id.
21
+ */
22
+ const AUTH_SERVICE_SUB = "00000000-0000-4000-8000-000000000001";
23
+ /** Header `typ` of a user access token (RFC 9068). */
24
+ const USER_TOKEN_TYP = "at+jwt";
25
+ /** Header `typ` of a service access token. Distinct from the user one on purpose (RFC 8725 3.11). */
26
+ const SERVICE_TOKEN_TYP = "svc-at+jwt";
27
+ /** The `kid` of a user signing key starts with this prefix. */
28
+ const USER_KID_PREFIX = "usr-";
29
+ /** The `kid` of a service signing key starts with this prefix. */
30
+ const SERVICE_KID_PREFIX = "svc-";
31
+ /** Lifetime in seconds of a service token obtained from the token endpoint. */
32
+ const SERVICE_TOKEN_LIFETIME_SECONDS = 300;
33
+ /** Lifetime in seconds of the single-use service token Auth mints in-process per OTP send. */
34
+ const INTERNAL_SERVICE_TOKEN_LIFETIME_SECONDS = 60;
35
+ /**
36
+ * Error codes of the token endpoint (RFC 6749 5.2 and RFC 8707 2). Throttling a client has no
37
+ * code of its own: it answers `429` with `temporarily_unavailable` and a `Retry-After` header (the
38
+ * SDK token provider reads both).
39
+ */
40
+ const SERVICE_TOKEN_ERROR_CODES = [
41
+ "invalid_request",
42
+ "invalid_client",
43
+ "invalid_target",
44
+ "invalid_scope",
45
+ "temporarily_unavailable"
46
+ ];
47
+ /**
48
+ * Header `typ` of a delegated access token (token exchange, RFC 8693). A third type, distinct from
49
+ * the user and service ones: it is signed with a SERVICE key (`svc-` kid) but no service verifier
50
+ * accepts it, and the delegated verifier accepts nothing else.
51
+ */
52
+ const DELEGATED_TOKEN_TYP = "dlg-at+jwt";
53
+ /** Lifetime in seconds of a delegated token (`exp` never exceeds the one of the subject token). */
54
+ const DELEGATED_TOKEN_LIFETIME_SECONDS = 120;
55
+ /**
56
+ * Most levels the `act` (actor) chain of a delegated token can have. A delegated token that
57
+ * already has this many levels cannot be exchanged again.
58
+ */
59
+ const DELEGATED_TOKEN_MAX_DEPTH = 3;
60
+ /** `grant_type` of the token exchange request (RFC 8693 2.1). */
61
+ const TOKEN_EXCHANGE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:token-exchange";
62
+ /**
63
+ * Token type identifier for `subject_token_type` (what is exchanged) and `issued_token_type` (what
64
+ * comes back): both are JWT access tokens (RFC 8693 3).
65
+ */
66
+ const ACCESS_TOKEN_TYPE = "urn:ietf:params:oauth:token-type:access_token";
67
+ /**
68
+ * Header with which a service sends the access token of a person on the requests that cannot carry
69
+ * a body (the `GET` that needs a person's role). Every other person-bound request carries it as
70
+ * `subjectToken` in the body.
71
+ */
72
+ const SUBJECT_TOKEN_HEADER = "x-eva-subject-token";
73
+ /**
74
+ * Error codes of the token exchange endpoint (RFC 6749 5.2, RFC 8693 2.2.2 and RFC 8707 2).
75
+ * `invalid_grant`: the subject token or what it depends on (session, user, membership, company,
76
+ * contract, depth, cycle) is not valid. Throttling answers `429` with `temporarily_unavailable`.
77
+ */
78
+ const TOKEN_EXCHANGE_ERROR_CODES = [
79
+ "invalid_request",
80
+ "invalid_client",
81
+ "invalid_grant",
82
+ "invalid_target",
83
+ "invalid_scope",
84
+ "temporarily_unavailable"
85
+ ];
86
+ /**
87
+ * Failure of the PERSON's token (`subjectToken`) on a person-bound request: invalid, expired, of
88
+ * another product, or its session/user is gone. It answers `403` with this code, never `401`: a
89
+ * `401` on `/internal/*` means the service Bearer was rejected (the S2S client then drops its
90
+ * service token and retries once), and a bad person token must not trigger that.
91
+ */
92
+ const SUBJECT_TOKEN_INVALID_STATUS = 403;
93
+ const SUBJECT_TOKEN_INVALID_CODE = "subject_token_invalid";
94
+ /**
95
+ * Keys that carry a person or service token in bodies, headers and token endpoint answers. The
96
+ * Auth API redacts them in logs and audit records. It is ADDED to the consumer's own redaction
97
+ * list (which already covers `refresh_token`, `authorization` and the like); it does not replace it.
98
+ */
99
+ const TOKEN_BEARING_KEYS = [
100
+ "subjectToken",
101
+ "subject_token",
102
+ "x-eva-subject-token",
103
+ "access_token"
104
+ ];
105
+ export { TOKEN_EXCHANGE_GRANT_TYPE as _, DELEGATED_TOKEN_TYP as a, USER_TOKEN_TYP as b, SERVICE_KID_PREFIX as c, SERVICE_TOKEN_TYP as d, SUBJECT_TOKEN_HEADER as f, TOKEN_EXCHANGE_ERROR_CODES as g, TOKEN_BEARING_KEYS as h, DELEGATED_TOKEN_MAX_DEPTH as i, SERVICE_TOKEN_ERROR_CODES as l, SUBJECT_TOKEN_INVALID_STATUS as m, AUTH_SERVICE_SUB as n, INTERNAL_SERVICE_TOKEN_LIFETIME_SECONDS as o, SUBJECT_TOKEN_INVALID_CODE as p, DELEGATED_TOKEN_LIFETIME_SECONDS as r, RESERVED_SERVICE_CLIENT_SLUGS as s, ACCESS_TOKEN_TYPE as t, SERVICE_TOKEN_LIFETIME_SECONDS as u, TOKEN_ISSUER as v, isReservedServiceClientSlug as x, USER_KID_PREFIX as y };
106
+
107
+ //# sourceMappingURL=tokens-C3Z40qd7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens-C3Z40qd7.js","names":[],"sources":["../../auth-contracts/dist/tokens.js"],"sourcesContent":["// src/tokens.ts\n/**\n* PURE module: it must never reference `zod` or any schema module of this package (see\n* `constants.ts`). Token vocabulary shared by the Auth service and every consumer: issuer, token\n* types, key prefixes, lifetimes and the token endpoint error codes.\n*/\n/** Issuer (`iss`) of every token the Auth service signs. */\nconst TOKEN_ISSUER = \"auth-service\";\n/**\n* Service client slugs nobody can create: the token issuer name (an `iss`-like value would let a\n* client pass for the service itself).\n*/\nconst RESERVED_SERVICE_CLIENT_SLUGS = [TOKEN_ISSUER];\n/** True when `slug` is reserved and cannot be used as a service client slug. */\nfunction isReservedServiceClientSlug(slug) {\n\treturn RESERVED_SERVICE_CLIENT_SLUGS.includes(slug);\n}\n/**\n* Fixed id (`sub`) of the Auth service itself when it mints its own service tokens (the OTP send).\n* Receivers register it like any other service client id.\n*/\nconst AUTH_SERVICE_SUB = \"00000000-0000-4000-8000-000000000001\";\n/** Header `typ` of a user access token (RFC 9068). */\nconst USER_TOKEN_TYP = \"at+jwt\";\n/** Header `typ` of a service access token. Distinct from the user one on purpose (RFC 8725 3.11). */\nconst SERVICE_TOKEN_TYP = \"svc-at+jwt\";\n/** The `kid` of a user signing key starts with this prefix. */\nconst USER_KID_PREFIX = \"usr-\";\n/** The `kid` of a service signing key starts with this prefix. */\nconst SERVICE_KID_PREFIX = \"svc-\";\n/** Lifetime in seconds of a service token obtained from the token endpoint. */\nconst SERVICE_TOKEN_LIFETIME_SECONDS = 300;\n/** Lifetime in seconds of the single-use service token Auth mints in-process per OTP send. */\nconst INTERNAL_SERVICE_TOKEN_LIFETIME_SECONDS = 60;\n/**\n* Error codes of the token endpoint (RFC 6749 5.2 and RFC 8707 2). Throttling a client has no\n* code of its own: it answers `429` with `temporarily_unavailable` and a `Retry-After` header (the\n* SDK token provider reads both).\n*/\nconst SERVICE_TOKEN_ERROR_CODES = [\n\t\"invalid_request\",\n\t\"invalid_client\",\n\t\"invalid_target\",\n\t\"invalid_scope\",\n\t\"temporarily_unavailable\"\n];\n/**\n* Header `typ` of a delegated access token (token exchange, RFC 8693). A third type, distinct from\n* the user and service ones: it is signed with a SERVICE key (`svc-` kid) but no service verifier\n* accepts it, and the delegated verifier accepts nothing else.\n*/\nconst DELEGATED_TOKEN_TYP = \"dlg-at+jwt\";\n/** Lifetime in seconds of a delegated token (`exp` never exceeds the one of the subject token). */\nconst DELEGATED_TOKEN_LIFETIME_SECONDS = 120;\n/**\n* Most levels the `act` (actor) chain of a delegated token can have. A delegated token that\n* already has this many levels cannot be exchanged again.\n*/\nconst DELEGATED_TOKEN_MAX_DEPTH = 3;\n/** `grant_type` of the token exchange request (RFC 8693 2.1). */\nconst TOKEN_EXCHANGE_GRANT_TYPE = \"urn:ietf:params:oauth:grant-type:token-exchange\";\n/**\n* Token type identifier for `subject_token_type` (what is exchanged) and `issued_token_type` (what\n* comes back): both are JWT access tokens (RFC 8693 3).\n*/\nconst ACCESS_TOKEN_TYPE = \"urn:ietf:params:oauth:token-type:access_token\";\n/**\n* Header with which a service sends the access token of a person on the requests that cannot carry\n* a body (the `GET` that needs a person's role). Every other person-bound request carries it as\n* `subjectToken` in the body.\n*/\nconst SUBJECT_TOKEN_HEADER = \"x-eva-subject-token\";\n/**\n* Error codes of the token exchange endpoint (RFC 6749 5.2, RFC 8693 2.2.2 and RFC 8707 2).\n* `invalid_grant`: the subject token or what it depends on (session, user, membership, company,\n* contract, depth, cycle) is not valid. Throttling answers `429` with `temporarily_unavailable`.\n*/\nconst TOKEN_EXCHANGE_ERROR_CODES = [\n\t\"invalid_request\",\n\t\"invalid_client\",\n\t\"invalid_grant\",\n\t\"invalid_target\",\n\t\"invalid_scope\",\n\t\"temporarily_unavailable\"\n];\n/**\n* Failure of the PERSON's token (`subjectToken`) on a person-bound request: invalid, expired, of\n* another product, or its session/user is gone. It answers `403` with this code, never `401`: a\n* `401` on `/internal/*` means the service Bearer was rejected (the S2S client then drops its\n* service token and retries once), and a bad person token must not trigger that.\n*/\nconst SUBJECT_TOKEN_INVALID_STATUS = 403;\nconst SUBJECT_TOKEN_INVALID_CODE = \"subject_token_invalid\";\n/**\n* Keys that carry a person or service token in bodies, headers and token endpoint answers. The\n* Auth API redacts them in logs and audit records. It is ADDED to the consumer's own redaction\n* list (which already covers `refresh_token`, `authorization` and the like); it does not replace it.\n*/\nconst TOKEN_BEARING_KEYS = [\n\t\"subjectToken\",\n\t\"subject_token\",\n\t\"x-eva-subject-token\",\n\t\"access_token\"\n];\nexport { ACCESS_TOKEN_TYPE, AUTH_SERVICE_SUB, DELEGATED_TOKEN_LIFETIME_SECONDS, DELEGATED_TOKEN_MAX_DEPTH, DELEGATED_TOKEN_TYP, INTERNAL_SERVICE_TOKEN_LIFETIME_SECONDS, RESERVED_SERVICE_CLIENT_SLUGS, SERVICE_KID_PREFIX, SERVICE_TOKEN_ERROR_CODES, SERVICE_TOKEN_LIFETIME_SECONDS, SERVICE_TOKEN_TYP, SUBJECT_TOKEN_HEADER, SUBJECT_TOKEN_INVALID_CODE, SUBJECT_TOKEN_INVALID_STATUS, TOKEN_BEARING_KEYS, TOKEN_EXCHANGE_ERROR_CODES, TOKEN_EXCHANGE_GRANT_TYPE, TOKEN_ISSUER, USER_KID_PREFIX, USER_TOKEN_TYP, isReservedServiceClientSlug };\n\n//# sourceMappingURL=tokens.js.map"],"mappings":";;;;;;;AAOA,MAAM,eAAe;;;;;AAKrB,MAAM,gCAAgC,CAAC,YAAY;;AAEnD,SAAS,4BAA4B,MAAM;CAC1C,OAAO,8BAA8B,SAAS,IAAI;AACnD;;;;;AAKA,MAAM,mBAAmB;;AAEzB,MAAM,iBAAiB;;AAEvB,MAAM,oBAAoB;;AAE1B,MAAM,kBAAkB;;AAExB,MAAM,qBAAqB;;AAE3B,MAAM,iCAAiC;;AAEvC,MAAM,0CAA0C;;;;;;AAMhD,MAAM,4BAA4B;CACjC;CACA;CACA;CACA;CACA;AACD;;;;;;AAMA,MAAM,sBAAsB;;AAE5B,MAAM,mCAAmC;;;;;AAKzC,MAAM,4BAA4B;;AAElC,MAAM,4BAA4B;;;;;AAKlC,MAAM,oBAAoB;;;;;;AAM1B,MAAM,uBAAuB;;;;;;AAM7B,MAAM,6BAA6B;CAClC;CACA;CACA;CACA;CACA;CACA;AACD;;;;;;;AAOA,MAAM,+BAA+B;AACrC,MAAM,6BAA6B;;;;;;AAMnC,MAAM,qBAAqB;CAC1B;CACA;CACA;CACA;AACD"}