@_mustachio/openauth 0.9.2 → 0.10.0

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 (712) hide show
  1. package/dist/esm/adapters/d1/audit-log.js +15 -0
  2. package/dist/esm/adapters/d1/config-store.js +45 -0
  3. package/dist/esm/adapters/d1/index.js +12 -0
  4. package/dist/esm/adapters/d1/key-store.js +116 -0
  5. package/dist/esm/adapters/d1/method-store.js +52 -0
  6. package/dist/esm/adapters/d1/migrations.js +77 -0
  7. package/dist/esm/adapters/d1/session-store.js +134 -0
  8. package/dist/esm/adapters/d1/session.js +18 -0
  9. package/dist/esm/adapters/d1/token-store.js +140 -0
  10. package/dist/esm/adapters/durable-object/index.js +3 -0
  11. package/dist/esm/adapters/durable-object/session-store.js +139 -0
  12. package/dist/esm/adapters/durable-object/types.js +0 -0
  13. package/dist/esm/adapters/dynamo/audit-log.js +23 -0
  14. package/dist/esm/adapters/dynamo/client.js +0 -0
  15. package/dist/esm/adapters/dynamo/config-store.js +57 -0
  16. package/dist/esm/adapters/dynamo/index.js +10 -0
  17. package/dist/esm/adapters/dynamo/key-store.js +188 -0
  18. package/dist/esm/adapters/dynamo/method-store.js +72 -0
  19. package/dist/esm/adapters/dynamo/passkey-credential-store.js +83 -0
  20. package/dist/esm/adapters/dynamo/sdk.js +128 -0
  21. package/dist/esm/adapters/dynamo/session-store.js +173 -0
  22. package/dist/esm/adapters/dynamo/token-store.js +178 -0
  23. package/dist/esm/adapters/kms/in-memory-backing.js +28 -0
  24. package/dist/esm/adapters/kms/index.js +5 -0
  25. package/dist/esm/adapters/kms/key-store.js +129 -0
  26. package/dist/esm/adapters/kms/sdk.js +23 -0
  27. package/dist/esm/adapters/kms/types.js +0 -0
  28. package/dist/esm/adapters/kv/audit-log.js +21 -0
  29. package/dist/esm/adapters/kv/config-store.js +43 -0
  30. package/dist/esm/adapters/kv/index.js +5 -0
  31. package/dist/esm/adapters/kv/method-store.js +63 -0
  32. package/dist/esm/adapters/kv/types.js +0 -0
  33. package/dist/esm/adapters/memory/audit-log.js +16 -0
  34. package/dist/esm/adapters/memory/clock.js +5 -0
  35. package/dist/esm/adapters/memory/config-store.js +31 -0
  36. package/dist/esm/adapters/memory/index.js +10 -0
  37. package/dist/esm/adapters/memory/key-store.js +78 -0
  38. package/dist/esm/adapters/memory/method-store.js +43 -0
  39. package/dist/esm/adapters/memory/passkey-credential-store.js +53 -0
  40. package/dist/esm/adapters/memory/session-store.js +82 -0
  41. package/dist/esm/adapters/memory/token-store.js +91 -0
  42. package/dist/esm/adapters/postgres/audit-log.js +16 -0
  43. package/dist/esm/adapters/postgres/config-store.js +48 -0
  44. package/dist/esm/adapters/postgres/executor.js +21 -0
  45. package/dist/esm/adapters/postgres/index.js +13 -0
  46. package/dist/esm/adapters/postgres/key-store.js +191 -0
  47. package/dist/esm/adapters/postgres/method-store.js +61 -0
  48. package/dist/esm/adapters/postgres/migrations.js +111 -0
  49. package/dist/esm/adapters/postgres/passkey-credential-store.js +80 -0
  50. package/dist/esm/adapters/postgres/session-store.js +135 -0
  51. package/dist/esm/adapters/postgres/token-store.js +151 -0
  52. package/dist/esm/client.js +26 -10
  53. package/dist/esm/domain/audit.js +13 -0
  54. package/dist/esm/domain/authorize.js +212 -0
  55. package/dist/esm/domain/callback.js +173 -0
  56. package/dist/esm/domain/client-auth.js +61 -0
  57. package/dist/esm/domain/client-credentials.js +91 -0
  58. package/dist/esm/domain/crypto.js +97 -0
  59. package/dist/esm/domain/discovery.js +41 -0
  60. package/dist/esm/domain/introspect.js +51 -0
  61. package/dist/esm/domain/jwt.js +43 -0
  62. package/dist/esm/domain/method-cache.js +136 -0
  63. package/dist/esm/domain/method-dispatch.js +36 -0
  64. package/dist/esm/domain/method-route.js +108 -0
  65. package/dist/esm/domain/pkce.js +16 -0
  66. package/dist/esm/domain/refresh.js +91 -0
  67. package/dist/esm/domain/revoke.js +81 -0
  68. package/dist/esm/domain/state-envelope.js +80 -0
  69. package/dist/esm/domain/token-exchange.js +101 -0
  70. package/dist/esm/domain/token.js +205 -0
  71. package/dist/esm/domain/userinfo.js +27 -0
  72. package/dist/esm/http/context.js +7 -0
  73. package/dist/esm/http/cookies.js +98 -0
  74. package/dist/esm/http/errors.js +71 -0
  75. package/dist/esm/http/handlers/authorize.js +163 -0
  76. package/dist/esm/http/handlers/callback.js +53 -0
  77. package/dist/esm/http/handlers/metadata.js +34 -0
  78. package/dist/esm/http/handlers/method-route.js +87 -0
  79. package/dist/esm/http/handlers/revocation.js +98 -0
  80. package/dist/esm/http/handlers/token.js +167 -0
  81. package/dist/esm/http/handlers/userinfo.js +54 -0
  82. package/dist/esm/http/middleware/error.js +15 -0
  83. package/dist/esm/http/middleware/tenant.js +102 -0
  84. package/dist/esm/http/resolver.js +15 -0
  85. package/dist/esm/http/router.js +35 -0
  86. package/dist/esm/http/schemas/authorize.js +24 -0
  87. package/dist/esm/http/schemas/revocation.js +18 -0
  88. package/dist/esm/http/schemas/token.js +57 -0
  89. package/dist/esm/index.js +121 -9
  90. package/dist/esm/methods/code.js +221 -0
  91. package/dist/esm/methods/m2m.js +41 -0
  92. package/dist/esm/methods/oauth2-factory.js +84 -0
  93. package/dist/esm/methods/oauth2-generic.js +196 -0
  94. package/dist/esm/methods/oidc-generic.js +53 -0
  95. package/dist/esm/methods/passkey.js +275 -0
  96. package/dist/esm/methods/password-hash.js +79 -0
  97. package/dist/esm/methods/password.js +166 -0
  98. package/dist/esm/methods/providers/apple.js +29 -0
  99. package/dist/esm/methods/providers/cognito.js +37 -0
  100. package/dist/esm/methods/providers/discord.js +28 -0
  101. package/dist/esm/methods/providers/facebook.js +42 -0
  102. package/dist/esm/methods/providers/github.js +29 -0
  103. package/dist/esm/methods/providers/google.js +29 -0
  104. package/dist/esm/methods/providers/index.js +17 -0
  105. package/dist/esm/methods/providers/jumpcloud.js +27 -0
  106. package/dist/esm/methods/providers/keycloak.js +32 -0
  107. package/dist/esm/methods/providers/linkedin.js +28 -0
  108. package/dist/esm/methods/providers/microsoft.js +28 -0
  109. package/dist/esm/methods/providers/slack.js +30 -0
  110. package/dist/esm/methods/providers/spotify.js +28 -0
  111. package/dist/esm/methods/providers/twitch.js +28 -0
  112. package/dist/esm/methods/providers/x.js +28 -0
  113. package/dist/esm/methods/providers/yahoo.js +27 -0
  114. package/dist/esm/pkce.js +4 -16
  115. package/dist/esm/ports/audit-log.js +0 -0
  116. package/dist/esm/ports/config-store.js +0 -0
  117. package/dist/esm/ports/key-store.js +0 -0
  118. package/dist/esm/ports/method-store.js +0 -0
  119. package/dist/esm/ports/session-store.js +0 -0
  120. package/dist/esm/ports/token-store.js +0 -0
  121. package/dist/esm/types/authorization.js +0 -0
  122. package/dist/esm/types/error.js +65 -0
  123. package/dist/esm/types/flow.js +0 -0
  124. package/dist/esm/types/idp.js +0 -0
  125. package/dist/esm/types/method.js +0 -0
  126. package/dist/esm/types/picker.js +0 -0
  127. package/dist/esm/types/result.js +11 -0
  128. package/dist/esm/types/subject.js +0 -0
  129. package/dist/esm/types/tenant.js +5 -0
  130. package/dist/esm/types/token.js +0 -0
  131. package/dist/esm/ui/forms.js +253 -0
  132. package/dist/esm/ui/index.js +8 -0
  133. package/dist/esm/ui/picker.js +49 -0
  134. package/dist/types/adapters/d1/audit-log.d.ts +19 -0
  135. package/dist/types/adapters/d1/audit-log.d.ts.map +1 -0
  136. package/dist/types/adapters/d1/config-store.d.ts +20 -0
  137. package/dist/types/adapters/d1/config-store.d.ts.map +1 -0
  138. package/dist/types/adapters/d1/index.d.ts +35 -0
  139. package/dist/types/adapters/d1/index.d.ts.map +1 -0
  140. package/dist/types/adapters/d1/key-store.d.ts +17 -0
  141. package/dist/types/adapters/d1/key-store.d.ts.map +1 -0
  142. package/dist/types/adapters/d1/method-store.d.ts +21 -0
  143. package/dist/types/adapters/d1/method-store.d.ts.map +1 -0
  144. package/dist/types/adapters/d1/migrations.d.ts +18 -0
  145. package/dist/types/adapters/d1/migrations.d.ts.map +1 -0
  146. package/dist/types/adapters/d1/session-store.d.ts +20 -0
  147. package/dist/types/adapters/d1/session-store.d.ts.map +1 -0
  148. package/dist/types/adapters/d1/session.d.ts +18 -0
  149. package/dist/types/adapters/d1/session.d.ts.map +1 -0
  150. package/dist/types/adapters/d1/token-store.d.ts +29 -0
  151. package/dist/types/adapters/d1/token-store.d.ts.map +1 -0
  152. package/dist/types/adapters/d1/types.d.ts +43 -0
  153. package/dist/types/adapters/d1/types.d.ts.map +1 -0
  154. package/dist/types/adapters/durable-object/index.d.ts +17 -0
  155. package/dist/types/adapters/durable-object/index.d.ts.map +1 -0
  156. package/dist/types/adapters/durable-object/session-store.d.ts +21 -0
  157. package/dist/types/adapters/durable-object/session-store.d.ts.map +1 -0
  158. package/dist/types/adapters/durable-object/types.d.ts +23 -0
  159. package/dist/types/adapters/durable-object/types.d.ts.map +1 -0
  160. package/dist/types/adapters/dynamo/audit-log.d.ts +19 -0
  161. package/dist/types/adapters/dynamo/audit-log.d.ts.map +1 -0
  162. package/dist/types/adapters/dynamo/client.d.ts +111 -0
  163. package/dist/types/adapters/dynamo/client.d.ts.map +1 -0
  164. package/dist/types/adapters/dynamo/config-store.d.ts +21 -0
  165. package/dist/types/adapters/dynamo/config-store.d.ts.map +1 -0
  166. package/dist/types/adapters/dynamo/index.d.ts +60 -0
  167. package/dist/types/adapters/dynamo/index.d.ts.map +1 -0
  168. package/dist/types/adapters/dynamo/key-store.d.ts +23 -0
  169. package/dist/types/adapters/dynamo/key-store.d.ts.map +1 -0
  170. package/dist/types/adapters/dynamo/method-store.d.ts +20 -0
  171. package/dist/types/adapters/dynamo/method-store.d.ts.map +1 -0
  172. package/dist/types/adapters/dynamo/passkey-credential-store.d.ts +47 -0
  173. package/dist/types/adapters/dynamo/passkey-credential-store.d.ts.map +1 -0
  174. package/dist/types/adapters/dynamo/sdk.d.ts +23 -0
  175. package/dist/types/adapters/dynamo/sdk.d.ts.map +1 -0
  176. package/dist/types/adapters/dynamo/session-store.d.ts +20 -0
  177. package/dist/types/adapters/dynamo/session-store.d.ts.map +1 -0
  178. package/dist/types/adapters/dynamo/token-store.d.ts +29 -0
  179. package/dist/types/adapters/dynamo/token-store.d.ts.map +1 -0
  180. package/dist/types/adapters/kms/in-memory-backing.d.ts +9 -0
  181. package/dist/types/adapters/kms/in-memory-backing.d.ts.map +1 -0
  182. package/dist/types/adapters/kms/index.d.ts +35 -0
  183. package/dist/types/adapters/kms/index.d.ts.map +1 -0
  184. package/dist/types/adapters/kms/key-store.d.ts +20 -0
  185. package/dist/types/adapters/kms/key-store.d.ts.map +1 -0
  186. package/dist/types/adapters/kms/sdk.d.ts +16 -0
  187. package/dist/types/adapters/kms/sdk.d.ts.map +1 -0
  188. package/dist/types/adapters/kms/types.d.ts +58 -0
  189. package/dist/types/adapters/kms/types.d.ts.map +1 -0
  190. package/dist/types/adapters/kv/audit-log.d.ts +22 -0
  191. package/dist/types/adapters/kv/audit-log.d.ts.map +1 -0
  192. package/dist/types/adapters/kv/config-store.d.ts +25 -0
  193. package/dist/types/adapters/kv/config-store.d.ts.map +1 -0
  194. package/dist/types/adapters/kv/index.d.ts +21 -0
  195. package/dist/types/adapters/kv/index.d.ts.map +1 -0
  196. package/dist/types/adapters/kv/method-store.d.ts +23 -0
  197. package/dist/types/adapters/kv/method-store.d.ts.map +1 -0
  198. package/dist/types/adapters/kv/types.d.ts +28 -0
  199. package/dist/types/adapters/kv/types.d.ts.map +1 -0
  200. package/dist/types/adapters/memory/audit-log.d.ts +18 -0
  201. package/dist/types/adapters/memory/audit-log.d.ts.map +1 -0
  202. package/dist/types/adapters/memory/clock.d.ts +7 -0
  203. package/dist/types/adapters/memory/clock.d.ts.map +1 -0
  204. package/dist/types/adapters/memory/config-store.d.ts +19 -0
  205. package/dist/types/adapters/memory/config-store.d.ts.map +1 -0
  206. package/dist/types/adapters/memory/index.d.ts +15 -0
  207. package/dist/types/adapters/memory/index.d.ts.map +1 -0
  208. package/dist/types/adapters/memory/key-store.d.ts +17 -0
  209. package/dist/types/adapters/memory/key-store.d.ts.map +1 -0
  210. package/dist/types/adapters/memory/method-store.d.ts +26 -0
  211. package/dist/types/adapters/memory/method-store.d.ts.map +1 -0
  212. package/dist/types/adapters/memory/passkey-credential-store.d.ts +43 -0
  213. package/dist/types/adapters/memory/passkey-credential-store.d.ts.map +1 -0
  214. package/dist/types/adapters/memory/session-store.d.ts +19 -0
  215. package/dist/types/adapters/memory/session-store.d.ts.map +1 -0
  216. package/dist/types/adapters/memory/token-store.d.ts +28 -0
  217. package/dist/types/adapters/memory/token-store.d.ts.map +1 -0
  218. package/dist/types/adapters/postgres/audit-log.d.ts +18 -0
  219. package/dist/types/adapters/postgres/audit-log.d.ts.map +1 -0
  220. package/dist/types/adapters/postgres/config-store.d.ts +21 -0
  221. package/dist/types/adapters/postgres/config-store.d.ts.map +1 -0
  222. package/dist/types/adapters/postgres/executor.d.ts +48 -0
  223. package/dist/types/adapters/postgres/executor.d.ts.map +1 -0
  224. package/dist/types/adapters/postgres/index.d.ts +39 -0
  225. package/dist/types/adapters/postgres/index.d.ts.map +1 -0
  226. package/dist/types/adapters/postgres/key-store.d.ts +23 -0
  227. package/dist/types/adapters/postgres/key-store.d.ts.map +1 -0
  228. package/dist/types/adapters/postgres/method-store.d.ts +21 -0
  229. package/dist/types/adapters/postgres/method-store.d.ts.map +1 -0
  230. package/dist/types/adapters/postgres/migrations.d.ts +22 -0
  231. package/dist/types/adapters/postgres/migrations.d.ts.map +1 -0
  232. package/dist/types/adapters/postgres/passkey-credential-store.d.ts +48 -0
  233. package/dist/types/adapters/postgres/passkey-credential-store.d.ts.map +1 -0
  234. package/dist/types/adapters/postgres/session-store.d.ts +20 -0
  235. package/dist/types/adapters/postgres/session-store.d.ts.map +1 -0
  236. package/dist/types/adapters/postgres/token-store.d.ts +30 -0
  237. package/dist/types/adapters/postgres/token-store.d.ts.map +1 -0
  238. package/dist/types/client.d.ts +1 -1
  239. package/dist/types/client.d.ts.map +1 -1
  240. package/dist/types/domain/audit.d.ts +17 -0
  241. package/dist/types/domain/audit.d.ts.map +1 -0
  242. package/dist/types/domain/authorize.d.ts +125 -0
  243. package/dist/types/domain/authorize.d.ts.map +1 -0
  244. package/dist/types/domain/callback.d.ts +70 -0
  245. package/dist/types/domain/callback.d.ts.map +1 -0
  246. package/dist/types/domain/client-auth.d.ts +57 -0
  247. package/dist/types/domain/client-auth.d.ts.map +1 -0
  248. package/dist/types/domain/client-credentials.d.ts +52 -0
  249. package/dist/types/domain/client-credentials.d.ts.map +1 -0
  250. package/dist/types/domain/crypto.d.ts +53 -0
  251. package/dist/types/domain/crypto.d.ts.map +1 -0
  252. package/dist/types/domain/discovery.d.ts +44 -0
  253. package/dist/types/domain/discovery.d.ts.map +1 -0
  254. package/dist/types/domain/introspect.d.ts +71 -0
  255. package/dist/types/domain/introspect.d.ts.map +1 -0
  256. package/dist/types/domain/jwt.d.ts +48 -0
  257. package/dist/types/domain/jwt.d.ts.map +1 -0
  258. package/dist/types/domain/method-cache.d.ts +42 -0
  259. package/dist/types/domain/method-cache.d.ts.map +1 -0
  260. package/dist/types/domain/method-dispatch.d.ts +37 -0
  261. package/dist/types/domain/method-dispatch.d.ts.map +1 -0
  262. package/dist/types/domain/method-route.d.ts +77 -0
  263. package/dist/types/domain/method-route.d.ts.map +1 -0
  264. package/dist/types/domain/pkce.d.ts +15 -0
  265. package/dist/types/domain/pkce.d.ts.map +1 -0
  266. package/dist/types/domain/refresh.d.ts +43 -0
  267. package/dist/types/domain/refresh.d.ts.map +1 -0
  268. package/dist/types/domain/revoke.d.ts +61 -0
  269. package/dist/types/domain/revoke.d.ts.map +1 -0
  270. package/dist/types/domain/state-envelope.d.ts +30 -0
  271. package/dist/types/domain/state-envelope.d.ts.map +1 -0
  272. package/dist/types/domain/token-exchange.d.ts +67 -0
  273. package/dist/types/domain/token-exchange.d.ts.map +1 -0
  274. package/dist/types/domain/token.d.ts +100 -0
  275. package/dist/types/domain/token.d.ts.map +1 -0
  276. package/dist/types/domain/userinfo.d.ts +22 -0
  277. package/dist/types/domain/userinfo.d.ts.map +1 -0
  278. package/dist/types/http/context.d.ts +63 -0
  279. package/dist/types/http/context.d.ts.map +1 -0
  280. package/dist/types/http/cookies.d.ts +45 -0
  281. package/dist/types/http/cookies.d.ts.map +1 -0
  282. package/dist/types/http/errors.d.ts +36 -0
  283. package/dist/types/http/errors.d.ts.map +1 -0
  284. package/dist/types/http/handlers/authorize.d.ts +3 -0
  285. package/dist/types/http/handlers/authorize.d.ts.map +1 -0
  286. package/dist/types/http/handlers/callback.d.ts +3 -0
  287. package/dist/types/http/handlers/callback.d.ts.map +1 -0
  288. package/dist/types/http/handlers/metadata.d.ts +4 -0
  289. package/dist/types/http/handlers/metadata.d.ts.map +1 -0
  290. package/dist/types/http/handlers/method-route.d.ts +3 -0
  291. package/dist/types/http/handlers/method-route.d.ts.map +1 -0
  292. package/dist/types/http/handlers/revocation.d.ts +4 -0
  293. package/dist/types/http/handlers/revocation.d.ts.map +1 -0
  294. package/dist/types/http/handlers/token.d.ts +3 -0
  295. package/dist/types/http/handlers/token.d.ts.map +1 -0
  296. package/dist/types/http/handlers/userinfo.d.ts +3 -0
  297. package/dist/types/http/handlers/userinfo.d.ts.map +1 -0
  298. package/dist/types/http/middleware/error.d.ts +9 -0
  299. package/dist/types/http/middleware/error.d.ts.map +1 -0
  300. package/dist/types/http/middleware/tenant.d.ts +30 -0
  301. package/dist/types/http/middleware/tenant.d.ts.map +1 -0
  302. package/dist/types/http/resolver.d.ts +22 -0
  303. package/dist/types/http/resolver.d.ts.map +1 -0
  304. package/dist/types/http/router.d.ts +21 -0
  305. package/dist/types/http/router.d.ts.map +1 -0
  306. package/dist/types/http/schemas/authorize.d.ts +52 -0
  307. package/dist/types/http/schemas/authorize.d.ts.map +1 -0
  308. package/dist/types/http/schemas/revocation.d.ts +41 -0
  309. package/dist/types/http/schemas/revocation.d.ts.map +1 -0
  310. package/dist/types/http/schemas/token.d.ts +227 -0
  311. package/dist/types/http/schemas/token.d.ts.map +1 -0
  312. package/dist/types/index.d.ts +63 -13
  313. package/dist/types/index.d.ts.map +1 -1
  314. package/dist/types/methods/code.d.ts +96 -0
  315. package/dist/types/methods/code.d.ts.map +1 -0
  316. package/dist/types/methods/m2m.d.ts +41 -0
  317. package/dist/types/methods/m2m.d.ts.map +1 -0
  318. package/dist/types/methods/oauth2-factory.d.ts +133 -0
  319. package/dist/types/methods/oauth2-factory.d.ts.map +1 -0
  320. package/dist/types/methods/oauth2-generic.d.ts +75 -0
  321. package/dist/types/methods/oauth2-generic.d.ts.map +1 -0
  322. package/dist/types/methods/oidc-generic.d.ts +26 -0
  323. package/dist/types/methods/oidc-generic.d.ts.map +1 -0
  324. package/dist/types/methods/passkey.d.ts +106 -0
  325. package/dist/types/methods/passkey.d.ts.map +1 -0
  326. package/dist/types/methods/password-hash.d.ts +25 -0
  327. package/dist/types/methods/password-hash.d.ts.map +1 -0
  328. package/dist/types/methods/password.d.ts +70 -0
  329. package/dist/types/methods/password.d.ts.map +1 -0
  330. package/dist/types/methods/providers/apple.d.ts +29 -0
  331. package/dist/types/methods/providers/apple.d.ts.map +1 -0
  332. package/dist/types/methods/providers/cognito.d.ts +36 -0
  333. package/dist/types/methods/providers/cognito.d.ts.map +1 -0
  334. package/dist/types/methods/providers/discord.d.ts +22 -0
  335. package/dist/types/methods/providers/discord.d.ts.map +1 -0
  336. package/dist/types/methods/providers/facebook.d.ts +29 -0
  337. package/dist/types/methods/providers/facebook.d.ts.map +1 -0
  338. package/dist/types/methods/providers/github.d.ts +25 -0
  339. package/dist/types/methods/providers/github.d.ts.map +1 -0
  340. package/dist/types/methods/providers/google.d.ts +28 -0
  341. package/dist/types/methods/providers/google.d.ts.map +1 -0
  342. package/dist/types/methods/providers/index.d.ts +24 -0
  343. package/dist/types/methods/providers/index.d.ts.map +1 -0
  344. package/dist/types/methods/providers/jumpcloud.d.ts +22 -0
  345. package/dist/types/methods/providers/jumpcloud.d.ts.map +1 -0
  346. package/dist/types/methods/providers/keycloak.d.ts +30 -0
  347. package/dist/types/methods/providers/keycloak.d.ts.map +1 -0
  348. package/dist/types/methods/providers/linkedin.d.ts +22 -0
  349. package/dist/types/methods/providers/linkedin.d.ts.map +1 -0
  350. package/dist/types/methods/providers/microsoft.d.ts +30 -0
  351. package/dist/types/methods/providers/microsoft.d.ts.map +1 -0
  352. package/dist/types/methods/providers/slack.d.ts +25 -0
  353. package/dist/types/methods/providers/slack.d.ts.map +1 -0
  354. package/dist/types/methods/providers/spotify.d.ts +22 -0
  355. package/dist/types/methods/providers/spotify.d.ts.map +1 -0
  356. package/dist/types/methods/providers/twitch.d.ts +23 -0
  357. package/dist/types/methods/providers/twitch.d.ts.map +1 -0
  358. package/dist/types/methods/providers/x.d.ts +25 -0
  359. package/dist/types/methods/providers/x.d.ts.map +1 -0
  360. package/dist/types/methods/providers/yahoo.d.ts +22 -0
  361. package/dist/types/methods/providers/yahoo.d.ts.map +1 -0
  362. package/dist/types/pkce.d.ts +1 -2
  363. package/dist/types/pkce.d.ts.map +1 -1
  364. package/dist/types/ports/audit-log.d.ts +139 -0
  365. package/dist/types/ports/audit-log.d.ts.map +1 -0
  366. package/dist/types/ports/config-store.d.ts +32 -0
  367. package/dist/types/ports/config-store.d.ts.map +1 -0
  368. package/dist/types/ports/key-store.d.ts +98 -0
  369. package/dist/types/ports/key-store.d.ts.map +1 -0
  370. package/dist/types/ports/method-store.d.ts +29 -0
  371. package/dist/types/ports/method-store.d.ts.map +1 -0
  372. package/dist/types/ports/session-store.d.ts +82 -0
  373. package/dist/types/ports/session-store.d.ts.map +1 -0
  374. package/dist/types/ports/token-store.d.ts +93 -0
  375. package/dist/types/ports/token-store.d.ts.map +1 -0
  376. package/dist/types/types/authorization.d.ts +52 -0
  377. package/dist/types/types/authorization.d.ts.map +1 -0
  378. package/dist/types/types/error.d.ts +92 -0
  379. package/dist/types/types/error.d.ts.map +1 -0
  380. package/dist/types/types/flow.d.ts +87 -0
  381. package/dist/types/types/flow.d.ts.map +1 -0
  382. package/dist/types/types/idp.d.ts +234 -0
  383. package/dist/types/types/idp.d.ts.map +1 -0
  384. package/dist/types/types/method.d.ts +256 -0
  385. package/dist/types/types/method.d.ts.map +1 -0
  386. package/dist/types/types/picker.d.ts +31 -0
  387. package/dist/types/types/picker.d.ts.map +1 -0
  388. package/dist/types/types/result.d.ts +29 -0
  389. package/dist/types/types/result.d.ts.map +1 -0
  390. package/dist/types/types/subject.d.ts +47 -0
  391. package/dist/types/types/subject.d.ts.map +1 -0
  392. package/dist/types/types/tenant.d.ts +239 -0
  393. package/dist/types/types/tenant.d.ts.map +1 -0
  394. package/dist/types/types/token.d.ts +103 -0
  395. package/dist/types/types/token.d.ts.map +1 -0
  396. package/dist/types/ui/forms.d.ts +35 -0
  397. package/dist/types/ui/forms.d.ts.map +1 -0
  398. package/dist/types/ui/index.d.ts +14 -0
  399. package/dist/types/ui/index.d.ts.map +1 -0
  400. package/dist/types/ui/picker.d.ts +18 -0
  401. package/dist/types/ui/picker.d.ts.map +1 -0
  402. package/package.json +41 -6
  403. package/src/adapters/d1/audit-log.ts +32 -0
  404. package/src/adapters/d1/config-store.ts +67 -0
  405. package/src/adapters/d1/index.ts +41 -0
  406. package/src/adapters/d1/key-store.ts +218 -0
  407. package/src/adapters/d1/method-store.ts +103 -0
  408. package/src/adapters/d1/migrations.ts +89 -0
  409. package/src/adapters/d1/session-store.ts +230 -0
  410. package/src/adapters/d1/session.ts +38 -0
  411. package/src/adapters/d1/token-store.ts +251 -0
  412. package/src/adapters/d1/types.ts +53 -0
  413. package/src/adapters/durable-object/index.ts +23 -0
  414. package/src/adapters/durable-object/session-store.ts +227 -0
  415. package/src/adapters/durable-object/types.ts +25 -0
  416. package/src/adapters/dynamo/audit-log.ts +35 -0
  417. package/src/adapters/dynamo/client.ts +118 -0
  418. package/src/adapters/dynamo/config-store.ts +72 -0
  419. package/src/adapters/dynamo/index.ts +81 -0
  420. package/src/adapters/dynamo/key-store.ts +267 -0
  421. package/src/adapters/dynamo/method-store.ts +105 -0
  422. package/src/adapters/dynamo/passkey-credential-store.ts +132 -0
  423. package/src/adapters/dynamo/sdk.ts +189 -0
  424. package/src/adapters/dynamo/session-store.ts +229 -0
  425. package/src/adapters/dynamo/token-store.ts +248 -0
  426. package/src/adapters/kms/in-memory-backing.ts +36 -0
  427. package/src/adapters/kms/index.ts +39 -0
  428. package/src/adapters/kms/key-store.ts +176 -0
  429. package/src/adapters/kms/sdk.ts +39 -0
  430. package/src/adapters/kms/types.ts +61 -0
  431. package/src/adapters/kv/audit-log.ts +40 -0
  432. package/src/adapters/kv/config-store.ts +63 -0
  433. package/src/adapters/kv/index.ts +20 -0
  434. package/src/adapters/kv/method-store.ts +98 -0
  435. package/src/adapters/kv/types.ts +26 -0
  436. package/src/adapters/memory/audit-log.ts +28 -0
  437. package/src/adapters/memory/clock.ts +7 -0
  438. package/src/adapters/memory/config-store.ts +41 -0
  439. package/src/adapters/memory/index.ts +26 -0
  440. package/src/adapters/memory/key-store.ts +102 -0
  441. package/src/adapters/memory/method-store.ts +75 -0
  442. package/src/adapters/memory/passkey-credential-store.ts +97 -0
  443. package/src/adapters/memory/session-store.ts +128 -0
  444. package/src/adapters/memory/token-store.ts +165 -0
  445. package/src/adapters/postgres/audit-log.ts +34 -0
  446. package/src/adapters/postgres/config-store.ts +72 -0
  447. package/src/adapters/postgres/executor.ts +76 -0
  448. package/src/adapters/postgres/index.ts +60 -0
  449. package/src/adapters/postgres/key-store.ts +334 -0
  450. package/src/adapters/postgres/method-store.ts +104 -0
  451. package/src/adapters/postgres/migrations.ts +131 -0
  452. package/src/adapters/postgres/passkey-credential-store.ts +150 -0
  453. package/src/adapters/postgres/session-store.ts +216 -0
  454. package/src/adapters/postgres/token-store.ts +263 -0
  455. package/src/client.ts +50 -16
  456. package/src/domain/audit.ts +28 -0
  457. package/src/domain/authorize.ts +405 -0
  458. package/src/domain/callback.ts +263 -0
  459. package/src/domain/client-auth.ts +116 -0
  460. package/src/domain/client-credentials.ts +178 -0
  461. package/src/domain/crypto.ts +168 -0
  462. package/src/domain/discovery.ts +83 -0
  463. package/src/domain/introspect.ts +145 -0
  464. package/src/domain/jwt.ts +106 -0
  465. package/src/domain/method-cache.ts +220 -0
  466. package/src/domain/method-dispatch.ts +95 -0
  467. package/src/domain/method-route.ts +208 -0
  468. package/src/domain/pkce.ts +37 -0
  469. package/src/domain/refresh.ts +169 -0
  470. package/src/domain/revoke.ts +161 -0
  471. package/src/domain/state-envelope.ts +142 -0
  472. package/src/domain/token-exchange.ts +232 -0
  473. package/src/domain/token.ts +357 -0
  474. package/src/domain/userinfo.ts +56 -0
  475. package/src/http/context.ts +86 -0
  476. package/src/http/cookies.ts +167 -0
  477. package/src/http/errors.ts +98 -0
  478. package/src/http/handlers/authorize.ts +221 -0
  479. package/src/http/handlers/callback.ts +77 -0
  480. package/src/http/handlers/metadata.ts +44 -0
  481. package/src/http/handlers/method-route.ts +115 -0
  482. package/src/http/handlers/revocation.ts +151 -0
  483. package/src/http/handlers/token.ts +244 -0
  484. package/src/http/handlers/userinfo.ts +66 -0
  485. package/src/http/middleware/error.ts +26 -0
  486. package/src/http/middleware/tenant.ts +165 -0
  487. package/src/http/resolver.ts +34 -0
  488. package/src/http/router.ts +66 -0
  489. package/src/http/schemas/authorize.ts +58 -0
  490. package/src/http/schemas/revocation.ts +23 -0
  491. package/src/http/schemas/token.ts +85 -0
  492. package/src/index.ts +266 -20
  493. package/src/methods/code.ts +359 -0
  494. package/src/methods/m2m.ts +82 -0
  495. package/src/methods/oauth2-factory.ts +151 -0
  496. package/src/methods/oauth2-generic.ts +360 -0
  497. package/src/methods/oidc-generic.ts +109 -0
  498. package/src/methods/passkey.ts +419 -0
  499. package/src/methods/password-hash.ts +134 -0
  500. package/src/methods/password.ts +298 -0
  501. package/src/methods/providers/apple.ts +42 -0
  502. package/src/methods/providers/cognito.ts +55 -0
  503. package/src/methods/providers/discord.ts +37 -0
  504. package/src/methods/providers/facebook.ts +54 -0
  505. package/src/methods/providers/github.ts +42 -0
  506. package/src/methods/providers/google.ts +43 -0
  507. package/src/methods/providers/index.ts +23 -0
  508. package/src/methods/providers/jumpcloud.ts +36 -0
  509. package/src/methods/providers/keycloak.ts +42 -0
  510. package/src/methods/providers/linkedin.ts +37 -0
  511. package/src/methods/providers/microsoft.ts +42 -0
  512. package/src/methods/providers/slack.ts +42 -0
  513. package/src/methods/providers/spotify.ts +37 -0
  514. package/src/methods/providers/twitch.ts +38 -0
  515. package/src/methods/providers/x.ts +40 -0
  516. package/src/methods/providers/yahoo.ts +36 -0
  517. package/src/pkce.ts +20 -21
  518. package/src/ports/CONSISTENCY.md +88 -0
  519. package/src/ports/audit-log.ts +148 -0
  520. package/src/ports/config-store.ts +34 -0
  521. package/src/ports/key-store.ts +106 -0
  522. package/src/ports/method-store.ts +41 -0
  523. package/src/ports/session-store.ts +98 -0
  524. package/src/ports/token-store.ts +103 -0
  525. package/src/types/authorization.ts +53 -0
  526. package/src/types/error.ts +123 -0
  527. package/src/types/flow.ts +89 -0
  528. package/src/types/idp.ts +269 -0
  529. package/src/types/method.ts +270 -0
  530. package/src/types/picker.ts +32 -0
  531. package/src/types/result.ts +23 -0
  532. package/src/types/subject.ts +50 -0
  533. package/src/types/tenant.ts +248 -0
  534. package/src/types/token.ts +101 -0
  535. package/src/ui/forms.ts +289 -0
  536. package/src/ui/index.ts +14 -0
  537. package/src/ui/picker.ts +63 -0
  538. package/dist/esm/issuer.js +0 -691
  539. package/dist/esm/jwt.js +0 -16
  540. package/dist/esm/keys.js +0 -113
  541. package/dist/esm/provider/apple.js +0 -28
  542. package/dist/esm/provider/arctic.js +0 -43
  543. package/dist/esm/provider/code.js +0 -58
  544. package/dist/esm/provider/cognito.js +0 -16
  545. package/dist/esm/provider/discord.js +0 -15
  546. package/dist/esm/provider/facebook.js +0 -24
  547. package/dist/esm/provider/github.js +0 -15
  548. package/dist/esm/provider/google.js +0 -25
  549. package/dist/esm/provider/index.js +0 -3
  550. package/dist/esm/provider/jumpcloud.js +0 -15
  551. package/dist/esm/provider/keycloak.js +0 -15
  552. package/dist/esm/provider/linkedin.js +0 -15
  553. package/dist/esm/provider/m2m.js +0 -16
  554. package/dist/esm/provider/microsoft.js +0 -24
  555. package/dist/esm/provider/oauth2.js +0 -119
  556. package/dist/esm/provider/oidc.js +0 -69
  557. package/dist/esm/provider/passkey.js +0 -315
  558. package/dist/esm/provider/password.js +0 -306
  559. package/dist/esm/provider/provider.js +0 -10
  560. package/dist/esm/provider/slack.js +0 -15
  561. package/dist/esm/provider/spotify.js +0 -15
  562. package/dist/esm/provider/twitch.js +0 -15
  563. package/dist/esm/provider/x.js +0 -16
  564. package/dist/esm/provider/yahoo.js +0 -15
  565. package/dist/esm/random.js +0 -27
  566. package/dist/esm/storage/aws.js +0 -39
  567. package/dist/esm/storage/cloudflare.js +0 -42
  568. package/dist/esm/storage/dynamo.js +0 -116
  569. package/dist/esm/storage/memory.js +0 -88
  570. package/dist/esm/storage/storage.js +0 -36
  571. package/dist/esm/subject.js +0 -7
  572. package/dist/esm/ui/base.js +0 -407
  573. package/dist/esm/ui/code.js +0 -151
  574. package/dist/esm/ui/form.js +0 -43
  575. package/dist/esm/ui/icon.js +0 -92
  576. package/dist/esm/ui/passkey.js +0 -329
  577. package/dist/esm/ui/password.js +0 -338
  578. package/dist/esm/ui/select.js +0 -187
  579. package/dist/esm/ui/theme.js +0 -115
  580. package/dist/esm/util.js +0 -54
  581. package/dist/types/issuer.d.ts +0 -607
  582. package/dist/types/issuer.d.ts.map +0 -1
  583. package/dist/types/jwt.d.ts +0 -6
  584. package/dist/types/jwt.d.ts.map +0 -1
  585. package/dist/types/keys.d.ts +0 -18
  586. package/dist/types/keys.d.ts.map +0 -1
  587. package/dist/types/provider/apple.d.ts +0 -108
  588. package/dist/types/provider/apple.d.ts.map +0 -1
  589. package/dist/types/provider/arctic.d.ts +0 -16
  590. package/dist/types/provider/arctic.d.ts.map +0 -1
  591. package/dist/types/provider/code.d.ts +0 -74
  592. package/dist/types/provider/code.d.ts.map +0 -1
  593. package/dist/types/provider/cognito.d.ts +0 -64
  594. package/dist/types/provider/cognito.d.ts.map +0 -1
  595. package/dist/types/provider/discord.d.ts +0 -38
  596. package/dist/types/provider/discord.d.ts.map +0 -1
  597. package/dist/types/provider/facebook.d.ts +0 -74
  598. package/dist/types/provider/facebook.d.ts.map +0 -1
  599. package/dist/types/provider/github.d.ts +0 -38
  600. package/dist/types/provider/github.d.ts.map +0 -1
  601. package/dist/types/provider/google.d.ts +0 -74
  602. package/dist/types/provider/google.d.ts.map +0 -1
  603. package/dist/types/provider/index.d.ts +0 -4
  604. package/dist/types/provider/index.d.ts.map +0 -1
  605. package/dist/types/provider/jumpcloud.d.ts +0 -38
  606. package/dist/types/provider/jumpcloud.d.ts.map +0 -1
  607. package/dist/types/provider/keycloak.d.ts +0 -67
  608. package/dist/types/provider/keycloak.d.ts.map +0 -1
  609. package/dist/types/provider/linkedin.d.ts +0 -6
  610. package/dist/types/provider/linkedin.d.ts.map +0 -1
  611. package/dist/types/provider/m2m.d.ts +0 -34
  612. package/dist/types/provider/m2m.d.ts.map +0 -1
  613. package/dist/types/provider/microsoft.d.ts +0 -89
  614. package/dist/types/provider/microsoft.d.ts.map +0 -1
  615. package/dist/types/provider/oauth2.d.ts +0 -133
  616. package/dist/types/provider/oauth2.d.ts.map +0 -1
  617. package/dist/types/provider/oidc.d.ts +0 -91
  618. package/dist/types/provider/oidc.d.ts.map +0 -1
  619. package/dist/types/provider/passkey.d.ts +0 -143
  620. package/dist/types/provider/passkey.d.ts.map +0 -1
  621. package/dist/types/provider/password.d.ts +0 -210
  622. package/dist/types/provider/password.d.ts.map +0 -1
  623. package/dist/types/provider/provider.d.ts +0 -29
  624. package/dist/types/provider/provider.d.ts.map +0 -1
  625. package/dist/types/provider/slack.d.ts +0 -59
  626. package/dist/types/provider/slack.d.ts.map +0 -1
  627. package/dist/types/provider/spotify.d.ts +0 -38
  628. package/dist/types/provider/spotify.d.ts.map +0 -1
  629. package/dist/types/provider/twitch.d.ts +0 -38
  630. package/dist/types/provider/twitch.d.ts.map +0 -1
  631. package/dist/types/provider/x.d.ts +0 -38
  632. package/dist/types/provider/x.d.ts.map +0 -1
  633. package/dist/types/provider/yahoo.d.ts +0 -38
  634. package/dist/types/provider/yahoo.d.ts.map +0 -1
  635. package/dist/types/random.d.ts +0 -3
  636. package/dist/types/random.d.ts.map +0 -1
  637. package/dist/types/storage/aws.d.ts +0 -4
  638. package/dist/types/storage/aws.d.ts.map +0 -1
  639. package/dist/types/storage/cloudflare.d.ts +0 -34
  640. package/dist/types/storage/cloudflare.d.ts.map +0 -1
  641. package/dist/types/storage/dynamo.d.ts +0 -65
  642. package/dist/types/storage/dynamo.d.ts.map +0 -1
  643. package/dist/types/storage/memory.d.ts +0 -49
  644. package/dist/types/storage/memory.d.ts.map +0 -1
  645. package/dist/types/storage/storage.d.ts +0 -15
  646. package/dist/types/storage/storage.d.ts.map +0 -1
  647. package/dist/types/subject.d.ts +0 -122
  648. package/dist/types/subject.d.ts.map +0 -1
  649. package/dist/types/ui/base.d.ts +0 -5
  650. package/dist/types/ui/base.d.ts.map +0 -1
  651. package/dist/types/ui/code.d.ts +0 -104
  652. package/dist/types/ui/code.d.ts.map +0 -1
  653. package/dist/types/ui/form.d.ts +0 -6
  654. package/dist/types/ui/form.d.ts.map +0 -1
  655. package/dist/types/ui/icon.d.ts +0 -6
  656. package/dist/types/ui/icon.d.ts.map +0 -1
  657. package/dist/types/ui/passkey.d.ts +0 -5
  658. package/dist/types/ui/passkey.d.ts.map +0 -1
  659. package/dist/types/ui/password.d.ts +0 -139
  660. package/dist/types/ui/password.d.ts.map +0 -1
  661. package/dist/types/ui/select.d.ts +0 -55
  662. package/dist/types/ui/select.d.ts.map +0 -1
  663. package/dist/types/ui/theme.d.ts +0 -207
  664. package/dist/types/ui/theme.d.ts.map +0 -1
  665. package/dist/types/util.d.ts +0 -8
  666. package/dist/types/util.d.ts.map +0 -1
  667. package/src/css.d.ts +0 -4
  668. package/src/issuer.ts +0 -1628
  669. package/src/jwt.ts +0 -17
  670. package/src/keys.ts +0 -139
  671. package/src/provider/apple.ts +0 -127
  672. package/src/provider/arctic.ts +0 -66
  673. package/src/provider/code.ts +0 -227
  674. package/src/provider/cognito.ts +0 -74
  675. package/src/provider/discord.ts +0 -45
  676. package/src/provider/facebook.ts +0 -84
  677. package/src/provider/github.ts +0 -45
  678. package/src/provider/google.ts +0 -85
  679. package/src/provider/index.ts +0 -3
  680. package/src/provider/jumpcloud.ts +0 -45
  681. package/src/provider/keycloak.ts +0 -75
  682. package/src/provider/linkedin.ts +0 -12
  683. package/src/provider/m2m.ts +0 -56
  684. package/src/provider/microsoft.ts +0 -100
  685. package/src/provider/oauth2.ts +0 -297
  686. package/src/provider/oidc.ts +0 -179
  687. package/src/provider/passkey.ts +0 -655
  688. package/src/provider/password.ts +0 -672
  689. package/src/provider/provider.ts +0 -33
  690. package/src/provider/slack.ts +0 -67
  691. package/src/provider/spotify.ts +0 -45
  692. package/src/provider/twitch.ts +0 -45
  693. package/src/provider/x.ts +0 -46
  694. package/src/provider/yahoo.ts +0 -45
  695. package/src/random.ts +0 -24
  696. package/src/storage/aws.ts +0 -59
  697. package/src/storage/cloudflare.ts +0 -77
  698. package/src/storage/dynamo.ts +0 -193
  699. package/src/storage/memory.ts +0 -135
  700. package/src/storage/storage.ts +0 -46
  701. package/src/subject.ts +0 -130
  702. package/src/ui/base.tsx +0 -118
  703. package/src/ui/code.tsx +0 -215
  704. package/src/ui/form.tsx +0 -40
  705. package/src/ui/icon.tsx +0 -95
  706. package/src/ui/passkey.tsx +0 -321
  707. package/src/ui/password.tsx +0 -405
  708. package/src/ui/select.tsx +0 -221
  709. package/src/ui/theme.ts +0 -319
  710. package/src/ui/ui.css +0 -252
  711. package/src/util.ts +0 -58
  712. /package/dist/esm/{css.d.js → adapters/d1/types.js} +0 -0
package/src/issuer.ts DELETED
@@ -1,1628 +0,0 @@
1
- /**
2
- * The `issuer` create an OpentAuth server, a [Hono](https://hono.dev) app that's
3
- * designed to run anywhere.
4
- *
5
- * The `issuer` function requires a few things:
6
- *
7
- * ```ts title="issuer.ts"
8
- * import { issuer } from "@openauthjs/openauth"
9
- *
10
- * const app = issuer({
11
- * providers: { ... },
12
- * storage,
13
- * subjects,
14
- * success: async (ctx, value) => { ... }
15
- * })
16
- * ```
17
- *
18
- * #### Add providers
19
- *
20
- * You start by specifying the auth providers you are going to use. Let's say you want your users
21
- * to be able to authenticate with GitHub and with their email and password.
22
- *
23
- * ```ts title="issuer.ts"
24
- * import { GithubProvider } from "@openauthjs/openauth/provider/github"
25
- * import { PasswordProvider } from "@openauthjs/openauth/provider/password"
26
- *
27
- * const app = issuer({
28
- * providers: {
29
- * github: GithubProvider({
30
- * // ...
31
- * }),
32
- * password: PasswordProvider({
33
- * // ...
34
- * }),
35
- * },
36
- * })
37
- * ```
38
- *
39
- * #### Handle success
40
- *
41
- * The `success` callback receives the payload when a user completes a provider's auth flow.
42
- *
43
- * ```ts title="issuer.ts"
44
- * const app = issuer({
45
- * providers: { ... },
46
- * subjects,
47
- * async success(ctx, value) {
48
- * let userID
49
- * if (value.provider === "password") {
50
- * console.log(value.email)
51
- * userID = ... // lookup user or create them
52
- * }
53
- * if (value.provider === "github") {
54
- * console.log(value.tokenset.access)
55
- * userID = ... // lookup user or create them
56
- * }
57
- * return ctx.subject("user", {
58
- * userID
59
- * })
60
- * }
61
- * })
62
- * ```
63
- *
64
- * Once complete, the `issuer` issues the access tokens that a client can use. The `ctx.subject`
65
- * call is what is placed in the access token as a JWT.
66
- *
67
- * #### Define subjects
68
- *
69
- * You define the shape of these in the `subjects` field.
70
- *
71
- * ```ts title="subjects.ts"
72
- * import { object, string } from "valibot"
73
- * import { createSubjects } from "@openauthjs/openauth/subject"
74
- *
75
- * const subjects = createSubjects({
76
- * user: object({
77
- * userID: string()
78
- * })
79
- * })
80
- * ```
81
- *
82
- * It's good to place this in a separate file since this'll be used in your client apps as well.
83
- *
84
- * ```ts title="issuer.ts"
85
- * import { subjects } from "./subjects.js"
86
- *
87
- * const app = issuer({
88
- * providers: { ... },
89
- * subjects,
90
- * // ...
91
- * })
92
- * ```
93
- *
94
- * #### Multi-tenant routes
95
- *
96
- * For environments where subdomains or headers can't identify tenants (e.g., Lambda URLs),
97
- * use explicit tenant routes: `/tenant/:tenantId/authorize` instead of `/authorize`.
98
- *
99
- * ```ts title="issuer.ts"
100
- * const app = issuer({
101
- * providers: async (ctx) => {
102
- * const tenantId = ctx.get("tenantId") as string
103
- * const config = await db.tenants.findUnique({ where: { id: tenantId } })
104
- * return { github: GithubProvider({ clientID: config.githubClientId, ... }) }
105
- * },
106
- * success: async (ctx, value) => {
107
- * return ctx.subject("user", { userID: value.email, tenantId: value.tenantId })
108
- * }
109
- * })
110
- * ```
111
- *
112
- * #### Advanced multi-tenant configuration
113
- *
114
- * For complex multi-tenant scenarios, OpenAuth provides three additional configuration options:
115
- *
116
- * - **`basePath`** - Dynamic URL prefix for both incoming routing and outgoing URLs when the issuer is mounted at a variable path
117
- * - **`cookies.path`** - Set to `"/"` so cookies work across all paths
118
- * - **`context`** - Extract custom data from requests, available in providers and callbacks
119
- *
120
- * ```ts title="issuer.ts"
121
- * const app = issuer({
122
- * storage,
123
- * subjects,
124
- * // Dynamic base path based on request headers
125
- * basePath: (req) => `/auth/${req.headers.get("x-org-slug")}`,
126
- * // Root-level cookies that work across all paths
127
- * cookies: { path: "/" },
128
- * // Extract org/app context from each request
129
- * context: (req) => ({
130
- * orgSlug: req.headers.get("x-org-slug")!,
131
- * appSlug: req.headers.get("x-app-slug")!,
132
- * }),
133
- * providers: async (ctx) => {
134
- * const { orgSlug, appSlug } = ctx.get("requestContext") as { orgSlug: string; appSlug: string }
135
- * const config = await db.getAppConfig(orgSlug, appSlug)
136
- * return {
137
- * github: GithubProvider({
138
- * clientID: config.githubClientId,
139
- * clientSecret: config.githubClientSecret,
140
- * })
141
- * }
142
- * },
143
- * success: async (ctx, value) => {
144
- * const { orgSlug, appSlug } = value.context
145
- * return ctx.subject("user", {
146
- * userID: value.email,
147
- * orgSlug,
148
- * appSlug,
149
- * })
150
- * },
151
- * })
152
- *
153
- * // Mount the issuer at a dynamic route
154
- * honoApp.route("/auth/:orgSlug/:appSlug", app)
155
- * ```
156
- *
157
- * #### Deploy
158
- *
159
- * Since `issuer` is a Hono app, you can deploy it anywhere Hono supports.
160
- *
161
- * <Tabs>
162
- * <TabItem label="Node">
163
- * ```ts title="issuer.ts"
164
- * import { serve } from "@hono/node-server"
165
- *
166
- * serve(app)
167
- * ```
168
- * </TabItem>
169
- * <TabItem label="Lambda">
170
- * ```ts title="issuer.ts"
171
- * import { handle } from "hono/aws-lambda"
172
- *
173
- * export const handler = handle(app)
174
- * ```
175
- * </TabItem>
176
- * <TabItem label="Bun">
177
- * ```ts title="issuer.ts"
178
- * export default app
179
- * ```
180
- * </TabItem>
181
- * <TabItem label="Workers">
182
- * ```ts title="issuer.ts"
183
- * export default app
184
- * ```
185
- * </TabItem>
186
- * </Tabs>
187
- *
188
- * @packageDocumentation
189
- */
190
- import { Provider, ProviderOptions } from "./provider/provider.js"
191
- import { SubjectPayload, SubjectSchema } from "./subject.js"
192
- import { Hono } from "hono/tiny"
193
- import { handle as awsHandle } from "hono/aws-lambda"
194
- import { Context } from "hono"
195
- import { deleteCookie, getCookie, setCookie } from "hono/cookie"
196
- import type { v1 } from "@standard-schema/spec"
197
-
198
- /**
199
- * Sets the subject payload in the JWT token and returns the response.
200
- *
201
- * ```ts
202
- * ctx.subject("user", {
203
- * userID
204
- * })
205
- * ```
206
- */
207
- export interface OnSuccessResponder<
208
- T extends { type: string; properties: any },
209
- > {
210
- /**
211
- * The `type` is the type of the subject, that was defined in the `subjects` field.
212
- *
213
- * The `properties` are the properties of the subject. This is the shape of the subject that
214
- * you defined in the `subjects` field.
215
- */
216
- subject<Type extends T["type"]>(
217
- type: Type,
218
- properties: Extract<T, { type: Type }>["properties"],
219
- opts?: {
220
- ttl?: {
221
- access?: number
222
- refresh?: number
223
- }
224
- subject?: string
225
- },
226
- ): Promise<Response>
227
- }
228
-
229
- export interface AllowCallbackInput {
230
- clientID: string
231
- redirectURI: string
232
- audience?: string
233
- }
234
-
235
- /**
236
- * @internal
237
- */
238
- export interface AuthorizationState {
239
- redirect_uri: string
240
- response_type: string
241
- state: string
242
- client_id: string
243
- audience?: string
244
- pkce?: {
245
- challenge: string
246
- method: "S256"
247
- }
248
- tenantId?: string
249
- }
250
-
251
- /**
252
- * @internal
253
- */
254
- export type Prettify<T> = {
255
- [K in keyof T]: T[K]
256
- } & {}
257
-
258
- import {
259
- MissingParameterError,
260
- OauthError,
261
- UnauthorizedClientError,
262
- UnknownStateError,
263
- } from "./error.js"
264
- import { compactDecrypt, CompactEncrypt, jwtVerify, SignJWT } from "jose"
265
- import { Storage, StorageAdapter } from "./storage/storage.js"
266
- import { encryptionKeys, legacySigningKeys, signingKeys } from "./keys.js"
267
- import { validatePKCE } from "./pkce.js"
268
- import { Select } from "./ui/select.js"
269
- import { setTheme, Theme } from "./ui/theme.js"
270
- import { getRelativeUrl, isDomainMatch, lazy } from "./util.js"
271
- import { DynamoStorage } from "./storage/dynamo.js"
272
- import { MemoryStorage } from "./storage/memory.js"
273
- import { cors } from "hono/cors"
274
- import { logger } from "hono/logger"
275
-
276
- // Tenant ID validation: alphanumeric, underscore, hyphen, 1-64 chars
277
- const TENANT_ID_REGEX = /^[a-zA-Z0-9_-]{1,64}$/
278
-
279
- function isValidTenantId(tenantId: string): boolean {
280
- return TENANT_ID_REGEX.test(tenantId)
281
- }
282
-
283
- /** @internal */
284
- export const aws = awsHandle
285
-
286
- export interface IssuerInput<
287
- Providers extends Record<string, Provider<any>>,
288
- Subjects extends SubjectSchema,
289
- RequestContext = undefined,
290
- Result = {
291
- [key in keyof Providers]: Prettify<
292
- {
293
- provider: key
294
- tenantId?: string
295
- context: RequestContext
296
- } & (Providers[key] extends Provider<infer T> ? T : {})
297
- >
298
- }[keyof Providers],
299
- > {
300
- /**
301
- * The shape of the subjects that you want to return.
302
- *
303
- * @example
304
- *
305
- * ```ts title="issuer.ts"
306
- * import { object, string } from "valibot"
307
- * import { createSubjects } from "@openauthjs/openauth/subject"
308
- *
309
- * issuer({
310
- * subjects: createSubjects({
311
- * user: object({
312
- * userID: string()
313
- * })
314
- * })
315
- * // ...
316
- * })
317
- * ```
318
- */
319
- subjects: Subjects
320
- /**
321
- * The storage adapter that you want to use.
322
- *
323
- * @example
324
- * ```ts title="issuer.ts"
325
- * import { DynamoStorage } from "@openauthjs/openauth/storage/dynamo"
326
- *
327
- * issuer({
328
- * storage: DynamoStorage()
329
- * // ...
330
- * })
331
- * ```
332
- */
333
- storage?: StorageAdapter
334
- /**
335
- * The providers that you want your OpenAuth server to support.
336
- *
337
- * @example
338
- *
339
- * ```ts title="issuer.ts"
340
- * import { GithubProvider } from "@openauthjs/openauth/provider/github"
341
- *
342
- * issuer({
343
- * providers: {
344
- * github: GithubProvider()
345
- * }
346
- * })
347
- * ```
348
- *
349
- * The key is just a string that you can use to identify the provider. It's passed back to
350
- * the `success` callback.
351
- *
352
- * You can also specify multiple providers.
353
- *
354
- * ```ts
355
- * {
356
- * providers: {
357
- * github: GithubProvider(),
358
- * google: GoogleProvider()
359
- * }
360
- * }
361
- * ```
362
- *
363
- * For multi-tenant applications, you can provide a function that returns providers dynamically.
364
- * When using tenant routes (`/tenant/:tenantId/authorize`), the tenant ID is available via
365
- * `ctx.get("tenantId")`:
366
- *
367
- * ```ts
368
- * {
369
- * providers: async (ctx) => {
370
- * const tenantId = ctx.get("tenantId") as string
371
- * const config = await db.tenants.findUnique({ where: { id: tenantId } })
372
- * return {
373
- * github: GithubProvider({
374
- * clientID: config.githubClientId,
375
- * clientSecret: config.githubClientSecret,
376
- * })
377
- * }
378
- * }
379
- * }
380
- * ```
381
- */
382
- providers: Providers | ((ctx: Context) => Promise<Providers>)
383
- /**
384
- * The theme you want to use for the UI.
385
- *
386
- * This includes the UI the user sees when selecting a provider. And the `PasswordUI` and
387
- * `CodeUI` that are used by the `PasswordProvider` and `CodeProvider`.
388
- *
389
- * @example
390
- * ```ts title="issuer.ts"
391
- * import { THEME_SST } from "@openauthjs/openauth/ui/theme"
392
- *
393
- * issuer({
394
- * theme: THEME_SST
395
- * // ...
396
- * })
397
- * ```
398
- *
399
- * Or define your own.
400
- *
401
- * ```ts title="issuer.ts"
402
- * import type { Theme } from "@openauthjs/openauth/ui/theme"
403
- *
404
- * const MY_THEME: Theme = {
405
- * // ...
406
- * }
407
- *
408
- * issuer({
409
- * theme: MY_THEME
410
- * // ...
411
- * })
412
- * ```
413
- */
414
- theme?: Theme
415
- /**
416
- * Set the TTL, in seconds, for access and refresh tokens.
417
- *
418
- * @example
419
- * ```ts
420
- * {
421
- * ttl: {
422
- * access: 60 * 60 * 24 * 30,
423
- * refresh: 60 * 60 * 24 * 365
424
- * }
425
- * }
426
- * ```
427
- */
428
- ttl?: {
429
- /**
430
- * Interval in seconds where the access token is valid.
431
- * @default 30d
432
- */
433
- access?: number
434
- /**
435
- * Interval in seconds where the refresh token is valid.
436
- * @default 1y
437
- */
438
- refresh?: number
439
- /**
440
- * Interval in seconds where refresh token reuse is allowed. This helps mitigrate
441
- * concurrency issues.
442
- * @default 60s
443
- */
444
- reuse?: number
445
- /**
446
- * Interval in seconds to retain refresh tokens for reuse detection.
447
- * @default 0s
448
- */
449
- retention?: number
450
- }
451
- /**
452
- * Optionally, configure the UI that's displayed when the user visits the root URL of the
453
- * of the OpenAuth server.
454
- *
455
- * ```ts title="issuer.ts"
456
- * import { Select } from "@openauthjs/openauth/ui/select"
457
- *
458
- * issuer({
459
- * select: Select({
460
- * providers: {
461
- * github: { hide: true },
462
- * google: { display: "Google" }
463
- * }
464
- * })
465
- * // ...
466
- * })
467
- * ```
468
- *
469
- * @default Select()
470
- */
471
- select?(providers: Record<string, string>, req: Request): Promise<Response>
472
- /**
473
- * @internal
474
- */
475
- start?(req: Request): Promise<void>
476
- /**
477
- * The success callback that's called when the user completes the flow.
478
- *
479
- * This is called after the user has been redirected back to your app after the OAuth flow.
480
- *
481
- * The `value` parameter includes `provider` (the provider name) and any provider-specific
482
- * data. When using tenant routes (`/tenant/:tenantId/authorize`), it also includes `tenantId`.
483
- *
484
- * @example
485
- * ```ts
486
- * {
487
- * success: async (ctx, value) => {
488
- * let userID
489
- * if (value.provider === "password") {
490
- * console.log(value.email)
491
- * userID = ... // lookup user or create them
492
- * }
493
- * if (value.provider === "github") {
494
- * console.log(value.tokenset.access)
495
- * userID = ... // lookup user or create them
496
- * }
497
- * return ctx.subject("user", {
498
- * userID,
499
- * // For multi-tenant, store tenantId in subject for refresh access
500
- * tenantId: value.tenantId,
501
- * })
502
- * },
503
- * // ...
504
- * }
505
- * ```
506
- */
507
- success(
508
- response: OnSuccessResponder<SubjectPayload<Subjects>>,
509
- input: Result,
510
- req: Request,
511
- ): Promise<Response>
512
- /**
513
- * Optional callback that's called when a refresh token is used to get new access tokens.
514
- *
515
- * This allows you to update dynamic user attributes (permissions, roles, etc.) during
516
- * token refresh without requiring the user to re-authenticate.
517
- *
518
- * If not provided, the original properties from the initial authentication will be reused.
519
- *
520
- * @example
521
- * ```ts
522
- * {
523
- * refresh: async (ctx, value) => {
524
- * // Fetch updated permissions from database
525
- * const permissions = await db.getPermissions(value.properties.userId)
526
- * return ctx.subject("user", {
527
- * ...value.properties,
528
- * permissions // Updated value
529
- * })
530
- * }
531
- * }
532
- * ```
533
- */
534
- refresh?(
535
- response: OnSuccessResponder<SubjectPayload<Subjects>>,
536
- input: {
537
- type: string
538
- properties: any
539
- subject: string
540
- clientID: string
541
- },
542
- req: Request,
543
- ): Promise<Response>
544
- /**
545
- * @internal
546
- */
547
- error?(error: UnknownStateError, req: Request): Promise<Response>
548
- /**
549
- * Override the logic for whether a client request is allowed to call the issuer.
550
- *
551
- * By default, it uses the following:
552
- *
553
- * - Allow if the `redirectURI` is localhost.
554
- * - Compare `redirectURI` to the request's hostname or the `x-forwarded-host` header. If they
555
- * share the same apex domain, then allow.
556
- *
557
- * :::caution[Security Notice]
558
- * The default implementation allows ANY `redirect_uri` on the same apex domain with no per-client isolation.
559
- * Consider implementing a custom `allow` function with strict per-client validation if your deployment has:
560
- * - Untrusted content on subdomains (user-generated content, third-party scripts)
561
- * - Potential XSS attack vectors
562
- * - Multiple client applications requiring isolation
563
- * :::
564
- *
565
- * @example
566
- * Recommended for production (per-client allowlist):
567
- * ```ts
568
- * {
569
- * allow: async (input, req) => {
570
- * const allowedRedirects = {
571
- * 'web-client': ['https://app.example.com/callback'],
572
- * 'mobile-client': ['https://admin.example.com/oauth'],
573
- * }
574
- * return allowedRedirects[input.clientID]?.includes(input.redirectURI) ?? false
575
- * }
576
- * }
577
- * ```
578
- */
579
- allow?(input: AllowCallbackInput, req: Request): Promise<boolean>
580
- /**
581
- * Cookie configuration options.
582
- */
583
- cookies?: {
584
- /**
585
- * Path for cookies. Defaults to the current path.
586
- * Set to "/" for root-level cookies that work across all paths.
587
- */
588
- path?: string
589
- }
590
- /**
591
- * Extract custom context from the request. This context is available
592
- * in providers via `ctx.get("requestContext")` and in callbacks via `input.context`.
593
- *
594
- * @example
595
- * ```ts
596
- * context: (req) => ({
597
- * orgSlug: req.header("x-org-slug")!,
598
- * appSlug: req.header("x-app-slug")!,
599
- * }),
600
- * ```
601
- */
602
- context?: (req: Request) => RequestContext
603
- /**
604
- * Base path for all routes. Can be a static string or a function that
605
- * receives the request and returns the path.
606
- *
607
- * When set, OpenAuth will:
608
- * 1. **Strip the basePath from incoming requests** for internal routing
609
- * 2. **Prepend the basePath to outgoing URLs** (redirects, metadata endpoints)
610
- *
611
- * This enables clean integration when mounting the issuer at dynamic paths:
612
- *
613
- * @example
614
- * ```ts
615
- * const auth = issuer({
616
- * basePath: (req) => `/auth/${req.headers.get("x-org-slug")}`,
617
- * // ...
618
- * })
619
- *
620
- * // Mount at dynamic path - no manual URL rewriting needed
621
- * app.all("/auth/:orgSlug/*", (c) => {
622
- * c.req.raw.headers.set("x-org-slug", c.req.param("orgSlug"))
623
- * return auth.fetch(c.req.raw)
624
- * })
625
- * ```
626
- */
627
- basePath?: string | ((req: Request) => string)
628
- }
629
-
630
- /**
631
- * Create an OpenAuth server, a Hono app.
632
- */
633
- export function issuer<
634
- Providers extends Record<string, Provider<any>>,
635
- Subjects extends SubjectSchema,
636
- RequestContext = undefined,
637
- Result = {
638
- [key in keyof Providers]: Prettify<
639
- {
640
- provider: key
641
- tenantId?: string
642
- context: RequestContext
643
- } & (Providers[key] extends Provider<infer T> ? T : {})
644
- >
645
- }[keyof Providers],
646
- >(input: IssuerInput<Providers, Subjects, RequestContext, Result>) {
647
- const error =
648
- input.error ??
649
- function (err) {
650
- return new Response(err.message, {
651
- status: 400,
652
- headers: {
653
- "Content-Type": "text/plain",
654
- },
655
- })
656
- }
657
- const ttlAccess = input.ttl?.access ?? 60 * 60 * 24 * 30
658
- const ttlRefresh = input.ttl?.refresh ?? 60 * 60 * 24 * 365
659
- const ttlRefreshReuse = input.ttl?.reuse ?? 60
660
- const ttlRefreshRetention = input.ttl?.retention ?? 0
661
- if (input.theme) {
662
- setTheme(input.theme)
663
- }
664
-
665
- const select = lazy(() => input.select ?? Select())
666
- const allow = lazy(
667
- () =>
668
- input.allow ??
669
- (async (input: AllowCallbackInput, req: Request) => {
670
- const redir = new URL(input.redirectURI).hostname
671
- if (redir === "localhost" || redir === "127.0.0.1") {
672
- return true
673
- }
674
- const forwarded = req.headers.get("x-forwarded-host")
675
- const host = forwarded
676
- ? new URL(`https://${forwarded}`).hostname
677
- : new URL(req.url).hostname
678
-
679
- return isDomainMatch(redir, host)
680
- }),
681
- )
682
-
683
- let storage = input.storage
684
- if (process.env.OPENAUTH_STORAGE) {
685
- const parsed = JSON.parse(process.env.OPENAUTH_STORAGE)
686
- if (parsed.type === "dynamo") storage = DynamoStorage(parsed.options)
687
- if (parsed.type === "memory") storage = MemoryStorage()
688
- if (parsed.type === "cloudflare")
689
- throw new Error(
690
- "Cloudflare storage cannot be configured through env because it requires bindings.",
691
- )
692
- }
693
- if (!storage)
694
- throw new Error(
695
- "Store is not configured. Either set the `storage` option or set `OPENAUTH_STORAGE` environment variable.",
696
- )
697
- const allSigning = lazy(() =>
698
- Promise.all([signingKeys(storage), legacySigningKeys(storage)]).then(
699
- ([a, b]) => [...a, ...b],
700
- ),
701
- )
702
- const allEncryption = lazy(() => encryptionKeys(storage))
703
- const signingKey = lazy(() => allSigning().then((all) => all[0]))
704
- const encryptionKey = lazy(() => allEncryption().then((all) => all[0]))
705
-
706
- const getBasePath = (req: Request) => {
707
- if (!input.basePath) return ""
708
- if (typeof input.basePath === "string") return input.basePath
709
- return input.basePath(req)
710
- }
711
-
712
- const auth: Omit<ProviderOptions<any>, "name"> = {
713
- async success(ctx: Context, properties: any, successOpts) {
714
- const authorization = await getAuthorization(ctx)
715
- const tenantIdFromPath = ctx.get("tenantId") as string | undefined
716
-
717
- // Security: Verify tenantId matches what was stored at authorize time
718
- if (authorization.tenantId !== tenantIdFromPath) {
719
- const url = new URL(authorization.redirect_uri)
720
- url.searchParams.set("error", "invalid_request")
721
- url.searchParams.set("error_description", "Tenant ID mismatch")
722
- return ctx.redirect(url.toString())
723
- }
724
-
725
- return await input.success(
726
- {
727
- async subject(type, properties, subjectOpts) {
728
- const subject = subjectOpts?.subject
729
- ? subjectOpts.subject
730
- : await resolveSubject(type, properties)
731
- await successOpts?.invalidate?.(
732
- await resolveSubject(type, properties),
733
- )
734
- if (authorization.response_type === "token") {
735
- const location = new URL(authorization.redirect_uri)
736
- const tokens = await generateTokens(ctx, {
737
- subject,
738
- type: type as string,
739
- properties,
740
- clientID: authorization.client_id,
741
- ttl: {
742
- access: subjectOpts?.ttl?.access ?? ttlAccess,
743
- refresh: subjectOpts?.ttl?.refresh ?? ttlRefresh,
744
- },
745
- })
746
- location.hash = new URLSearchParams({
747
- access_token: tokens.access,
748
- refresh_token: tokens.refresh,
749
- state: authorization.state || "",
750
- }).toString()
751
- await auth.unset(ctx, "authorization")
752
- return ctx.redirect(location.toString(), 302)
753
- }
754
- if (authorization.response_type === "code") {
755
- const code = crypto.randomUUID()
756
- await Storage.set(
757
- storage,
758
- ["oauth:code", code],
759
- {
760
- type,
761
- properties,
762
- subject,
763
- redirectURI: authorization.redirect_uri,
764
- clientID: authorization.client_id,
765
- pkce: authorization.pkce,
766
- ttl: {
767
- access: subjectOpts?.ttl?.access ?? ttlAccess,
768
- refresh: subjectOpts?.ttl?.refresh ?? ttlRefresh,
769
- },
770
- },
771
- 60,
772
- )
773
- const location = new URL(authorization.redirect_uri)
774
- location.searchParams.set("code", code)
775
- location.searchParams.set("state", authorization.state || "")
776
- await auth.unset(ctx, "authorization")
777
- return ctx.redirect(location.toString(), 302)
778
- }
779
- throw new OauthError(
780
- "invalid_request",
781
- `Unsupported response_type: ${authorization.response_type}`,
782
- )
783
- },
784
- },
785
- {
786
- provider: ctx.get("provider"),
787
- tenantId: authorization.tenantId,
788
- context: ctx.get("requestContext"),
789
- ...properties,
790
- },
791
- ctx.req.raw,
792
- )
793
- },
794
- forward(ctx, response) {
795
- return ctx.newResponse(
796
- response.body,
797
- response.status as any,
798
- Object.fromEntries(response.headers.entries()),
799
- )
800
- },
801
- async set(ctx, key, maxAge, value) {
802
- setCookie(ctx, key, await encrypt(value), {
803
- maxAge,
804
- httpOnly: true,
805
- path: input.cookies?.path,
806
- ...(ctx.req.url.startsWith("https://")
807
- ? { secure: true, sameSite: "None" }
808
- : {}),
809
- })
810
- },
811
- async get(ctx: Context, key: string) {
812
- const raw = getCookie(ctx, key)
813
- if (!raw) return
814
- return decrypt(raw).catch((ex) => {
815
- console.error("failed to decrypt", key, ex)
816
- })
817
- },
818
- async unset(ctx: Context, key: string) {
819
- deleteCookie(ctx, key, { path: input.cookies?.path })
820
- },
821
- async invalidate(subject: string) {
822
- // Resolve the scan in case modifications interfere with iteration
823
- const keys = await Array.fromAsync(
824
- Storage.scan(this.storage, ["oauth:refresh", subject]),
825
- )
826
- for (const [key] of keys) {
827
- await Storage.remove(this.storage, key)
828
- }
829
- },
830
- storage,
831
- }
832
-
833
- async function getAuthorization(ctx: Context) {
834
- const match =
835
- (await auth.get(ctx, "authorization")) || ctx.get("authorization")
836
- if (!match) throw new UnknownStateError()
837
- return match as AuthorizationState
838
- }
839
-
840
- async function encrypt(value: any) {
841
- return await new CompactEncrypt(
842
- new TextEncoder().encode(JSON.stringify(value)),
843
- )
844
- .setProtectedHeader({ alg: "RSA-OAEP-512", enc: "A256GCM" })
845
- .encrypt(await encryptionKey().then((k) => k.public))
846
- }
847
-
848
- async function resolveSubject(type: string, properties: any) {
849
- const jsonString = JSON.stringify(properties)
850
- const encoder = new TextEncoder()
851
- const data = encoder.encode(jsonString)
852
- const hashBuffer = await crypto.subtle.digest("SHA-1", data)
853
- const hashArray = Array.from(new Uint8Array(hashBuffer))
854
- const hashHex = hashArray
855
- .map((b) => b.toString(16).padStart(2, "0"))
856
- .join("")
857
- return `${type}:${hashHex.slice(0, 16)}`
858
- }
859
-
860
- async function generateTokens(
861
- ctx: Context,
862
- value: {
863
- type: string
864
- properties: any
865
- subject: string
866
- clientID: string
867
- ttl: {
868
- access: number
869
- refresh: number
870
- }
871
- timeUsed?: number
872
- nextToken?: string
873
- },
874
- opts?: {
875
- generateRefreshToken?: boolean
876
- },
877
- ) {
878
- const refreshToken = value.nextToken ?? crypto.randomUUID()
879
- if (opts?.generateRefreshToken ?? true) {
880
- /**
881
- * Generate and store the next refresh token after the one we are currently returning.
882
- * Reserving these in advance avoids concurrency issues with multiple refreshes.
883
- * Similar treatment should be given to any other values that may have race conditions,
884
- * for example if a jti claim was added to the access token.
885
- */
886
- const refreshValue = {
887
- ...value,
888
- nextToken: crypto.randomUUID(),
889
- }
890
- delete refreshValue.timeUsed
891
- await Storage.set(
892
- storage!,
893
- ["oauth:refresh", value.subject, refreshToken],
894
- refreshValue,
895
- value.ttl.refresh,
896
- )
897
- }
898
- const accessTimeUsed = Math.floor((value.timeUsed ?? Date.now()) / 1000)
899
- return {
900
- access: await new SignJWT({
901
- mode: "access",
902
- type: value.type,
903
- properties: value.properties,
904
- aud: value.clientID,
905
- iss: issuer(ctx),
906
- sub: value.subject,
907
- })
908
- .setIssuedAt(accessTimeUsed)
909
- .setExpirationTime(Math.floor(accessTimeUsed + value.ttl.access))
910
- .setProtectedHeader(
911
- await signingKey().then((k) => ({
912
- alg: k.alg,
913
- kid: k.id,
914
- typ: "JWT",
915
- })),
916
- )
917
- .sign(await signingKey().then((item) => item.private)),
918
- expiresIn: Math.floor(
919
- accessTimeUsed + value.ttl.access - Date.now() / 1000,
920
- ),
921
- refresh: [value.subject, refreshToken].join(":"),
922
- }
923
- }
924
-
925
- async function decrypt(value: string) {
926
- return JSON.parse(
927
- new TextDecoder().decode(
928
- await compactDecrypt(
929
- value,
930
- await encryptionKey().then((v) => v.private),
931
- ).then((value) => value.plaintext),
932
- ),
933
- )
934
- }
935
-
936
- function issuer(ctx: Context) {
937
- const base = getBasePath(ctx.req.raw)
938
- return new URL(getRelativeUrl(ctx, base || "/")).origin + base
939
- }
940
-
941
- const app = new Hono<{
942
- Variables: {
943
- authorization: AuthorizationState
944
- tenantId: string
945
- requestContext: RequestContext
946
- }
947
- }>().use(logger())
948
-
949
- // Extract custom context from request if configured
950
- app.use(async (c, next) => {
951
- if (input.context) {
952
- c.set("requestContext", input.context(c.req.raw))
953
- }
954
- await next()
955
- })
956
-
957
- const getProviders = async (c: Context): Promise<Providers> => {
958
- if (typeof input.providers === "function") {
959
- return input.providers(c)
960
- }
961
- return input.providers
962
- }
963
-
964
- if (typeof input.providers === "object") {
965
- for (const [name, value] of Object.entries(input.providers)) {
966
- const route = new Hono<any>()
967
- route.use(async (c, next) => {
968
- c.set("provider", name)
969
- await next()
970
- })
971
- value.init(route, {
972
- name,
973
- ...auth,
974
- })
975
- app.route(`/${name}`, route)
976
- }
977
- }
978
-
979
- app.get(
980
- "/.well-known/jwks.json",
981
- cors({
982
- origin: "*",
983
- allowHeaders: ["*"],
984
- allowMethods: ["GET"],
985
- credentials: false,
986
- }),
987
- async (c) => {
988
- const all = await allSigning()
989
- return c.json({
990
- keys: all.map((item) => ({
991
- ...item.jwk,
992
- alg: item.alg,
993
- exp: item.expired
994
- ? Math.floor(item.expired.getTime() / 1000)
995
- : undefined,
996
- })),
997
- })
998
- },
999
- )
1000
-
1001
- const metadataHandler = async (c: Context) => {
1002
- const iss = issuer(c)
1003
- return c.json({
1004
- issuer: iss,
1005
- authorization_endpoint: `${iss}/authorize`,
1006
- token_endpoint: `${iss}/token`,
1007
- jwks_uri: `${iss}/.well-known/jwks.json`,
1008
- response_types_supported: ["code", "token"],
1009
- id_token_signing_alg_values_supported: ["ES256"],
1010
- subject_types_supported: ["public"],
1011
- })
1012
- }
1013
- app.get(
1014
- "/.well-known/oauth-authorization-server",
1015
- cors({
1016
- origin: "*",
1017
- allowHeaders: ["*"],
1018
- allowMethods: ["GET"],
1019
- credentials: false,
1020
- }),
1021
- metadataHandler,
1022
- )
1023
- app.get(
1024
- "/.well-known/openid-configuration",
1025
- cors({
1026
- origin: "*",
1027
- allowHeaders: ["*"],
1028
- allowMethods: ["GET"],
1029
- credentials: false,
1030
- }),
1031
- metadataHandler,
1032
- )
1033
-
1034
- app.post(
1035
- "/token",
1036
- cors({
1037
- origin: "*",
1038
- allowHeaders: ["*"],
1039
- allowMethods: ["POST"],
1040
- credentials: false,
1041
- }),
1042
- async (c) => {
1043
- const form = await c.req.formData()
1044
- const grantType = form.get("grant_type")
1045
-
1046
- if (grantType === "authorization_code") {
1047
- const code = form.get("code")
1048
- if (!code)
1049
- return c.json(
1050
- {
1051
- error: "invalid_request",
1052
- error_description: "Missing code",
1053
- },
1054
- 400,
1055
- )
1056
- const key = ["oauth:code", code.toString()]
1057
- const payload = await Storage.get<{
1058
- type: string
1059
- properties: any
1060
- clientID: string
1061
- redirectURI: string
1062
- subject: string
1063
- ttl: {
1064
- access: number
1065
- refresh: number
1066
- }
1067
- pkce?: AuthorizationState["pkce"]
1068
- }>(storage, key)
1069
- if (!payload) {
1070
- return c.json(
1071
- {
1072
- error: "invalid_grant",
1073
- error_description: "Authorization code has been used or expired",
1074
- },
1075
- 400,
1076
- )
1077
- }
1078
- if (payload.redirectURI !== form.get("redirect_uri")) {
1079
- return c.json(
1080
- {
1081
- error: "invalid_redirect_uri",
1082
- error_description: "Redirect URI mismatch",
1083
- },
1084
- 400,
1085
- )
1086
- }
1087
- if (payload.clientID !== form.get("client_id")) {
1088
- return c.json(
1089
- {
1090
- error: "unauthorized_client",
1091
- error_description:
1092
- "Client is not authorized to use this authorization code",
1093
- },
1094
- 403,
1095
- )
1096
- }
1097
-
1098
- if (payload.pkce) {
1099
- const codeVerifier = form.get("code_verifier")?.toString()
1100
- if (!codeVerifier)
1101
- return c.json(
1102
- {
1103
- error: "invalid_grant",
1104
- error_description: "Missing code_verifier",
1105
- },
1106
- 400,
1107
- )
1108
-
1109
- if (
1110
- !(await validatePKCE(
1111
- codeVerifier,
1112
- payload.pkce.challenge,
1113
- payload.pkce.method,
1114
- ))
1115
- ) {
1116
- return c.json(
1117
- {
1118
- error: "invalid_grant",
1119
- error_description: "Code verifier does not match",
1120
- },
1121
- 400,
1122
- )
1123
- }
1124
- }
1125
- const tokens = await generateTokens(c, payload)
1126
- await Storage.remove(storage, key)
1127
- return c.json({
1128
- access_token: tokens.access,
1129
- token_type: "Bearer",
1130
- expires_in: tokens.expiresIn,
1131
- refresh_token: tokens.refresh,
1132
- })
1133
- }
1134
-
1135
- if (grantType === "refresh_token") {
1136
- const refreshToken = form.get("refresh_token")
1137
- if (!refreshToken)
1138
- return c.json(
1139
- {
1140
- error: "invalid_request",
1141
- error_description: "Missing refresh_token",
1142
- },
1143
- 400,
1144
- )
1145
- const splits = refreshToken.toString().split(":")
1146
- const token = splits.pop()!
1147
- const subject = splits.join(":")
1148
- const key = ["oauth:refresh", subject, token]
1149
- const payload = await Storage.get<{
1150
- type: string
1151
- properties: any
1152
- clientID: string
1153
- subject: string
1154
- ttl: {
1155
- access: number
1156
- refresh: number
1157
- }
1158
- nextToken: string
1159
- timeUsed?: number
1160
- }>(storage, key)
1161
- if (!payload) {
1162
- return c.json(
1163
- {
1164
- error: "invalid_grant",
1165
- error_description: "Refresh token has been used or expired",
1166
- },
1167
- 400,
1168
- )
1169
- }
1170
- const generateRefreshToken = !payload.timeUsed
1171
- if (ttlRefreshReuse <= 0) {
1172
- // no reuse interval, remove the refresh token immediately
1173
- await Storage.remove(storage, key)
1174
- } else if (!payload.timeUsed) {
1175
- payload.timeUsed = Date.now()
1176
- await Storage.set(
1177
- storage,
1178
- key,
1179
- payload,
1180
- ttlRefreshReuse + ttlRefreshRetention,
1181
- )
1182
- } else if (Date.now() > payload.timeUsed + ttlRefreshReuse * 1000) {
1183
- // token was reused past the allowed interval
1184
- await auth.invalidate(subject)
1185
- return c.json(
1186
- {
1187
- error: "invalid_grant",
1188
- error_description: "Refresh token has been used or expired",
1189
- },
1190
- 400,
1191
- )
1192
- }
1193
-
1194
- // If refresh callback is provided, call it to allow updating properties
1195
- if (input.refresh) {
1196
- return input.refresh(
1197
- {
1198
- async subject(type, properties, opts) {
1199
- const tokens = await generateTokens(
1200
- c,
1201
- {
1202
- type: type as string,
1203
- subject: opts?.subject || payload.subject,
1204
- properties,
1205
- clientID: payload.clientID,
1206
- ttl: {
1207
- access: opts?.ttl?.access ?? ttlAccess,
1208
- refresh: opts?.ttl?.refresh ?? ttlRefresh,
1209
- },
1210
- },
1211
- { generateRefreshToken },
1212
- )
1213
- return c.json({
1214
- access_token: tokens.access,
1215
- refresh_token: tokens.refresh,
1216
- expires_in: tokens.expiresIn,
1217
- })
1218
- },
1219
- },
1220
- {
1221
- type: payload.type,
1222
- properties: payload.properties,
1223
- subject: payload.subject,
1224
- clientID: payload.clientID,
1225
- },
1226
- c.req.raw,
1227
- )
1228
- }
1229
-
1230
- // Fallback: use existing cached properties
1231
- const tokens = await generateTokens(c, payload, {
1232
- generateRefreshToken,
1233
- })
1234
- return c.json({
1235
- access_token: tokens.access,
1236
- token_type: "Bearer",
1237
- refresh_token: tokens.refresh,
1238
- expires_in: tokens.expiresIn,
1239
- })
1240
- }
1241
-
1242
- if (grantType === "client_credentials") {
1243
- const provider = form.get("provider")
1244
- if (!provider)
1245
- return c.json({ error: "missing `provider` form value" }, 400)
1246
- const providers = await getProviders(c)
1247
- const match = providers[provider.toString()]
1248
- if (!match)
1249
- return c.json({ error: "invalid `provider` query parameter" }, 400)
1250
- if (!match.client)
1251
- return c.json(
1252
- { error: "this provider does not support client_credentials" },
1253
- 400,
1254
- )
1255
- const clientID = form.get("client_id")
1256
- const clientSecret = form.get("client_secret")
1257
- if (!clientID)
1258
- return c.json({ error: "missing `client_id` form value" }, 400)
1259
- if (!clientSecret)
1260
- return c.json({ error: "missing `client_secret` form value" }, 400)
1261
- const response = await match.client({
1262
- clientID: clientID.toString(),
1263
- clientSecret: clientSecret.toString(),
1264
- params: Object.fromEntries(form) as Record<string, string>,
1265
- })
1266
- return input.success(
1267
- {
1268
- async subject(type, properties, opts) {
1269
- const tokens = await generateTokens(c, {
1270
- type: type as string,
1271
- subject:
1272
- opts?.subject || (await resolveSubject(type, properties)),
1273
- properties,
1274
- clientID: clientID.toString(),
1275
- ttl: {
1276
- access: opts?.ttl?.access ?? ttlAccess,
1277
- refresh: opts?.ttl?.refresh ?? ttlRefresh,
1278
- },
1279
- })
1280
- return c.json({
1281
- access_token: tokens.access,
1282
- refresh_token: tokens.refresh,
1283
- })
1284
- },
1285
- },
1286
- {
1287
- provider: provider.toString(),
1288
- context: c.get("requestContext"),
1289
- ...response,
1290
- },
1291
- c.req.raw,
1292
- )
1293
- }
1294
-
1295
- throw new Error("Invalid grant_type")
1296
- },
1297
- )
1298
-
1299
- app.get("/authorize", async (c) => {
1300
- const provider = c.req.query("provider")
1301
- const response_type = c.req.query("response_type")
1302
- const redirect_uri = c.req.query("redirect_uri")
1303
- const state = c.req.query("state")
1304
- const client_id = c.req.query("client_id")
1305
- const audience = c.req.query("audience")
1306
- const code_challenge = c.req.query("code_challenge")
1307
- const code_challenge_method = c.req.query("code_challenge_method")
1308
- const authorization: AuthorizationState = {
1309
- response_type,
1310
- redirect_uri,
1311
- state,
1312
- client_id,
1313
- audience,
1314
- pkce:
1315
- code_challenge && code_challenge_method
1316
- ? {
1317
- challenge: code_challenge,
1318
- method: code_challenge_method,
1319
- }
1320
- : undefined,
1321
- } as AuthorizationState
1322
-
1323
- if (!redirect_uri) {
1324
- return c.text("Missing redirect_uri", { status: 400 })
1325
- }
1326
-
1327
- if (!response_type) {
1328
- throw new MissingParameterError("response_type")
1329
- }
1330
-
1331
- if (!client_id) {
1332
- throw new MissingParameterError("client_id")
1333
- }
1334
-
1335
- if (input.start) {
1336
- await input.start(c.req.raw)
1337
- }
1338
-
1339
- if (
1340
- !(await allow()(
1341
- {
1342
- clientID: client_id,
1343
- redirectURI: redirect_uri,
1344
- audience,
1345
- },
1346
- c.req.raw,
1347
- ))
1348
- )
1349
- throw new UnauthorizedClientError(client_id, redirect_uri)
1350
- await auth.set(c, "authorization", 60 * 60 * 24, authorization)
1351
- c.set("authorization", authorization)
1352
- if (provider)
1353
- return c.redirect(`${getBasePath(c.req.raw)}/${provider}/authorize`)
1354
- const resolvedProviders = await getProviders(c)
1355
- const providerNames = Object.keys(resolvedProviders)
1356
- if (providerNames.length === 1)
1357
- return c.redirect(
1358
- `${getBasePath(c.req.raw)}/${providerNames[0]}/authorize`,
1359
- )
1360
- return auth.forward(
1361
- c,
1362
- await select()(
1363
- Object.fromEntries(
1364
- Object.entries(resolvedProviders).map(([key, value]) => [
1365
- key,
1366
- value.type,
1367
- ]),
1368
- ),
1369
- c.req.raw,
1370
- ),
1371
- )
1372
- })
1373
-
1374
- app.get("/tenant/:tenantId/authorize", async (c) => {
1375
- const tenantId = c.req.param("tenantId")
1376
-
1377
- // Validate tenantId to prevent path traversal/injection attacks
1378
- if (!isValidTenantId(tenantId)) {
1379
- return c.json({ error: "invalid_tenant_id" }, 400)
1380
- }
1381
-
1382
- c.set("tenantId", tenantId)
1383
- const provider = c.req.query("provider")
1384
- const response_type = c.req.query("response_type")
1385
- const redirect_uri = c.req.query("redirect_uri")
1386
- const state = c.req.query("state")
1387
- const client_id = c.req.query("client_id")
1388
- const audience = c.req.query("audience")
1389
- const code_challenge = c.req.query("code_challenge")
1390
- const code_challenge_method = c.req.query("code_challenge_method")
1391
- const authorization: AuthorizationState = {
1392
- response_type,
1393
- redirect_uri,
1394
- state,
1395
- client_id,
1396
- audience,
1397
- pkce:
1398
- code_challenge && code_challenge_method
1399
- ? {
1400
- challenge: code_challenge,
1401
- method: code_challenge_method,
1402
- }
1403
- : undefined,
1404
- tenantId,
1405
- } as AuthorizationState
1406
-
1407
- if (!redirect_uri) {
1408
- return c.text("Missing redirect_uri", { status: 400 })
1409
- }
1410
-
1411
- if (!response_type) {
1412
- throw new MissingParameterError("response_type")
1413
- }
1414
-
1415
- if (!client_id) {
1416
- throw new MissingParameterError("client_id")
1417
- }
1418
-
1419
- if (input.start) {
1420
- await input.start(c.req.raw)
1421
- }
1422
-
1423
- if (
1424
- !(await allow()(
1425
- {
1426
- clientID: client_id,
1427
- redirectURI: redirect_uri,
1428
- audience,
1429
- },
1430
- c.req.raw,
1431
- ))
1432
- )
1433
- throw new UnauthorizedClientError(client_id, redirect_uri)
1434
- await auth.set(c, "authorization", 60 * 60 * 24, authorization)
1435
- c.set("authorization", authorization)
1436
- if (provider)
1437
- return c.redirect(
1438
- `${getBasePath(c.req.raw)}/tenant/${tenantId}/${provider}/authorize`,
1439
- )
1440
- const resolvedProviders = await getProviders(c)
1441
- const providerNames = Object.keys(resolvedProviders)
1442
- if (providerNames.length === 1)
1443
- return c.redirect(
1444
- `${getBasePath(c.req.raw)}/tenant/${tenantId}/${providerNames[0]}/authorize`,
1445
- )
1446
- return auth.forward(
1447
- c,
1448
- await select()(
1449
- Object.fromEntries(
1450
- Object.entries(resolvedProviders).map(([key, value]) => [
1451
- key,
1452
- value.type,
1453
- ]),
1454
- ),
1455
- c.req.raw,
1456
- ),
1457
- )
1458
- })
1459
-
1460
- app.get("/userinfo", async (c) => {
1461
- const header = c.req.header("Authorization")
1462
-
1463
- if (!header) {
1464
- return c.json(
1465
- {
1466
- error: "invalid_request",
1467
- error_description: "Missing Authorization header",
1468
- },
1469
- 400,
1470
- )
1471
- }
1472
-
1473
- const [type, token] = header.split(" ")
1474
-
1475
- if (type !== "Bearer") {
1476
- return c.json(
1477
- {
1478
- error: "invalid_request",
1479
- error_description: "Missing or invalid Authorization header",
1480
- },
1481
- 400,
1482
- )
1483
- }
1484
-
1485
- if (!token) {
1486
- return c.json(
1487
- {
1488
- error: "invalid_request",
1489
- error_description: "Missing token",
1490
- },
1491
- 400,
1492
- )
1493
- }
1494
-
1495
- const result = await jwtVerify<{
1496
- mode: "access"
1497
- type: keyof SubjectSchema
1498
- properties: v1.InferInput<SubjectSchema[keyof SubjectSchema]>
1499
- }>(token, () => signingKey().then((item) => item.public), {
1500
- issuer: issuer(c),
1501
- })
1502
-
1503
- const validated = await input.subjects[result.payload.type][
1504
- "~standard"
1505
- ].validate(result.payload.properties)
1506
-
1507
- if (!validated.issues && result.payload.mode === "access") {
1508
- return c.json(validated.value as SubjectSchema)
1509
- }
1510
-
1511
- return c.json({
1512
- error: "invalid_token",
1513
- error_description: "Invalid token",
1514
- })
1515
- })
1516
-
1517
- if (typeof input.providers === "function") {
1518
- // Tenant-specific provider routes (must be before generic /:provider_name/*)
1519
- app.all("/tenant/:tenantId/:provider_name/*", async (c, next) => {
1520
- const tenantId = c.req.param("tenantId")
1521
-
1522
- // Validate tenantId to prevent path traversal/injection attacks
1523
- if (!isValidTenantId(tenantId)) {
1524
- return c.json({ error: "invalid_tenant_id" }, 400)
1525
- }
1526
-
1527
- c.set("tenantId", tenantId)
1528
- const name = c.req.param("provider_name")
1529
- const providers = await getProviders(c)
1530
- const value = providers[name]
1531
- if (!value) return next()
1532
-
1533
- const requestContext = c.get("requestContext")
1534
- const route = new Hono<any>()
1535
- route.use(async (c, next) => {
1536
- c.set("provider", name)
1537
- c.set("tenantId", tenantId)
1538
- if (requestContext !== undefined) {
1539
- c.set("requestContext", requestContext)
1540
- }
1541
- await next()
1542
- })
1543
- value.init(route, {
1544
- name,
1545
- ...auth,
1546
- })
1547
- const sub = new Hono()
1548
- sub.route(`/tenant/${tenantId}/${name}`, route)
1549
- return sub.fetch(c.req.raw)
1550
- })
1551
-
1552
- // Generic provider routes (for non-tenant flows)
1553
- app.all("/:provider_name/*", async (c, next) => {
1554
- const name = c.req.param("provider_name")
1555
- const providers = await getProviders(c)
1556
- const value = providers[name]
1557
- if (!value) return next()
1558
-
1559
- const requestContext = c.get("requestContext")
1560
- const route = new Hono<any>()
1561
- route.use(async (c, next) => {
1562
- c.set("provider", name)
1563
- if (requestContext !== undefined) {
1564
- c.set("requestContext", requestContext)
1565
- }
1566
- await next()
1567
- })
1568
- value.init(route, {
1569
- name,
1570
- ...auth,
1571
- })
1572
- const sub = new Hono()
1573
- sub.route(`/${name}`, route)
1574
- return sub.fetch(c.req.raw)
1575
- })
1576
- }
1577
-
1578
- app.onError(async (err, c) => {
1579
- console.error(err)
1580
-
1581
- if (err instanceof UnauthorizedClientError) {
1582
- return c.json(
1583
- { error: err.error, error_description: err.description },
1584
- 400,
1585
- )
1586
- }
1587
-
1588
- if (err instanceof MissingParameterError) {
1589
- return c.json(
1590
- { error: err.error, error_description: err.description },
1591
- 400,
1592
- )
1593
- }
1594
-
1595
- if (err instanceof UnknownStateError) {
1596
- return auth.forward(c, await error(err, c.req.raw))
1597
- }
1598
- const authorization = await getAuthorization(c)
1599
- const url = new URL(authorization.redirect_uri)
1600
- const oauth =
1601
- err instanceof OauthError
1602
- ? err
1603
- : new OauthError("server_error", err.message)
1604
- url.searchParams.set("error", oauth.error)
1605
- url.searchParams.set("error_description", oauth.description)
1606
- return c.redirect(url.toString())
1607
- })
1608
-
1609
- // If basePath is configured, wrap app to strip basePath from incoming requests
1610
- if (input.basePath) {
1611
- const wrapper = new Hono()
1612
- wrapper.all("*", async (c) => {
1613
- const base = getBasePath(c.req.raw)
1614
- let request = c.req.raw
1615
-
1616
- if (base && c.req.path.startsWith(base)) {
1617
- const url = new URL(c.req.url)
1618
- url.pathname = url.pathname.slice(base.length) || "/"
1619
- request = new Request(url.toString(), c.req.raw)
1620
- }
1621
-
1622
- return app.fetch(request)
1623
- })
1624
- return wrapper as unknown as typeof app
1625
- }
1626
-
1627
- return app
1628
- }