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

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-3avoUa9e.d.cts +95 -0
  37. package/dist/config-3avoUa9e.d.cts.map +1 -0
  38. package/dist/config-COX7rGAP.d.ts +95 -0
  39. package/dist/config-COX7rGAP.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-0woh13Wd.d.cts +105 -0
  65. package/dist/error-helpers-0woh13Wd.d.cts.map +1 -0
  66. package/dist/error-helpers-Ct3AUK1I.d.ts +105 -0
  67. package/dist/error-helpers-Ct3AUK1I.d.ts.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-CIH_2t7Y.d.ts +240 -0
  113. package/dist/index-CIH_2t7Y.d.ts.map +1 -0
  114. package/dist/index-CZru7c5T.d.cts +1711 -0
  115. package/dist/index-CZru7c5T.d.cts.map +1 -0
  116. package/dist/index-CZru7c5T.d.ts +1711 -0
  117. package/dist/index-CZru7c5T.d.ts.map +1 -0
  118. package/dist/index-DMVe5IJA.d.cts +240 -0
  119. package/dist/index-DMVe5IJA.d.cts.map +1 -0
  120. package/dist/index-DRWKobSp.d.ts +312 -0
  121. package/dist/index-DRWKobSp.d.ts.map +1 -0
  122. package/dist/index-DU9wJ-P2.d.cts +312 -0
  123. package/dist/index-DU9wJ-P2.d.cts.map +1 -0
  124. package/dist/index-DbiXllNy.d.cts +66 -0
  125. package/dist/index-DbiXllNy.d.cts.map +1 -0
  126. package/dist/index-z9r98qlk.d.ts +66 -0
  127. package/dist/index-z9r98qlk.d.ts.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-Ai3iIFlB.d.cts +538 -0
  186. package/dist/types-Ai3iIFlB.d.cts.map +1 -0
  187. package/dist/types-Bxg4hCMc.d.cts +52 -0
  188. package/dist/types-Bxg4hCMc.d.cts.map +1 -0
  189. package/dist/types-CEABh1Zf.d.ts +96 -0
  190. package/dist/types-CEABh1Zf.d.ts.map +1 -0
  191. package/dist/types-Ci0Jq0xB.d.cts +96 -0
  192. package/dist/types-Ci0Jq0xB.d.cts.map +1 -0
  193. package/dist/types-DXg8BvEh.d.ts +52 -0
  194. package/dist/types-DXg8BvEh.d.ts.map +1 -0
  195. package/dist/types-_zY7QbM5.d.ts +538 -0
  196. package/dist/types-_zY7QbM5.d.ts.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,309 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_constants = require("../constants-CcbhOaAP.cjs");
3
+ const require_jwt = require("../jwt-BBNqk0TV.cjs");
4
+ const require_cookies = require("../cookies-DCIcr7uy.cjs");
5
+ const require_http_client = require("../http-client-BVF3iktR.cjs");
6
+ const require_refresh_dedup = require("../refresh-dedup-CLdACQXR.cjs");
7
+ const require_parse_error_response = require("../parse-error-response-6qOQS5y9.cjs");
8
+ const require_auth_handlers = require("../auth-handlers-CDzGFDTu.cjs");
9
+ const require_constants$1 = require("../constants-BE1_9Tod.cjs");
10
+ const require_delegated_token = require("../delegated-token-DHSK4rHI.cjs");
11
+ let hono_factory = require("hono/factory");
12
+ let hono = require("hono");
13
+ let hono_request = require("hono/request");
14
+ // src/hono/middleware.ts
15
+ const client = require_http_client.createHttpClient();
16
+ function evaAuth(opts = {}) {
17
+ if (opts.errorMessages !== void 0) require_parse_error_response.validateErrorMessagesInput(opts.errorMessages);
18
+ return (0, hono_factory.createMiddleware)(async (c, next) => {
19
+ const cookieHeader = c.req.header("cookie") || null;
20
+ const { accessToken, refreshToken } = require_cookies.readTokensFromCookies(cookieHeader);
21
+ if (accessToken) {
22
+ const result = await require_jwt.verifyAccessToken(accessToken, { extraClaimsSchema: opts.extraClaimsSchema });
23
+ if (result.ok) {
24
+ c.set("evaPayload", result.data);
25
+ await next();
26
+ return;
27
+ }
28
+ }
29
+ if (refreshToken) {
30
+ const refreshResult = await require_refresh_dedup.deduplicateRefresh(refreshToken, () => client.refresh({ refreshToken }));
31
+ if (refreshResult.ok && refreshResult.data.tokens) {
32
+ const verifyResult = await require_jwt.verifyAccessToken(refreshResult.data.tokens.accessToken, { extraClaimsSchema: opts.extraClaimsSchema });
33
+ if (verifyResult.ok) {
34
+ c.set("evaPayload", verifyResult.data);
35
+ const cookieHeaders = require_cookies.setTokenCookies(refreshResult.data.tokens);
36
+ for (const cookie of cookieHeaders) c.header("Set-Cookie", cookie, { append: true });
37
+ await next();
38
+ return;
39
+ }
40
+ }
41
+ const clearHeaders = require_cookies.clearTokenCookies();
42
+ for (const cookie of clearHeaders) c.header("Set-Cookie", cookie, { append: true });
43
+ }
44
+ const messages = require_parse_error_response.resolveErrorMessages(opts.errorMessages, require_parse_error_response.getErrorMessages());
45
+ if (require_parse_error_response.getErrorWire() === "api") return c.json({ error: {
46
+ code: "unauthorized",
47
+ message: messages.authRequired
48
+ } }, 401);
49
+ return c.json({ error: messages.authRequired }, 401);
50
+ });
51
+ }
52
+ // src/hono/auth-routes.ts
53
+ function evaAuthRoutes(opts = {}) {
54
+ const app = new hono.Hono();
55
+ const h = require_auth_handlers.buildAuthHandlers(opts);
56
+ app.use("*", h.originGuard);
57
+ app.post("/get-code", h.getCode);
58
+ app.post("/login", h.login);
59
+ app.post("/refresh", h.refresh);
60
+ app.post("/logout", h.logout);
61
+ app.get("/me", h.getMe);
62
+ app.patch("/me", h.updateMe);
63
+ app.delete("/me", h.deleteMe);
64
+ app.get("/empresas", h.getEmpresas);
65
+ app.post("/empresa-activa", h.setActiveEmpresa);
66
+ app.get("/sessions", h.getSessions);
67
+ app.delete("/sessions/:id", h.deleteSession);
68
+ app.delete("/sessions", h.deleteAllSessions);
69
+ return app;
70
+ }
71
+ // src/hono/helpers.ts
72
+ function getEvaPayload(c) {
73
+ const payload = c.get("evaPayload");
74
+ if (!payload) throw new Error("Middleware evaAuth no aplicado");
75
+ return payload;
76
+ }
77
+ function getSessionId(c) {
78
+ return getEvaPayload(c).sessionId;
79
+ }
80
+ // src/hono/s2s.ts
81
+ /**
82
+ * Hono middlewares for inbound S2S request authentication and scope-based authorization.
83
+ *
84
+ * REQ-HONO-AUTH-*, REQ-HONO-SCOPE-*, REQ-HONO-WIRE-*, REQ-API-02, REQ-API-03, REQ-API-05.
85
+ *
86
+ * Decisión in-flight B3-01: `cloneRawRequest` existe en Hono 4.12.19 bajo el entry point
87
+ * `'hono/request'` (no `'hono/utils/request'` como estimaba el design). Se usa la ruta correcta
88
+ * confirmada en node_modules/hono/package.json exports map: `"./request"` → `dist/request.js`.
89
+ */
90
+ /**
91
+ * Hono middleware that verifies inbound S2S requests signed with HMAC-SHA-256.
92
+ *
93
+ * On **success**: sets `c.var.s2sClientId` and `c.var.s2sScopes`, then calls `next()`.
94
+ * On **failure**: responds with HTTP 401 `{ error: { code: <S2SVerifyReason>, message } }`.
95
+ *
96
+ * The middleware clones the request before reading the body (using Hono's `cloneRawRequest`),
97
+ * so route handlers can still read the body after authentication — even if a prior middleware
98
+ * already consumed the original stream.
99
+ *
100
+ * @see {@link requireScope} to enforce scope-based authorization after authentication.
101
+ *
102
+ * @example
103
+ * ```ts
104
+ * import { Hono } from 'hono'
105
+ * import { s2sAuth, requireScope } from '@eva_solutions/auth-sdk/hono'
106
+ *
107
+ * const app = new Hono()
108
+ *
109
+ * app.use('/api/*', s2sAuth({
110
+ * secretStore: async (clientId) => redis.get(`s2s:${clientId}:secret`),
111
+ * scopesOf: async (clientId) => redis.smembers(`s2s:${clientId}:scopes`),
112
+ * onAuth: (clientId, scopes) => logger.info({ clientId, scopes }, 's2s authenticated'),
113
+ * }))
114
+ *
115
+ * app.get('/api/resource', (c) => {
116
+ * const clientId = c.var.s2sClientId // available after s2sAuth
117
+ * const scopes = c.var.s2sScopes
118
+ * return c.json({ clientId, scopes })
119
+ * })
120
+ * ```
121
+ */
122
+ function s2sAuth(opts) {
123
+ return (0, hono_factory.createMiddleware)(async (c, next) => {
124
+ const clonedRequest = await (0, hono_request.cloneRawRequest)(c.req);
125
+ const result = await require_delegated_token.verifyS2SRequest(clonedRequest, {
126
+ secretStore: opts.secretStore,
127
+ timestampWindowSeconds: opts.timestampWindowSeconds,
128
+ replayCache: opts.replayCache,
129
+ messages: opts.messages
130
+ });
131
+ if (!result.ok) return c.json({ error: {
132
+ code: result.error.reason,
133
+ message: result.error.message
134
+ } }, 401);
135
+ const scopes = opts.scopesOf ? await opts.scopesOf(result.data.clientId) : [];
136
+ c.set("s2sClientId", result.data.clientId);
137
+ c.set("s2sScopes", scopes);
138
+ if (opts.onAuth) await opts.onAuth(result.data.clientId, scopes);
139
+ await next();
140
+ });
141
+ }
142
+ function requireScope(arg) {
143
+ if (arg === null || arg === void 0) throw new TypeError("requireScope: scope argument required");
144
+ if (typeof arg === "object") {
145
+ const hasAll = "all" in arg && arg.all !== void 0;
146
+ const hasAny = "any" in arg && arg.any !== void 0;
147
+ if (hasAll && hasAny) throw new TypeError("requireScope: cannot use both 'all' and 'any'");
148
+ if (!hasAll && !hasAny) throw new TypeError("requireScope: must specify 'all' or 'any'");
149
+ if (hasAll && arg.all.length === 0) throw new TypeError("requireScope: 'all' cannot be empty");
150
+ if (hasAny && arg.any.length === 0) throw new TypeError("requireScope: 'any' cannot be empty");
151
+ }
152
+ return (0, hono_factory.createMiddleware)(async (c, next) => {
153
+ const vars = c.var.s2sScopes ?? c.var.serviceScopes;
154
+ if (vars === void 0) throw new Error("[eva-auth-sdk] requireScope: no auth middleware applied — apply s2sAuth() or serviceTokenAuth() before requireScope()");
155
+ if (typeof arg === "string") {
156
+ if (!vars.includes(arg)) return c.json({ error: {
157
+ code: "insufficient_scope",
158
+ required: arg
159
+ } }, 403);
160
+ } else if ("all" in arg && arg.all) {
161
+ const required = arg.all;
162
+ const missing = required.filter((s) => !vars.includes(s));
163
+ if (missing.length > 0) return c.json({ error: {
164
+ code: "insufficient_scope",
165
+ requiredAll: required,
166
+ missing
167
+ } }, 403);
168
+ } else if ("any" in arg && arg.any) {
169
+ const required = arg.any;
170
+ if (!required.some((s) => vars.includes(s))) return c.json({ error: {
171
+ code: "insufficient_scope",
172
+ requiredAny: required
173
+ } }, 403);
174
+ }
175
+ await next();
176
+ });
177
+ }
178
+ const BEARER_REGEX = /^Bearer ([A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+)$/i;
179
+ /**
180
+ * Hono middleware that verifies the service token (ES256, `typ: 'svc-at+jwt'`, `kid` `svc-…`, `aud`
181
+ * of this service, `scope`) sent as `Authorization: Bearer`. See `verifyServiceToken` for the
182
+ * token contract.
183
+ *
184
+ * On **success**: sets `c.var.serviceClientId` (`sub`), `c.var.serviceClientSlug` (`client_id`) and
185
+ * `c.var.serviceScopes`, then calls `next()`.
186
+ * On **failure**: HTTP 401 `{ error: { code: <ServiceTokenVerifyReason>, message } }`, or HTTP 403
187
+ * with code `insufficient_scope` when the token is valid but lacks the required scope.
188
+ *
189
+ * JWKS/config failures are not rejections: they propagate and Hono answers 500.
190
+ *
191
+ * With `scopeCheck: 'deferred'` the token is authenticated but no permission is required here; mount
192
+ * `requireScope(...)` per route afterwards (it reads `serviceScopes` when `s2sScopes` is absent).
193
+ *
194
+ * @throws `TypeError` when the middleware is built with options that are not valid for the
195
+ * catalog (unknown audience, a permission of another audience, no permission rule).
196
+ *
197
+ * @example
198
+ * ```ts
199
+ * app.use(
200
+ * '/v1/internal/messages/*',
201
+ * serviceTokenAuth({ audience: 'whatsapp-api', requiredScope: 'messages:send:text' }),
202
+ * )
203
+ * ```
204
+ */
205
+ function serviceTokenAuth(opts) {
206
+ require_delegated_token.assertServiceTokenOptions(opts);
207
+ return (0, hono_factory.createMiddleware)(async (c, next) => {
208
+ const bearer = c.req.header("authorization")?.match(BEARER_REGEX);
209
+ const result = bearer ? await require_delegated_token.verifyServiceToken(bearer[1], opts) : {
210
+ ok: false,
211
+ error: {
212
+ reason: "token_missing",
213
+ message: opts.messages?.token_missing ?? "Bearer token is missing"
214
+ }
215
+ };
216
+ if (!result.ok) {
217
+ if (result.error.reason === "scope_insufficient") return c.json({ error: {
218
+ code: "insufficient_scope",
219
+ message: result.error.message
220
+ } }, 403);
221
+ return c.json({ error: {
222
+ code: result.error.reason,
223
+ message: result.error.message
224
+ } }, 401);
225
+ }
226
+ c.set("serviceClientId", result.data.serviceClientId);
227
+ c.set("serviceClientSlug", result.data.serviceClientSlug);
228
+ c.set("serviceScopes", result.data.scopes);
229
+ await next();
230
+ });
231
+ }
232
+ /**
233
+ * Hono middleware that verifies the delegated token (ES256, `typ: 'dlg-at+jwt'`, `kid` `svc-…`, one
234
+ * `aud` = this service, never `auth-api`, mandatory `empresa`) sent as `Authorization: Bearer`. See
235
+ * `verifyDelegatedToken` for the token contract. It accepts NOTHING else: a service token, a user
236
+ * access token and a delegated token are three different types and each verifier takes only its own.
237
+ *
238
+ * On **success**: sets `c.var.userId`, `empresaId`, `producto`, `sessionId`, `actorChain` and
239
+ * `scopes`, then calls `next()`.
240
+ * On **failure**: HTTP 401 `{ error: { code: <reason>, message } }`, or HTTP 403 with code
241
+ * `insufficient_scope` when the token is valid but lacks the required scope.
242
+ *
243
+ * With `scopeCheck: 'deferred'` no permission is required here; check `c.var.scopes` in the route.
244
+ * (`requireScope` reads the scopes of `s2sAuth` / `serviceTokenAuth` and does not apply here.)
245
+ *
246
+ * The receiving service does not see the roles of the product: the product that acted is
247
+ * responsible for having checked the permission of the person before asking for the token.
248
+ *
249
+ * @throws `TypeError` when the middleware is built with options that are not valid for the catalog.
250
+ *
251
+ * @example
252
+ * ```ts
253
+ * app.use(
254
+ * '/v1/stock/*',
255
+ * delegatedTokenAuth({ audience: 'whatsapp-api', requiredScope: 'messages:send:text' }),
256
+ * )
257
+ * ```
258
+ */
259
+ function delegatedTokenAuth(opts) {
260
+ require_delegated_token.assertDelegatedTokenOptions(opts);
261
+ return (0, hono_factory.createMiddleware)(async (c, next) => {
262
+ const bearer = c.req.header("authorization")?.match(BEARER_REGEX);
263
+ const result = bearer ? await require_delegated_token.verifyDelegatedToken(bearer[1], opts) : {
264
+ ok: false,
265
+ error: {
266
+ reason: "token_missing",
267
+ message: opts.messages?.token_missing ?? "Bearer token is missing"
268
+ }
269
+ };
270
+ if (!result.ok) {
271
+ if (result.error.reason === "scope_insufficient") return c.json({ error: {
272
+ code: "insufficient_scope",
273
+ message: result.error.message
274
+ } }, 403);
275
+ return c.json({ error: {
276
+ code: result.error.reason,
277
+ message: result.error.message
278
+ } }, 401);
279
+ }
280
+ c.set("userId", result.data.userId);
281
+ c.set("empresaId", result.data.empresaId);
282
+ c.set("producto", result.data.producto);
283
+ c.set("sessionId", result.data.sessionId);
284
+ c.set("actorChain", result.data.actorChain);
285
+ c.set("scopes", result.data.scopes);
286
+ await next();
287
+ });
288
+ }
289
+ exports.COOKIE_MAX_AGE = require_constants$1.COOKIE_MAX_AGE;
290
+ exports.DEFAULT_ERROR_MESSAGES = require_parse_error_response.DEFAULT_ERROR_MESSAGES;
291
+ exports.HEADERS = require_constants.HEADERS;
292
+ exports.clearTokenCookies = require_cookies.clearTokenCookies;
293
+ exports.configureEvaAuth = require_parse_error_response.configureEvaAuth;
294
+ exports.delegatedTokenAuth = delegatedTokenAuth;
295
+ exports.evaAuth = evaAuth;
296
+ exports.evaAuthRoutes = evaAuthRoutes;
297
+ exports.getAuthUrl = require_parse_error_response.getAuthUrl;
298
+ exports.getCookieDomain = require_parse_error_response.getCookieDomain;
299
+ exports.getCookieNames = require_constants$1.getCookieNames;
300
+ exports.getEvaPayload = getEvaPayload;
301
+ exports.getSessionId = getSessionId;
302
+ exports.parseDeviceInfo = require_auth_handlers.parseDeviceInfo;
303
+ exports.readTokensFromCookies = require_cookies.readTokensFromCookies;
304
+ exports.requireScope = requireScope;
305
+ exports.s2sAuth = s2sAuth;
306
+ exports.serviceTokenAuth = serviceTokenAuth;
307
+ exports.setTokenCookies = require_cookies.setTokenCookies;
308
+
309
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["createHttpClient","createMiddleware","readTokensFromCookies","verifyAccessToken","deduplicateRefresh","setTokenCookies","clearTokenCookies","resolveErrorMessages","getErrorMessages","getErrorWire","Hono","buildAuthHandlers","createMiddleware","cloneRawRequest","verifyS2SRequest","verifyServiceToken","verifyDelegatedToken"],"sources":["../../src/hono/middleware.ts","../../src/hono/auth-routes.ts","../../src/hono/helpers.ts","../../src/hono/s2s.ts"],"sourcesContent":["import { createMiddleware } from 'hono/factory'\nimport type { ZodType } from 'zod'\nimport { verifyAccessToken } from '../jwt'\nimport {\n readTokensFromCookies,\n setTokenCookies,\n clearTokenCookies,\n} from '../cookies'\nimport { createHttpClient } from '../http-client'\nimport { deduplicateRefresh } from '../refresh-dedup'\nimport type { EvaTokenPayload } from '../types'\nimport { resolveErrorMessages, type EvaErrorMessages } from '../error-messages'\nimport {\n getErrorMessages,\n getErrorWire,\n validateErrorMessagesInput,\n} from '../config'\n\nconst client = createHttpClient()\n\nexport type EvaAuthOptions<TExtra extends Record<string, unknown>> = {\n extraClaimsSchema?: ZodType<TExtra>\n errorMessages?: Partial<EvaErrorMessages>\n}\n\nexport type EvaAuthVariables<TExtra extends Record<string, unknown>> = {\n evaPayload: EvaTokenPayload<TExtra>\n}\n\nexport function evaAuth<TExtra extends Record<string, unknown> = {}>(\n opts: EvaAuthOptions<TExtra> = {},\n) {\n if (opts.errorMessages !== undefined) {\n validateErrorMessagesInput(opts.errorMessages)\n }\n return createMiddleware<{ Variables: EvaAuthVariables<TExtra> }>(\n async (c, next) => {\n const cookieHeader = c.req.header('cookie') || null\n const { accessToken, refreshToken } = readTokensFromCookies(cookieHeader)\n\n if (accessToken) {\n const result = await verifyAccessToken<TExtra>(accessToken, {\n extraClaimsSchema: opts.extraClaimsSchema,\n })\n if (result.ok) {\n c.set('evaPayload', result.data)\n await next()\n return\n }\n }\n\n if (refreshToken) {\n const refreshResult = await deduplicateRefresh(refreshToken, () =>\n client.refresh({ refreshToken }),\n )\n if (refreshResult.ok && refreshResult.data.tokens) {\n const verifyResult = await verifyAccessToken<TExtra>(\n refreshResult.data.tokens.accessToken,\n {\n extraClaimsSchema: opts.extraClaimsSchema,\n },\n )\n if (verifyResult.ok) {\n c.set('evaPayload', verifyResult.data)\n const cookieHeaders = setTokenCookies(refreshResult.data.tokens)\n for (const cookie of cookieHeaders) {\n c.header('Set-Cookie', cookie, { append: true })\n }\n await next()\n return\n }\n }\n const clearHeaders = clearTokenCookies()\n for (const cookie of clearHeaders) {\n c.header('Set-Cookie', cookie, { append: true })\n }\n }\n\n const messages = resolveErrorMessages(\n opts.errorMessages,\n getErrorMessages(),\n )\n const wire = getErrorWire()\n if (wire === 'api') {\n return c.json(\n { error: { code: 'unauthorized', message: messages.authRequired } },\n 401,\n )\n }\n return c.json({ error: messages.authRequired }, 401)\n },\n )\n}\n","import { Hono } from 'hono'\nimport { buildAuthHandlers, type AuthHandlerOptions } from '../auth-handlers'\n\nexport type EvaAuthRoutesOptions = AuthHandlerOptions\n\nexport function evaAuthRoutes(opts: EvaAuthRoutesOptions = {}): Hono {\n const app = new Hono()\n const h = buildAuthHandlers(opts)\n\n app.use('*', h.originGuard)\n\n app.post('/get-code', h.getCode)\n app.post('/login', h.login)\n app.post('/refresh', h.refresh)\n app.post('/logout', h.logout)\n app.get('/me', h.getMe)\n app.patch('/me', h.updateMe)\n app.delete('/me', h.deleteMe)\n app.get('/empresas', h.getEmpresas)\n app.post('/empresa-activa', h.setActiveEmpresa)\n app.get('/sessions', h.getSessions)\n app.delete('/sessions/:id', h.deleteSession)\n app.delete('/sessions', h.deleteAllSessions)\n\n return app\n}\n","import type { Context } from 'hono'\nimport type { EvaTokenPayload } from '../types'\nimport type { EvaAuthVariables } from './middleware'\n\nexport function getEvaPayload<TExtra extends Record<string, unknown> = {}>(\n c: Context<{ Variables: EvaAuthVariables<TExtra> }>,\n): EvaTokenPayload<TExtra> {\n const payload = c.get('evaPayload')\n if (!payload) throw new Error('Middleware evaAuth no aplicado')\n return payload\n}\n\nexport function getSessionId<TExtra extends Record<string, unknown> = {}>(\n c: Context<{ Variables: EvaAuthVariables<TExtra> }>,\n): string {\n return getEvaPayload(c).sessionId\n}\n","/**\n * Hono middlewares for inbound S2S request authentication and scope-based authorization.\n *\n * REQ-HONO-AUTH-*, REQ-HONO-SCOPE-*, REQ-HONO-WIRE-*, REQ-API-02, REQ-API-03, REQ-API-05.\n *\n * Decisión in-flight B3-01: `cloneRawRequest` existe en Hono 4.12.19 bajo el entry point\n * `'hono/request'` (no `'hono/utils/request'` como estimaba el design). Se usa la ruta correcta\n * confirmada en node_modules/hono/package.json exports map: `\"./request\"` → `dist/request.js`.\n */\n\nimport { createMiddleware } from 'hono/factory'\nimport { cloneRawRequest } from 'hono/request'\nimport { verifyS2SRequest } from '../s2s/verify'\nimport {\n assertServiceTokenOptions,\n verifyServiceToken,\n} from '../s2s/service-token'\nimport type { ServiceTokenVerifyOptions } from '../s2s/service-token'\nimport {\n assertDelegatedTokenOptions,\n verifyDelegatedToken,\n} from '../s2s/delegated-token'\nimport type {\n DelegatedActor,\n DelegatedTokenVerifyOptions,\n} from '../s2s/delegated-token'\nimport type { S2SVerifyOptions } from '../s2s/types'\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * Options for the `s2sAuth` Hono middleware.\n * Extends `S2SVerifyOptions` (omits `request` — the middleware provides it internally).\n */\nexport type S2sAuthOptions = {\n /**\n * Callback that returns the plaintext secret (64 hex chars) for the given clientId,\n * or null if unknown. Return null — do NOT throw — for unknown clients.\n * D5 LOCKED: SDK does not assume any storage layer.\n */\n secretStore: S2SVerifyOptions['secretStore']\n /**\n * Optional callback that returns the scope list for the verified clientId.\n * If omitted, `c.var.s2sScopes` will be an empty array.\n */\n scopesOf?: (clientId: string) => Promise<readonly string[]>\n /**\n * Optional hook called after successful authentication and scope lookup, before `next()`.\n * Useful for audit logging, nonce tracking, or metrics.\n *\n * @throws If this hook throws, the middleware propagates the error and Hono returns HTTP 500.\n * Catch errors inside the hook if you want different behavior.\n *\n * @example\n * ```ts\n * onAuth: (clientId, scopes) => logger.info({ clientId, scopes }, 's2s authenticated'),\n * ```\n */\n onAuth?: (clientId: string, scopes: readonly string[]) => void | Promise<void>\n /**\n * Override timestamp validation window in seconds.\n * Default: `S2S_TIMESTAMP_WINDOW_SECONDS` (120).\n */\n timestampWindowSeconds?: number\n /**\n * Optional replay-protection cache. If provided, each verified request's key\n * (`${clientId}:${nonce}`) is atomically inserted with a TTL of\n * `2 * timestampWindowSeconds + 1`; if already present the request is rejected with `replay_detected`.\n *\n * @since v1.1.0\n * @see verifyS2SRequest for the full `setIfAbsent` contract and nonce format.\n */\n replayCache?: S2SVerifyOptions['replayCache']\n /**\n * Optional message overrides for error reasons (i18n / custom wording).\n * Any key not overridden falls back to the built-in English default.\n *\n * @since v1.1.0\n * @see verifyS2SRequest for the full `messages` contract and default strings.\n */\n messages?: S2SVerifyOptions['messages']\n}\n\n/**\n * Hono context variables set by `s2sAuth`.\n * Declare in your app type for full type inference:\n * ```ts\n * const app = new Hono<{ Variables: S2sAuthVariables }>()\n * ```\n */\nexport type S2sAuthVariables = {\n s2sClientId: string\n s2sScopes: readonly string[]\n}\n\n// ---------------------------------------------------------------------------\n// Middlewares\n// ---------------------------------------------------------------------------\n\n/**\n * Hono middleware that verifies inbound S2S requests signed with HMAC-SHA-256.\n *\n * On **success**: sets `c.var.s2sClientId` and `c.var.s2sScopes`, then calls `next()`.\n * On **failure**: responds with HTTP 401 `{ error: { code: <S2SVerifyReason>, message } }`.\n *\n * The middleware clones the request before reading the body (using Hono's `cloneRawRequest`),\n * so route handlers can still read the body after authentication — even if a prior middleware\n * already consumed the original stream.\n *\n * @see {@link requireScope} to enforce scope-based authorization after authentication.\n *\n * @example\n * ```ts\n * import { Hono } from 'hono'\n * import { s2sAuth, requireScope } from '@eva_solutions/auth-sdk/hono'\n *\n * const app = new Hono()\n *\n * app.use('/api/*', s2sAuth({\n * secretStore: async (clientId) => redis.get(`s2s:${clientId}:secret`),\n * scopesOf: async (clientId) => redis.smembers(`s2s:${clientId}:scopes`),\n * onAuth: (clientId, scopes) => logger.info({ clientId, scopes }, 's2s authenticated'),\n * }))\n *\n * app.get('/api/resource', (c) => {\n * const clientId = c.var.s2sClientId // available after s2sAuth\n * const scopes = c.var.s2sScopes\n * return c.json({ clientId, scopes })\n * })\n * ```\n */\nexport function s2sAuth(\n opts: S2sAuthOptions,\n): ReturnType<typeof createMiddleware<{ Variables: S2sAuthVariables }>> {\n return createMiddleware<{ Variables: S2sAuthVariables }>(async (c, next) => {\n // Clone the request so route handlers can still read the body.\n // cloneRawRequest (Hono 4.12.19) handles the case where a prior middleware\n // already consumed the original ReadableStream by using HonoRequest's body cache.\n const clonedRequest = await cloneRawRequest(c.req)\n\n const result = await verifyS2SRequest(clonedRequest, {\n secretStore: opts.secretStore,\n timestampWindowSeconds: opts.timestampWindowSeconds,\n replayCache: opts.replayCache,\n messages: opts.messages,\n })\n\n if (!result.ok) {\n return c.json(\n { error: { code: result.error.reason, message: result.error.message } },\n 401,\n )\n }\n\n const scopes: readonly string[] = opts.scopesOf\n ? await opts.scopesOf(result.data.clientId)\n : []\n\n c.set('s2sClientId', result.data.clientId)\n c.set('s2sScopes', scopes)\n\n if (opts.onAuth) {\n await opts.onAuth(result.data.clientId, scopes)\n }\n\n await next()\n })\n}\n\n/**\n * Hono middleware that requires a specific scope to be present in `c.var.s2sScopes`.\n *\n * Must be applied **after** `s2sAuth`. If `s2sAuth` was not applied, this middleware\n * throws a descriptive `Error` (programming error, results in HTTP 500).\n *\n * On **success** (scope present): calls `next()`.\n * On **failure** (scope absent): returns HTTP 403 with `{ error: { code: 'insufficient_scope', ... } }`.\n *\n * @throws `TypeError` at setup-time if the argument is invalid (empty object, empty array,\n * or both `all` and `any` specified simultaneously).\n * @throws `Error` at runtime if `s2sAuth` was not applied before this middleware.\n *\n * @example\n * ```ts\n * // Single scope (legacy — unchanged)\n * app.use('/admin/*', s2sAuth({ secretStore }), requireScope('admin'))\n *\n * // AND semantics — all scopes must be present\n * app.use('/admin/*', s2sAuth({ secretStore }), requireScope({ all: ['admin', 'audit'] }))\n *\n * // OR semantics — at least one scope must be present\n * app.use('/data/*', s2sAuth({ secretStore }), requireScope({ any: ['data:read', 'data:write'] }))\n * ```\n */\nexport function requireScope(\n scope: string,\n): ReturnType<typeof createMiddleware<{ Variables: S2sAuthVariables }>>\n/**\n * Hono middleware that requires **all** listed scopes to be present (AND semantics).\n *\n * On failure returns HTTP 403 with `{ error: { code: 'insufficient_scope', requiredAll, missing } }`.\n *\n * @since v1.1.0\n * @throws `TypeError` at setup-time if `all` is an empty array.\n */\nexport function requireScope(spec: {\n all: readonly string[]\n}): ReturnType<typeof createMiddleware<{ Variables: S2sAuthVariables }>>\n/**\n * Hono middleware that requires **at least one** of the listed scopes to be present (OR semantics).\n *\n * On failure returns HTTP 403 with `{ error: { code: 'insufficient_scope', requiredAny } }`.\n *\n * @since v1.1.0\n * @throws `TypeError` at setup-time if `any` is an empty array.\n */\nexport function requireScope(spec: {\n any: readonly string[]\n}): ReturnType<typeof createMiddleware<{ Variables: S2sAuthVariables }>>\nexport function requireScope(\n arg: string | { all?: readonly string[]; any?: readonly string[] },\n): ReturnType<typeof createMiddleware<{ Variables: S2sAuthVariables }>> {\n // Setup-time guards (D23)\n if (arg === null || arg === undefined) {\n throw new TypeError('requireScope: scope argument required')\n }\n if (typeof arg === 'object') {\n const hasAll = 'all' in arg && arg.all !== undefined\n const hasAny = 'any' in arg && arg.any !== undefined\n if (hasAll && hasAny) {\n throw new TypeError(\"requireScope: cannot use both 'all' and 'any'\")\n }\n if (!hasAll && !hasAny) {\n throw new TypeError(\"requireScope: must specify 'all' or 'any'\")\n }\n if (hasAll && arg.all!.length === 0) {\n throw new TypeError(\"requireScope: 'all' cannot be empty\")\n }\n if (hasAny && arg.any!.length === 0) {\n throw new TypeError(\"requireScope: 'any' cannot be empty\")\n }\n }\n\n return createMiddleware<{ Variables: S2sAuthVariables }>(async (c, next) => {\n // Tras `s2sAuth` (HMAC) vive en `s2sScopes`; tras `serviceTokenAuth` (Bearer), en `serviceScopes`.\n const vars =\n c.var.s2sScopes ??\n (c.var as unknown as { serviceScopes?: readonly string[] }).serviceScopes\n\n if (vars === undefined) {\n throw new Error(\n '[eva-auth-sdk] requireScope: no auth middleware applied — apply s2sAuth() or serviceTokenAuth() before requireScope()',\n )\n }\n\n if (typeof arg === 'string') {\n // Single scope — legacy wire format preserved (S-LEGACY-01)\n if (!vars.includes(arg)) {\n return c.json(\n { error: { code: 'insufficient_scope', required: arg } },\n 403,\n )\n }\n } else if ('all' in arg && arg.all) {\n // AND semantics\n const required = arg.all\n const missing = required.filter((s) => !vars.includes(s))\n if (missing.length > 0) {\n return c.json(\n {\n error: {\n code: 'insufficient_scope',\n requiredAll: required,\n missing,\n },\n },\n 403,\n )\n }\n } else if ('any' in arg && arg.any) {\n // OR semantics\n const required = arg.any\n const hasAnyScope = required.some((s) => vars.includes(s))\n if (!hasAnyScope) {\n return c.json(\n { error: { code: 'insufficient_scope', requiredAny: required } },\n 403,\n )\n }\n }\n\n await next()\n })\n}\n\n// ---------------------------------------------------------------------------\n// Token de servicio (Bearer de otro servicio, o del propio Auth en el OTP)\n// ---------------------------------------------------------------------------\n\n/** Options for `serviceTokenAuth`: those of `verifyServiceToken` (the middleware provides the token). */\nexport type ServiceTokenAuthOptions = ServiceTokenVerifyOptions\n\n/**\n * Hono context variables set by `serviceTokenAuth`.\n */\nexport type ServiceTokenAuthVariables = {\n /** `sub` del token: id interno estable del service client. Es la identidad. */\n serviceClientId: string\n /** `client_id` del token: slug del service client. Dato visible, no identidad. */\n serviceClientSlug: string\n serviceScopes: readonly string[]\n}\n\n// El esquema se compara sin distinguir mayúsculas (RFC 9110 §11.1: `bearer` también es válido).\nconst BEARER_REGEX =\n /^Bearer ([A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+)$/i\n\n/**\n * Hono middleware that verifies the service token (ES256, `typ: 'svc-at+jwt'`, `kid` `svc-…`, `aud`\n * of this service, `scope`) sent as `Authorization: Bearer`. See `verifyServiceToken` for the\n * token contract.\n *\n * On **success**: sets `c.var.serviceClientId` (`sub`), `c.var.serviceClientSlug` (`client_id`) and\n * `c.var.serviceScopes`, then calls `next()`.\n * On **failure**: HTTP 401 `{ error: { code: <ServiceTokenVerifyReason>, message } }`, or HTTP 403\n * with code `insufficient_scope` when the token is valid but lacks the required scope.\n *\n * JWKS/config failures are not rejections: they propagate and Hono answers 500.\n *\n * With `scopeCheck: 'deferred'` the token is authenticated but no permission is required here; mount\n * `requireScope(...)` per route afterwards (it reads `serviceScopes` when `s2sScopes` is absent).\n *\n * @throws `TypeError` when the middleware is built with options that are not valid for the\n * catalog (unknown audience, a permission of another audience, no permission rule).\n *\n * @example\n * ```ts\n * app.use(\n * '/v1/internal/messages/*',\n * serviceTokenAuth({ audience: 'whatsapp-api', requiredScope: 'messages:send:text' }),\n * )\n * ```\n */\nexport function serviceTokenAuth(\n opts: ServiceTokenAuthOptions,\n): ReturnType<\n typeof createMiddleware<{ Variables: ServiceTokenAuthVariables }>\n> {\n // Las opciones se validan al construir el middleware (falla al arrancar), no en cada request.\n assertServiceTokenOptions(opts)\n return createMiddleware<{ Variables: ServiceTokenAuthVariables }>(\n async (c, next) => {\n const bearer = c.req.header('authorization')?.match(BEARER_REGEX)\n const result = bearer\n ? await verifyServiceToken(bearer[1] as string, opts)\n : ({\n ok: false,\n error: {\n reason: 'token_missing',\n message:\n opts.messages?.token_missing ?? 'Bearer token is missing',\n },\n } as const)\n\n if (!result.ok) {\n if (result.error.reason === 'scope_insufficient') {\n return c.json(\n {\n error: {\n code: 'insufficient_scope',\n message: result.error.message,\n },\n },\n 403,\n )\n }\n return c.json(\n {\n error: { code: result.error.reason, message: result.error.message },\n },\n 401,\n )\n }\n\n c.set('serviceClientId', result.data.serviceClientId)\n c.set('serviceClientSlug', result.data.serviceClientSlug)\n c.set('serviceScopes', result.data.scopes)\n await next()\n },\n )\n}\n\n// ---------------------------------------------------------------------------\n// Token delegado (otro servicio actuando en nombre de un usuario)\n// ---------------------------------------------------------------------------\n\n/** Options for `delegatedTokenAuth`: those of `verifyDelegatedToken` (the middleware provides the token). */\nexport type DelegatedTokenAuthOptions = DelegatedTokenVerifyOptions\n\n/**\n * Hono context variables set by `delegatedTokenAuth`.\n */\nexport type DelegatedTokenAuthVariables = {\n /** `sub` del token: el usuario en cuyo nombre se actúa. */\n userId: string\n /** `empresa`: obligatoria en toda la cadena. */\n empresaId: string\n /** `producto` de origen de la cadena. */\n producto: string\n /** `sid`: sesión de origen. */\n sessionId: string\n /** Cadena de actores, del último (quien llama a este servicio) al primero. */\n actorChain: readonly DelegatedActor[]\n /** Permisos del token. */\n scopes: readonly string[]\n}\n\n/**\n * Hono middleware that verifies the delegated token (ES256, `typ: 'dlg-at+jwt'`, `kid` `svc-…`, one\n * `aud` = this service, never `auth-api`, mandatory `empresa`) sent as `Authorization: Bearer`. See\n * `verifyDelegatedToken` for the token contract. It accepts NOTHING else: a service token, a user\n * access token and a delegated token are three different types and each verifier takes only its own.\n *\n * On **success**: sets `c.var.userId`, `empresaId`, `producto`, `sessionId`, `actorChain` and\n * `scopes`, then calls `next()`.\n * On **failure**: HTTP 401 `{ error: { code: <reason>, message } }`, or HTTP 403 with code\n * `insufficient_scope` when the token is valid but lacks the required scope.\n *\n * With `scopeCheck: 'deferred'` no permission is required here; check `c.var.scopes` in the route.\n * (`requireScope` reads the scopes of `s2sAuth` / `serviceTokenAuth` and does not apply here.)\n *\n * The receiving service does not see the roles of the product: the product that acted is\n * responsible for having checked the permission of the person before asking for the token.\n *\n * @throws `TypeError` when the middleware is built with options that are not valid for the catalog.\n *\n * @example\n * ```ts\n * app.use(\n * '/v1/stock/*',\n * delegatedTokenAuth({ audience: 'whatsapp-api', requiredScope: 'messages:send:text' }),\n * )\n * ```\n */\nexport function delegatedTokenAuth(\n opts: DelegatedTokenAuthOptions,\n): ReturnType<\n typeof createMiddleware<{ Variables: DelegatedTokenAuthVariables }>\n> {\n assertDelegatedTokenOptions(opts)\n return createMiddleware<{ Variables: DelegatedTokenAuthVariables }>(\n async (c, next) => {\n const bearer = c.req.header('authorization')?.match(BEARER_REGEX)\n const result = bearer\n ? await verifyDelegatedToken(bearer[1] as string, opts)\n : ({\n ok: false,\n error: {\n reason: 'token_missing',\n message:\n opts.messages?.token_missing ?? 'Bearer token is missing',\n },\n } as const)\n\n if (!result.ok) {\n if (result.error.reason === 'scope_insufficient') {\n return c.json(\n {\n error: {\n code: 'insufficient_scope',\n message: result.error.message,\n },\n },\n 403,\n )\n }\n return c.json(\n {\n error: { code: result.error.reason, message: result.error.message },\n },\n 401,\n )\n }\n\n c.set('userId', result.data.userId)\n c.set('empresaId', result.data.empresaId)\n c.set('producto', result.data.producto)\n c.set('sessionId', result.data.sessionId)\n c.set('actorChain', result.data.actorChain)\n c.set('scopes', result.data.scopes)\n await next()\n },\n )\n}\n"],"mappings":"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"}
@@ -0,0 +1,272 @@
1
+ import { xi as HEADERS } from "../index-CZru7c5T.cjs";
2
+ import { c as EvaTokenPayload, n as DeviceInfo } from "../types-Ci0Jq0xB.cjs";
3
+ import { n as EvaErrorMessages, t as DEFAULT_ERROR_MESSAGES } from "../error-messages-CGpW1fsg.cjs";
4
+ import { t as AuthHandlerOptions } from "../auth-handlers-DRUUTEtW.cjs";
5
+ import { a as COOKIE_MAX_AGE, c as clearTokenCookies, i as getCookieDomain, l as readTokensFromCookies, n as configureEvaAuth, r as getAuthUrl, s as getCookieNames, t as ConfigureEvaAuthOptions, u as setTokenCookies } from "../config-3avoUa9e.cjs";
6
+ import { L as S2SVerifyOptions, at as DelegatedTokenVerifyOptions, nt as DelegatedActor, pt as ServiceTokenVerifyOptions } from "../types-Ai3iIFlB.cjs";
7
+ import { ZodType } from "zod";
8
+ import { Context, Hono } from "hono";
9
+ import { createMiddleware } from "hono/factory";
10
+ type EvaAuthOptions<TExtra extends Record<string, unknown>> = {
11
+ extraClaimsSchema?: ZodType<TExtra>;
12
+ errorMessages?: Partial<EvaErrorMessages>;
13
+ };
14
+ type EvaAuthVariables<TExtra extends Record<string, unknown>> = {
15
+ evaPayload: EvaTokenPayload<TExtra>;
16
+ };
17
+ declare function evaAuth<TExtra extends Record<string, unknown> = {}>(opts?: EvaAuthOptions<TExtra>): import("hono").MiddlewareHandler<{
18
+ Variables: EvaAuthVariables<TExtra>;
19
+ }, string, {}, Response>;
20
+ type EvaAuthRoutesOptions = AuthHandlerOptions;
21
+ declare function evaAuthRoutes(opts?: EvaAuthRoutesOptions): Hono;
22
+ declare function getEvaPayload<TExtra extends Record<string, unknown> = {}>(c: Context<{
23
+ Variables: EvaAuthVariables<TExtra>;
24
+ }>): EvaTokenPayload<TExtra>;
25
+ declare function getSessionId<TExtra extends Record<string, unknown> = {}>(c: Context<{
26
+ Variables: EvaAuthVariables<TExtra>;
27
+ }>): string;
28
+ declare function parseDeviceInfo(request: Request): DeviceInfo;
29
+ /**
30
+ * Options for the `s2sAuth` Hono middleware.
31
+ * Extends `S2SVerifyOptions` (omits `request` — the middleware provides it internally).
32
+ */
33
+ type S2sAuthOptions = {
34
+ /**
35
+ * Callback that returns the plaintext secret (64 hex chars) for the given clientId,
36
+ * or null if unknown. Return null — do NOT throw — for unknown clients.
37
+ * D5 LOCKED: SDK does not assume any storage layer.
38
+ */
39
+ secretStore: S2SVerifyOptions['secretStore'];
40
+ /**
41
+ * Optional callback that returns the scope list for the verified clientId.
42
+ * If omitted, `c.var.s2sScopes` will be an empty array.
43
+ */
44
+ scopesOf?: (clientId: string) => Promise<readonly string[]>;
45
+ /**
46
+ * Optional hook called after successful authentication and scope lookup, before `next()`.
47
+ * Useful for audit logging, nonce tracking, or metrics.
48
+ *
49
+ * @throws If this hook throws, the middleware propagates the error and Hono returns HTTP 500.
50
+ * Catch errors inside the hook if you want different behavior.
51
+ *
52
+ * @example
53
+ * ```ts
54
+ * onAuth: (clientId, scopes) => logger.info({ clientId, scopes }, 's2s authenticated'),
55
+ * ```
56
+ */
57
+ onAuth?: (clientId: string, scopes: readonly string[]) => void | Promise<void>;
58
+ /**
59
+ * Override timestamp validation window in seconds.
60
+ * Default: `S2S_TIMESTAMP_WINDOW_SECONDS` (120).
61
+ */
62
+ timestampWindowSeconds?: number;
63
+ /**
64
+ * Optional replay-protection cache. If provided, each verified request's key
65
+ * (`${clientId}:${nonce}`) is atomically inserted with a TTL of
66
+ * `2 * timestampWindowSeconds + 1`; if already present the request is rejected with `replay_detected`.
67
+ *
68
+ * @since v1.1.0
69
+ * @see verifyS2SRequest for the full `setIfAbsent` contract and nonce format.
70
+ */
71
+ replayCache?: S2SVerifyOptions['replayCache'];
72
+ /**
73
+ * Optional message overrides for error reasons (i18n / custom wording).
74
+ * Any key not overridden falls back to the built-in English default.
75
+ *
76
+ * @since v1.1.0
77
+ * @see verifyS2SRequest for the full `messages` contract and default strings.
78
+ */
79
+ messages?: S2SVerifyOptions['messages'];
80
+ };
81
+ /**
82
+ * Hono context variables set by `s2sAuth`.
83
+ * Declare in your app type for full type inference:
84
+ * ```ts
85
+ * const app = new Hono<{ Variables: S2sAuthVariables }>()
86
+ * ```
87
+ */
88
+ type S2sAuthVariables = {
89
+ s2sClientId: string;
90
+ s2sScopes: readonly string[];
91
+ };
92
+ /**
93
+ * Hono middleware that verifies inbound S2S requests signed with HMAC-SHA-256.
94
+ *
95
+ * On **success**: sets `c.var.s2sClientId` and `c.var.s2sScopes`, then calls `next()`.
96
+ * On **failure**: responds with HTTP 401 `{ error: { code: <S2SVerifyReason>, message } }`.
97
+ *
98
+ * The middleware clones the request before reading the body (using Hono's `cloneRawRequest`),
99
+ * so route handlers can still read the body after authentication — even if a prior middleware
100
+ * already consumed the original stream.
101
+ *
102
+ * @see {@link requireScope} to enforce scope-based authorization after authentication.
103
+ *
104
+ * @example
105
+ * ```ts
106
+ * import { Hono } from 'hono'
107
+ * import { s2sAuth, requireScope } from '@eva_solutions/auth-sdk/hono'
108
+ *
109
+ * const app = new Hono()
110
+ *
111
+ * app.use('/api/*', s2sAuth({
112
+ * secretStore: async (clientId) => redis.get(`s2s:${clientId}:secret`),
113
+ * scopesOf: async (clientId) => redis.smembers(`s2s:${clientId}:scopes`),
114
+ * onAuth: (clientId, scopes) => logger.info({ clientId, scopes }, 's2s authenticated'),
115
+ * }))
116
+ *
117
+ * app.get('/api/resource', (c) => {
118
+ * const clientId = c.var.s2sClientId // available after s2sAuth
119
+ * const scopes = c.var.s2sScopes
120
+ * return c.json({ clientId, scopes })
121
+ * })
122
+ * ```
123
+ */
124
+ declare function s2sAuth(opts: S2sAuthOptions): ReturnType<typeof createMiddleware<{
125
+ Variables: S2sAuthVariables;
126
+ }>>;
127
+ /**
128
+ * Hono middleware that requires a specific scope to be present in `c.var.s2sScopes`.
129
+ *
130
+ * Must be applied **after** `s2sAuth`. If `s2sAuth` was not applied, this middleware
131
+ * throws a descriptive `Error` (programming error, results in HTTP 500).
132
+ *
133
+ * On **success** (scope present): calls `next()`.
134
+ * On **failure** (scope absent): returns HTTP 403 with `{ error: { code: 'insufficient_scope', ... } }`.
135
+ *
136
+ * @throws `TypeError` at setup-time if the argument is invalid (empty object, empty array,
137
+ * or both `all` and `any` specified simultaneously).
138
+ * @throws `Error` at runtime if `s2sAuth` was not applied before this middleware.
139
+ *
140
+ * @example
141
+ * ```ts
142
+ * // Single scope (legacy — unchanged)
143
+ * app.use('/admin/*', s2sAuth({ secretStore }), requireScope('admin'))
144
+ *
145
+ * // AND semantics — all scopes must be present
146
+ * app.use('/admin/*', s2sAuth({ secretStore }), requireScope({ all: ['admin', 'audit'] }))
147
+ *
148
+ * // OR semantics — at least one scope must be present
149
+ * app.use('/data/*', s2sAuth({ secretStore }), requireScope({ any: ['data:read', 'data:write'] }))
150
+ * ```
151
+ */
152
+ declare function requireScope(scope: string): ReturnType<typeof createMiddleware<{
153
+ Variables: S2sAuthVariables;
154
+ }>>;
155
+ /**
156
+ * Hono middleware that requires **all** listed scopes to be present (AND semantics).
157
+ *
158
+ * On failure returns HTTP 403 with `{ error: { code: 'insufficient_scope', requiredAll, missing } }`.
159
+ *
160
+ * @since v1.1.0
161
+ * @throws `TypeError` at setup-time if `all` is an empty array.
162
+ */
163
+ declare function requireScope(spec: {
164
+ all: readonly string[];
165
+ }): ReturnType<typeof createMiddleware<{
166
+ Variables: S2sAuthVariables;
167
+ }>>;
168
+ /**
169
+ * Hono middleware that requires **at least one** of the listed scopes to be present (OR semantics).
170
+ *
171
+ * On failure returns HTTP 403 with `{ error: { code: 'insufficient_scope', requiredAny } }`.
172
+ *
173
+ * @since v1.1.0
174
+ * @throws `TypeError` at setup-time if `any` is an empty array.
175
+ */
176
+ declare function requireScope(spec: {
177
+ any: readonly string[];
178
+ }): ReturnType<typeof createMiddleware<{
179
+ Variables: S2sAuthVariables;
180
+ }>>;
181
+ /** Options for `serviceTokenAuth`: those of `verifyServiceToken` (the middleware provides the token). */
182
+ type ServiceTokenAuthOptions = ServiceTokenVerifyOptions;
183
+ /**
184
+ * Hono context variables set by `serviceTokenAuth`.
185
+ */
186
+ type ServiceTokenAuthVariables = {
187
+ /** `sub` del token: id interno estable del service client. Es la identidad. */
188
+ serviceClientId: string;
189
+ /** `client_id` del token: slug del service client. Dato visible, no identidad. */
190
+ serviceClientSlug: string;
191
+ serviceScopes: readonly string[];
192
+ };
193
+ /**
194
+ * Hono middleware that verifies the service token (ES256, `typ: 'svc-at+jwt'`, `kid` `svc-…`, `aud`
195
+ * of this service, `scope`) sent as `Authorization: Bearer`. See `verifyServiceToken` for the
196
+ * token contract.
197
+ *
198
+ * On **success**: sets `c.var.serviceClientId` (`sub`), `c.var.serviceClientSlug` (`client_id`) and
199
+ * `c.var.serviceScopes`, then calls `next()`.
200
+ * On **failure**: HTTP 401 `{ error: { code: <ServiceTokenVerifyReason>, message } }`, or HTTP 403
201
+ * with code `insufficient_scope` when the token is valid but lacks the required scope.
202
+ *
203
+ * JWKS/config failures are not rejections: they propagate and Hono answers 500.
204
+ *
205
+ * With `scopeCheck: 'deferred'` the token is authenticated but no permission is required here; mount
206
+ * `requireScope(...)` per route afterwards (it reads `serviceScopes` when `s2sScopes` is absent).
207
+ *
208
+ * @throws `TypeError` when the middleware is built with options that are not valid for the
209
+ * catalog (unknown audience, a permission of another audience, no permission rule).
210
+ *
211
+ * @example
212
+ * ```ts
213
+ * app.use(
214
+ * '/v1/internal/messages/*',
215
+ * serviceTokenAuth({ audience: 'whatsapp-api', requiredScope: 'messages:send:text' }),
216
+ * )
217
+ * ```
218
+ */
219
+ declare function serviceTokenAuth(opts: ServiceTokenAuthOptions): ReturnType<typeof createMiddleware<{
220
+ Variables: ServiceTokenAuthVariables;
221
+ }>>;
222
+ /** Options for `delegatedTokenAuth`: those of `verifyDelegatedToken` (the middleware provides the token). */
223
+ type DelegatedTokenAuthOptions = DelegatedTokenVerifyOptions;
224
+ /**
225
+ * Hono context variables set by `delegatedTokenAuth`.
226
+ */
227
+ type DelegatedTokenAuthVariables = {
228
+ /** `sub` del token: el usuario en cuyo nombre se actúa. */
229
+ userId: string;
230
+ /** `empresa`: obligatoria en toda la cadena. */
231
+ empresaId: string;
232
+ /** `producto` de origen de la cadena. */
233
+ producto: string;
234
+ /** `sid`: sesión de origen. */
235
+ sessionId: string;
236
+ /** Cadena de actores, del último (quien llama a este servicio) al primero. */
237
+ actorChain: readonly DelegatedActor[];
238
+ /** Permisos del token. */
239
+ scopes: readonly string[];
240
+ };
241
+ /**
242
+ * Hono middleware that verifies the delegated token (ES256, `typ: 'dlg-at+jwt'`, `kid` `svc-…`, one
243
+ * `aud` = this service, never `auth-api`, mandatory `empresa`) sent as `Authorization: Bearer`. See
244
+ * `verifyDelegatedToken` for the token contract. It accepts NOTHING else: a service token, a user
245
+ * access token and a delegated token are three different types and each verifier takes only its own.
246
+ *
247
+ * On **success**: sets `c.var.userId`, `empresaId`, `producto`, `sessionId`, `actorChain` and
248
+ * `scopes`, then calls `next()`.
249
+ * On **failure**: HTTP 401 `{ error: { code: <reason>, message } }`, or HTTP 403 with code
250
+ * `insufficient_scope` when the token is valid but lacks the required scope.
251
+ *
252
+ * With `scopeCheck: 'deferred'` no permission is required here; check `c.var.scopes` in the route.
253
+ * (`requireScope` reads the scopes of `s2sAuth` / `serviceTokenAuth` and does not apply here.)
254
+ *
255
+ * The receiving service does not see the roles of the product: the product that acted is
256
+ * responsible for having checked the permission of the person before asking for the token.
257
+ *
258
+ * @throws `TypeError` when the middleware is built with options that are not valid for the catalog.
259
+ *
260
+ * @example
261
+ * ```ts
262
+ * app.use(
263
+ * '/v1/stock/*',
264
+ * delegatedTokenAuth({ audience: 'whatsapp-api', requiredScope: 'messages:send:text' }),
265
+ * )
266
+ * ```
267
+ */
268
+ declare function delegatedTokenAuth(opts: DelegatedTokenAuthOptions): ReturnType<typeof createMiddleware<{
269
+ Variables: DelegatedTokenAuthVariables;
270
+ }>>;
271
+ export { COOKIE_MAX_AGE, type ConfigureEvaAuthOptions, DEFAULT_ERROR_MESSAGES, type DelegatedTokenAuthOptions, type DelegatedTokenAuthVariables, type EvaAuthOptions, type EvaAuthRoutesOptions, type EvaAuthVariables, type EvaErrorMessages, HEADERS, type S2sAuthOptions, type S2sAuthVariables, type ServiceTokenAuthOptions, type ServiceTokenAuthVariables, clearTokenCookies, configureEvaAuth, delegatedTokenAuth, evaAuth, evaAuthRoutes, getAuthUrl, getCookieDomain, getCookieNames, getEvaPayload, getSessionId, parseDeviceInfo, readTokensFromCookies, requireScope, s2sAuth, serviceTokenAuth, setTokenCookies };
272
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/hono/middleware.ts","../../src/hono/auth-routes.ts","../../src/hono/helpers.ts","../../src/hono/device-info.ts","../../src/hono/s2s.ts"],"mappings":";;;;;;;;;KAoBY,eAAe,eAAe;EACxC,oBAAoB,QAAQ;EAC5B,gBAAgB,QAAQ;;KAGd,iBAAiB,eAAe;EAC1C,YAAY,gBAAgB;;iBAGd,QAAQ,eAAe,8BACrC,OAAM,eAAe,yBAAY;EAKI,WAAA,iBAAiB;eAyDvD;KCzFW,uBAAuB;iBAEnB,cAAc,OAAM,uBAA4B;iBCDhD,cAAc,eAAe,8BAC3C,GAAG;EAAU,WAAW,iBAAiB;KACxC,gBAAgB;iBAMH,aAAa,eAAe,8BAC1C,GAAG;EAAU,WAAW,iBAAiB;;iBCV3B,gBAAgB,SAAS,UAAU;;;;;KCiCvC;;;;;;EAMV,aAAa;;;;;EAKb,YAAY,qBAAqB;;;;;;;;;;;;;EAajC,UAAU,kBAAkB,qCAAqC;;;;;EAKjE;;;;;;;;;EASA,cAAc;;;;;;;;EAQd,WAAW;;;;;;;;;KAUD;EACV;EACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAuCc,QACd,MAAM,iBACL,kBAAkB;EAAmB,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA6DnC,aACd,gBACC,kBAAkB;EAAmB,WAAW;;;;;;;;;;iBASnC,aAAa;EAC3B;IACE,kBAAkB;EAAmB,WAAW;;;;;;;;;;iBASpC,aAAa;EAC3B;IACE,kBAAkB;EAAmB,WAAW;;;KAkFxC,0BAA0B;;;;KAK1B;;EAEV;;EAEA;EACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAiCc,iBACd,MAAM,0BACL,kBACM;EAAmB,WAAW;;;KAmD3B,4BAA4B;;;;KAK5B;;EAEV;;EAEA;;EAEA;;EAEA;;EAEA,qBAAqB;;EAErB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA8Bc,mBACd,MAAM,4BACL,kBACM;EAAmB,WAAW"}