@udibo/oauth2 0.1.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 (375) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +174 -0
  3. package/SECURITY.md +77 -0
  4. package/esm/_dnt.polyfills.d.ts +17 -0
  5. package/esm/_dnt.polyfills.js +15 -0
  6. package/esm/adapters/hono/_common.d.ts +66 -0
  7. package/esm/adapters/hono/_common.js +108 -0
  8. package/esm/adapters/hono/authorization-server.d.ts +211 -0
  9. package/esm/adapters/hono/authorization-server.js +214 -0
  10. package/esm/adapters/hono/bff/auth-request-store.d.ts +164 -0
  11. package/esm/adapters/hono/bff/auth-request-store.js +154 -0
  12. package/esm/adapters/hono/bff/bff.d.ts +852 -0
  13. package/esm/adapters/hono/bff/bff.js +1194 -0
  14. package/esm/adapters/hono/bff/cookie-prefix.d.ts +72 -0
  15. package/esm/adapters/hono/bff/cookie-prefix.js +85 -0
  16. package/esm/adapters/hono/bff/mod.d.ts +19 -0
  17. package/esm/adapters/hono/bff/mod.js +19 -0
  18. package/esm/adapters/hono/bff/proxy.d.ts +108 -0
  19. package/esm/adapters/hono/bff/proxy.js +314 -0
  20. package/esm/adapters/hono/bff/session-store.d.ts +250 -0
  21. package/esm/adapters/hono/bff/session-store.js +216 -0
  22. package/esm/adapters/hono/bff/testing.d.ts +165 -0
  23. package/esm/adapters/hono/bff/testing.js +254 -0
  24. package/esm/adapters/hono/identity.d.ts +117 -0
  25. package/esm/adapters/hono/identity.js +215 -0
  26. package/esm/adapters/hono/log.d.ts +49 -0
  27. package/esm/adapters/hono/log.js +66 -0
  28. package/esm/adapters/hono/resource-server.d.ts +101 -0
  29. package/esm/adapters/hono/resource-server.js +108 -0
  30. package/esm/client/_http.d.ts +91 -0
  31. package/esm/client/_http.js +303 -0
  32. package/esm/client/base.d.ts +184 -0
  33. package/esm/client/base.js +93 -0
  34. package/esm/client/bff-client.d.ts +235 -0
  35. package/esm/client/bff-client.js +280 -0
  36. package/esm/client/browser-storage.d.ts +152 -0
  37. package/esm/client/browser-storage.js +246 -0
  38. package/esm/client/check.d.ts +114 -0
  39. package/esm/client/check.js +97 -0
  40. package/esm/client/direct-client.d.ts +707 -0
  41. package/esm/client/direct-client.js +1237 -0
  42. package/esm/client/discovery-cache.d.ts +138 -0
  43. package/esm/client/discovery-cache.js +124 -0
  44. package/esm/client/events.d.ts +54 -0
  45. package/esm/client/events.js +37 -0
  46. package/esm/client/mod.d.ts +35 -0
  47. package/esm/client/mod.js +33 -0
  48. package/esm/client/storage.d.ts +127 -0
  49. package/esm/client/storage.js +81 -0
  50. package/esm/deps/jsr.io/@std/assert/1.0.19/almost_equals.d.ts +29 -0
  51. package/esm/deps/jsr.io/@std/assert/1.0.19/almost_equals.js +47 -0
  52. package/esm/deps/jsr.io/@std/assert/1.0.19/array_includes.d.ts +28 -0
  53. package/esm/deps/jsr.io/@std/assert/1.0.19/array_includes.js +65 -0
  54. package/esm/deps/jsr.io/@std/assert/1.0.19/assert.d.ts +16 -0
  55. package/esm/deps/jsr.io/@std/assert/1.0.19/assert.js +23 -0
  56. package/esm/deps/jsr.io/@std/assert/1.0.19/assertion_error.d.ts +25 -0
  57. package/esm/deps/jsr.io/@std/assert/1.0.19/assertion_error.js +30 -0
  58. package/esm/deps/jsr.io/@std/assert/1.0.19/equal.d.ts +24 -0
  59. package/esm/deps/jsr.io/@std/assert/1.0.19/equal.js +193 -0
  60. package/esm/deps/jsr.io/@std/assert/1.0.19/equals.d.ts +36 -0
  61. package/esm/deps/jsr.io/@std/assert/1.0.19/equals.js +61 -0
  62. package/esm/deps/jsr.io/@std/assert/1.0.19/exists.d.ts +17 -0
  63. package/esm/deps/jsr.io/@std/assert/1.0.19/exists.js +27 -0
  64. package/esm/deps/jsr.io/@std/assert/1.0.19/fail.d.ts +14 -0
  65. package/esm/deps/jsr.io/@std/assert/1.0.19/fail.js +20 -0
  66. package/esm/deps/jsr.io/@std/assert/1.0.19/false.d.ts +18 -0
  67. package/esm/deps/jsr.io/@std/assert/1.0.19/false.js +23 -0
  68. package/esm/deps/jsr.io/@std/assert/1.0.19/greater.d.ts +19 -0
  69. package/esm/deps/jsr.io/@std/assert/1.0.19/greater.js +29 -0
  70. package/esm/deps/jsr.io/@std/assert/1.0.19/greater_or_equal.d.ts +19 -0
  71. package/esm/deps/jsr.io/@std/assert/1.0.19/greater_or_equal.js +29 -0
  72. package/esm/deps/jsr.io/@std/assert/1.0.19/instance_of.d.ts +22 -0
  73. package/esm/deps/jsr.io/@std/assert/1.0.19/instance_of.js +52 -0
  74. package/esm/deps/jsr.io/@std/assert/1.0.19/is_error.d.ts +24 -0
  75. package/esm/deps/jsr.io/@std/assert/1.0.19/is_error.js +53 -0
  76. package/esm/deps/jsr.io/@std/assert/1.0.19/less.d.ts +18 -0
  77. package/esm/deps/jsr.io/@std/assert/1.0.19/less.js +28 -0
  78. package/esm/deps/jsr.io/@std/assert/1.0.19/less_or_equal.d.ts +19 -0
  79. package/esm/deps/jsr.io/@std/assert/1.0.19/less_or_equal.js +29 -0
  80. package/esm/deps/jsr.io/@std/assert/1.0.19/match.d.ts +17 -0
  81. package/esm/deps/jsr.io/@std/assert/1.0.19/match.js +26 -0
  82. package/esm/deps/jsr.io/@std/assert/1.0.19/mod.d.ts +43 -0
  83. package/esm/deps/jsr.io/@std/assert/1.0.19/mod.js +45 -0
  84. package/esm/deps/jsr.io/@std/assert/1.0.19/not_equals.d.ts +26 -0
  85. package/esm/deps/jsr.io/@std/assert/1.0.19/not_equals.js +39 -0
  86. package/esm/deps/jsr.io/@std/assert/1.0.19/not_instance_of.d.ts +19 -0
  87. package/esm/deps/jsr.io/@std/assert/1.0.19/not_instance_of.js +29 -0
  88. package/esm/deps/jsr.io/@std/assert/1.0.19/not_match.d.ts +17 -0
  89. package/esm/deps/jsr.io/@std/assert/1.0.19/not_match.js +26 -0
  90. package/esm/deps/jsr.io/@std/assert/1.0.19/not_strict_equals.d.ts +22 -0
  91. package/esm/deps/jsr.io/@std/assert/1.0.19/not_strict_equals.js +32 -0
  92. package/esm/deps/jsr.io/@std/assert/1.0.19/object_match.d.ts +28 -0
  93. package/esm/deps/jsr.io/@std/assert/1.0.19/object_match.js +177 -0
  94. package/esm/deps/jsr.io/@std/assert/1.0.19/rejects.d.ts +41 -0
  95. package/esm/deps/jsr.io/@std/assert/1.0.19/rejects.js +53 -0
  96. package/esm/deps/jsr.io/@std/assert/1.0.19/strict_equals.d.ts +23 -0
  97. package/esm/deps/jsr.io/@std/assert/1.0.19/strict_equals.js +58 -0
  98. package/esm/deps/jsr.io/@std/assert/1.0.19/string_includes.d.ts +17 -0
  99. package/esm/deps/jsr.io/@std/assert/1.0.19/string_includes.js +26 -0
  100. package/esm/deps/jsr.io/@std/assert/1.0.19/throws.d.ts +44 -0
  101. package/esm/deps/jsr.io/@std/assert/1.0.19/throws.js +44 -0
  102. package/esm/deps/jsr.io/@std/assert/1.0.19/unimplemented.d.ts +14 -0
  103. package/esm/deps/jsr.io/@std/assert/1.0.19/unimplemented.js +20 -0
  104. package/esm/deps/jsr.io/@std/assert/1.0.19/unreachable.d.ts +14 -0
  105. package/esm/deps/jsr.io/@std/assert/1.0.19/unreachable.js +20 -0
  106. package/esm/deps/jsr.io/@std/async/1.5.0/delay.d.ts +44 -0
  107. package/esm/deps/jsr.io/@std/async/1.5.0/delay.js +84 -0
  108. package/esm/deps/jsr.io/@std/crypto/1.1.0/timing_safe_equal.d.ts +39 -0
  109. package/esm/deps/jsr.io/@std/crypto/1.1.0/timing_safe_equal.js +61 -0
  110. package/esm/deps/jsr.io/@std/encoding/1.0.11/_common16.d.ts +22 -0
  111. package/esm/deps/jsr.io/@std/encoding/1.0.11/_common16.js +51 -0
  112. package/esm/deps/jsr.io/@std/encoding/1.0.11/_common32.d.ts +34 -0
  113. package/esm/deps/jsr.io/@std/encoding/1.0.11/_common32.js +192 -0
  114. package/esm/deps/jsr.io/@std/encoding/1.0.11/_common64.d.ts +34 -0
  115. package/esm/deps/jsr.io/@std/encoding/1.0.11/_common64.js +113 -0
  116. package/esm/deps/jsr.io/@std/encoding/1.0.11/_common_detach.d.ts +3 -0
  117. package/esm/deps/jsr.io/@std/encoding/1.0.11/_common_detach.js +13 -0
  118. package/esm/deps/jsr.io/@std/encoding/1.0.11/_types.d.ts +8 -0
  119. package/esm/deps/jsr.io/@std/encoding/1.0.11/_types.js +2 -0
  120. package/esm/deps/jsr.io/@std/encoding/1.0.11/_validate_binary_like.d.ts +1 -0
  121. package/esm/deps/jsr.io/@std/encoding/1.0.11/_validate_binary_like.js +26 -0
  122. package/esm/deps/jsr.io/@std/encoding/1.0.11/ascii85.d.ts +60 -0
  123. package/esm/deps/jsr.io/@std/encoding/1.0.11/ascii85.js +152 -0
  124. package/esm/deps/jsr.io/@std/encoding/1.0.11/base32.d.ts +39 -0
  125. package/esm/deps/jsr.io/@std/encoding/1.0.11/base32.js +87 -0
  126. package/esm/deps/jsr.io/@std/encoding/1.0.11/base58.d.ts +39 -0
  127. package/esm/deps/jsr.io/@std/encoding/1.0.11/base58.js +131 -0
  128. package/esm/deps/jsr.io/@std/encoding/1.0.11/base64.d.ts +39 -0
  129. package/esm/deps/jsr.io/@std/encoding/1.0.11/base64.js +82 -0
  130. package/esm/deps/jsr.io/@std/encoding/1.0.11/base64url.d.ts +39 -0
  131. package/esm/deps/jsr.io/@std/encoding/1.0.11/base64url.js +72 -0
  132. package/esm/deps/jsr.io/@std/encoding/1.0.11/hex.d.ts +38 -0
  133. package/esm/deps/jsr.io/@std/encoding/1.0.11/hex.js +87 -0
  134. package/esm/deps/jsr.io/@std/encoding/1.0.11/mod.d.ts +97 -0
  135. package/esm/deps/jsr.io/@std/encoding/1.0.11/mod.js +99 -0
  136. package/esm/deps/jsr.io/@std/encoding/1.0.11/varint.d.ts +119 -0
  137. package/esm/deps/jsr.io/@std/encoding/1.0.11/varint.js +209 -0
  138. package/esm/deps/jsr.io/@std/http/1.1.3/status.d.ts +343 -0
  139. package/esm/deps/jsr.io/@std/http/1.1.3/status.js +343 -0
  140. package/esm/deps/jsr.io/@std/internal/1.0.14/assertion_state.d.ts +159 -0
  141. package/esm/deps/jsr.io/@std/internal/1.0.14/assertion_state.js +223 -0
  142. package/esm/deps/jsr.io/@std/internal/1.0.14/build_message.d.ts +79 -0
  143. package/esm/deps/jsr.io/@std/internal/1.0.14/build_message.js +116 -0
  144. package/esm/deps/jsr.io/@std/internal/1.0.14/diff.d.ts +139 -0
  145. package/esm/deps/jsr.io/@std/internal/1.0.14/diff.js +277 -0
  146. package/esm/deps/jsr.io/@std/internal/1.0.14/diff_str.d.ts +98 -0
  147. package/esm/deps/jsr.io/@std/internal/1.0.14/diff_str.js +181 -0
  148. package/esm/deps/jsr.io/@std/internal/1.0.14/format.d.ts +29 -0
  149. package/esm/deps/jsr.io/@std/internal/1.0.14/format.js +68 -0
  150. package/esm/deps/jsr.io/@std/internal/1.0.14/styles.d.ts +158 -0
  151. package/esm/deps/jsr.io/@std/internal/1.0.14/styles.js +206 -0
  152. package/esm/deps/jsr.io/@std/internal/1.0.14/types.d.ts +24 -0
  153. package/esm/deps/jsr.io/@std/internal/1.0.14/types.js +3 -0
  154. package/esm/deps/jsr.io/@std/testing/1.0.20/_test_suite.d.ts +91 -0
  155. package/esm/deps/jsr.io/@std/testing/1.0.20/_test_suite.js +347 -0
  156. package/esm/deps/jsr.io/@std/testing/1.0.20/bdd.d.ts +382 -0
  157. package/esm/deps/jsr.io/@std/testing/1.0.20/bdd.js +1110 -0
  158. package/esm/deps/jsr.io/@udibo/http-error/0.11.1/mod.d.ts +363 -0
  159. package/esm/deps/jsr.io/@udibo/http-error/0.11.1/mod.js +616 -0
  160. package/esm/errors.d.ts +203 -0
  161. package/esm/errors.js +287 -0
  162. package/esm/identity/captcha.d.ts +147 -0
  163. package/esm/identity/captcha.js +64 -0
  164. package/esm/identity/delivery.d.ts +96 -0
  165. package/esm/identity/delivery.js +41 -0
  166. package/esm/identity/errors.d.ts +39 -0
  167. package/esm/identity/errors.js +46 -0
  168. package/esm/identity/events.d.ts +242 -0
  169. package/esm/identity/events.js +39 -0
  170. package/esm/identity/external/_shared.d.ts +86 -0
  171. package/esm/identity/external/_shared.js +107 -0
  172. package/esm/identity/external/_token-exchange.d.ts +61 -0
  173. package/esm/identity/external/_token-exchange.js +179 -0
  174. package/esm/identity/external/apple-client-secret.d.ts +82 -0
  175. package/esm/identity/external/apple-client-secret.js +133 -0
  176. package/esm/identity/external/apple.d.ts +64 -0
  177. package/esm/identity/external/apple.js +248 -0
  178. package/esm/identity/external/discord.d.ts +38 -0
  179. package/esm/identity/external/discord.js +62 -0
  180. package/esm/identity/external/errors.d.ts +48 -0
  181. package/esm/identity/external/errors.js +36 -0
  182. package/esm/identity/external/flow.d.ts +107 -0
  183. package/esm/identity/external/flow.js +158 -0
  184. package/esm/identity/external/github.d.ts +42 -0
  185. package/esm/identity/external/github.js +164 -0
  186. package/esm/identity/external/google.d.ts +52 -0
  187. package/esm/identity/external/google.js +38 -0
  188. package/esm/identity/external/mod.d.ts +63 -0
  189. package/esm/identity/external/mod.js +61 -0
  190. package/esm/identity/external/oauth2.d.ts +110 -0
  191. package/esm/identity/external/oauth2.js +158 -0
  192. package/esm/identity/external/oidc.d.ts +81 -0
  193. package/esm/identity/external/oidc.js +250 -0
  194. package/esm/identity/external/provider.d.ts +132 -0
  195. package/esm/identity/external/provider.js +12 -0
  196. package/esm/identity/hibp.d.ts +67 -0
  197. package/esm/identity/hibp.js +87 -0
  198. package/esm/identity/identifier.d.ts +44 -0
  199. package/esm/identity/identifier.js +47 -0
  200. package/esm/identity/lockout.d.ts +155 -0
  201. package/esm/identity/lockout.js +117 -0
  202. package/esm/identity/mfa/mod.d.ts +42 -0
  203. package/esm/identity/mfa/mod.js +42 -0
  204. package/esm/identity/mfa/recovery-codes.d.ts +96 -0
  205. package/esm/identity/mfa/recovery-codes.js +80 -0
  206. package/esm/identity/mfa/service.d.ts +338 -0
  207. package/esm/identity/mfa/service.js +351 -0
  208. package/esm/identity/mfa/totp.d.ts +186 -0
  209. package/esm/identity/mfa/totp.js +194 -0
  210. package/esm/identity/migration.d.ts +155 -0
  211. package/esm/identity/migration.js +243 -0
  212. package/esm/identity/mod.d.ts +65 -0
  213. package/esm/identity/mod.js +64 -0
  214. package/esm/identity/otp.d.ts +255 -0
  215. package/esm/identity/otp.js +245 -0
  216. package/esm/identity/password-policy.d.ts +45 -0
  217. package/esm/identity/password-policy.js +60 -0
  218. package/esm/identity/password.d.ts +171 -0
  219. package/esm/identity/password.js +160 -0
  220. package/esm/identity/rate-limit.d.ts +192 -0
  221. package/esm/identity/rate-limit.js +168 -0
  222. package/esm/identity/service.d.ts +579 -0
  223. package/esm/identity/service.js +835 -0
  224. package/esm/identity/session.d.ts +122 -0
  225. package/esm/identity/session.js +48 -0
  226. package/esm/identity/token-flow.d.ts +214 -0
  227. package/esm/identity/token-flow.js +173 -0
  228. package/esm/models/authentication.d.ts +24 -0
  229. package/esm/models/authentication.js +1 -0
  230. package/esm/models/authorization-code.d.ts +63 -0
  231. package/esm/models/authorization-code.js +1 -0
  232. package/esm/models/authorization.d.ts +165 -0
  233. package/esm/models/authorization.js +160 -0
  234. package/esm/models/client.d.ts +78 -0
  235. package/esm/models/client.js +1 -0
  236. package/esm/models/device-authorization.d.ts +30 -0
  237. package/esm/models/device-authorization.js +1 -0
  238. package/esm/models/responses.d.ts +93 -0
  239. package/esm/models/responses.js +1 -0
  240. package/esm/models/scope.d.ts +81 -0
  241. package/esm/models/scope.js +125 -0
  242. package/esm/models/token.d.ts +135 -0
  243. package/esm/models/token.js +1 -0
  244. package/esm/package.json +3 -0
  245. package/esm/react/callback.d.ts +52 -0
  246. package/esm/react/callback.js +71 -0
  247. package/esm/react/components/class-names.d.ts +91 -0
  248. package/esm/react/components/class-names.js +118 -0
  249. package/esm/react/components/internal.d.ts +62 -0
  250. package/esm/react/components/internal.js +102 -0
  251. package/esm/react/components/mfa-challenge-form.d.ts +66 -0
  252. package/esm/react/components/mfa-challenge-form.js +46 -0
  253. package/esm/react/components/mfa-enrollment-form.d.ts +83 -0
  254. package/esm/react/components/mfa-enrollment-form.js +41 -0
  255. package/esm/react/components/mod.d.ts +103 -0
  256. package/esm/react/components/mod.js +93 -0
  257. package/esm/react/components/request-password-reset-form.d.ts +61 -0
  258. package/esm/react/components/request-password-reset-form.js +41 -0
  259. package/esm/react/components/reset-password-form.d.ts +66 -0
  260. package/esm/react/components/reset-password-form.js +56 -0
  261. package/esm/react/components/sign-in-form.d.ts +74 -0
  262. package/esm/react/components/sign-in-form.js +43 -0
  263. package/esm/react/components/sign-up-form.d.ts +85 -0
  264. package/esm/react/components/sign-up-form.js +57 -0
  265. package/esm/react/components/types.d.ts +208 -0
  266. package/esm/react/components/types.js +14 -0
  267. package/esm/react/components/use-auth-form.d.ts +118 -0
  268. package/esm/react/components/use-auth-form.js +172 -0
  269. package/esm/react/components/user-menu.d.ts +79 -0
  270. package/esm/react/components/user-menu.js +73 -0
  271. package/esm/react/context.d.ts +51 -0
  272. package/esm/react/context.js +16 -0
  273. package/esm/react/mod.d.ts +26 -0
  274. package/esm/react/mod.js +26 -0
  275. package/esm/react/provider.d.ts +40 -0
  276. package/esm/react/provider.js +189 -0
  277. package/esm/react/require-auth.d.ts +31 -0
  278. package/esm/react/require-auth.js +37 -0
  279. package/esm/react/testing.d.ts +322 -0
  280. package/esm/react/testing.js +461 -0
  281. package/esm/react/use-authorization.d.ts +31 -0
  282. package/esm/react/use-authorization.js +36 -0
  283. package/esm/react/use-oauth2.d.ts +112 -0
  284. package/esm/react/use-oauth2.js +127 -0
  285. package/esm/server/authorization-server.d.ts +736 -0
  286. package/esm/server/authorization-server.js +1304 -0
  287. package/esm/server/client-authentication.d.ts +28 -0
  288. package/esm/server/client-authentication.js +51 -0
  289. package/esm/server/grants/authorization-code.d.ts +179 -0
  290. package/esm/server/grants/authorization-code.js +232 -0
  291. package/esm/server/grants/client-credentials.d.ts +52 -0
  292. package/esm/server/grants/client-credentials.js +53 -0
  293. package/esm/server/grants/device-authorization.d.ts +103 -0
  294. package/esm/server/grants/device-authorization.js +156 -0
  295. package/esm/server/grants/grant.d.ts +165 -0
  296. package/esm/server/grants/grant.js +173 -0
  297. package/esm/server/grants/password.d.ts +80 -0
  298. package/esm/server/grants/password.js +92 -0
  299. package/esm/server/grants/refresh-token.d.ts +80 -0
  300. package/esm/server/grants/refresh-token.js +136 -0
  301. package/esm/server/introspection-token-reader.d.ts +153 -0
  302. package/esm/server/introspection-token-reader.js +164 -0
  303. package/esm/server/jwks-token-reader.d.ts +263 -0
  304. package/esm/server/jwks-token-reader.js +508 -0
  305. package/esm/server/mod.d.ts +23 -0
  306. package/esm/server/mod.js +15 -0
  307. package/esm/server/public-suffix/mod.d.ts +62 -0
  308. package/esm/server/public-suffix/mod.js +103 -0
  309. package/esm/server/public-suffix/rules.d.ts +23 -0
  310. package/esm/server/public-suffix/rules.js +23 -0
  311. package/esm/server/redirect-uri.d.ts +187 -0
  312. package/esm/server/redirect-uri.js +331 -0
  313. package/esm/server/resource-server.d.ts +286 -0
  314. package/esm/server/resource-server.js +365 -0
  315. package/esm/server/services/authorization-code.d.ts +84 -0
  316. package/esm/server/services/authorization-code.js +35 -0
  317. package/esm/server/services/client.d.ts +35 -0
  318. package/esm/server/services/client.js +1 -0
  319. package/esm/server/services/device-authorization.d.ts +134 -0
  320. package/esm/server/services/device-authorization.js +7 -0
  321. package/esm/server/services/token.d.ts +242 -0
  322. package/esm/server/services/token.js +78 -0
  323. package/esm/server/services/user.d.ts +29 -0
  324. package/esm/server/services/user.js +7 -0
  325. package/esm/server/signing-keys.d.ts +201 -0
  326. package/esm/server/signing-keys.js +225 -0
  327. package/esm/server/utils/hash.d.ts +6 -0
  328. package/esm/server/utils/hash.js +11 -0
  329. package/esm/testing/contract/authorization-code.d.ts +37 -0
  330. package/esm/testing/contract/authorization-code.js +93 -0
  331. package/esm/testing/contract/client.d.ts +85 -0
  332. package/esm/testing/contract/client.js +126 -0
  333. package/esm/testing/contract/device-authorization.d.ts +37 -0
  334. package/esm/testing/contract/device-authorization.js +193 -0
  335. package/esm/testing/contract/lockout-store.d.ts +47 -0
  336. package/esm/testing/contract/lockout-store.js +122 -0
  337. package/esm/testing/contract/mfa-store.d.ts +50 -0
  338. package/esm/testing/contract/mfa-store.js +226 -0
  339. package/esm/testing/contract/mod.d.ts +39 -0
  340. package/esm/testing/contract/mod.js +39 -0
  341. package/esm/testing/contract/otp-store.d.ts +48 -0
  342. package/esm/testing/contract/otp-store.js +197 -0
  343. package/esm/testing/contract/rate-limit-store.d.ts +52 -0
  344. package/esm/testing/contract/rate-limit-store.js +105 -0
  345. package/esm/testing/contract/token-flow-store.d.ts +54 -0
  346. package/esm/testing/contract/token-flow-store.js +179 -0
  347. package/esm/testing/contract/token-reader.d.ts +77 -0
  348. package/esm/testing/contract/token-reader.js +78 -0
  349. package/esm/testing/contract/token.d.ts +61 -0
  350. package/esm/testing/contract/token.js +287 -0
  351. package/esm/testing/contract/user.d.ts +63 -0
  352. package/esm/testing/contract/user.js +75 -0
  353. package/esm/testing/mod.d.ts +34 -0
  354. package/esm/testing/mod.js +34 -0
  355. package/esm/testing/server.d.ts +197 -0
  356. package/esm/testing/server.js +193 -0
  357. package/esm/testing/services.d.ts +373 -0
  358. package/esm/testing/services.js +703 -0
  359. package/esm/utils/_buffer.d.ts +10 -0
  360. package/esm/utils/_buffer.js +12 -0
  361. package/esm/utils/_timing-safe.d.ts +13 -0
  362. package/esm/utils/_timing-safe.js +22 -0
  363. package/esm/utils/authentication-context.d.ts +3 -0
  364. package/esm/utils/authentication-context.js +14 -0
  365. package/esm/utils/basic-auth.d.ts +50 -0
  366. package/esm/utils/basic-auth.js +106 -0
  367. package/esm/utils/crypto.d.ts +97 -0
  368. package/esm/utils/crypto.js +162 -0
  369. package/esm/utils/pkce.d.ts +151 -0
  370. package/esm/utils/pkce.js +179 -0
  371. package/esm/utils/text.d.ts +24 -0
  372. package/esm/utils/text.js +28 -0
  373. package/esm/utils/url.d.ts +66 -0
  374. package/esm/utils/url.js +90 -0
  375. package/package.json +92 -0
@@ -0,0 +1,331 @@
1
+ /**
2
+ * Redirect URI matching for the authorization server.
3
+ *
4
+ * RFC 6749 §3.1.2.3 and the OAuth 2.0 Security BCP require `redirect_uri` to be
5
+ * compared against a pre-registered value by exact string match, and that is
6
+ * what {@link matchRedirectUri} does for every ordinary registration. A
7
+ * registration may instead be a **pattern** — a single `*` in the leftmost host
8
+ * label — which lets one registration cover the per-deploy hostnames a preview
9
+ * environment produces.
10
+ *
11
+ * Patterns are deliberately narrow, because a wildcard that reaches beyond the
12
+ * registrant's own namespace hands authorization codes to whoever can obtain a
13
+ * neighbouring host. The rules are enforced by {@link checkRedirectUriPattern},
14
+ * and {@link matchRedirectUri} refuses to match a pattern that violates any of
15
+ * them, so an invalid pattern in storage is inert rather than dangerous.
16
+ *
17
+ * The narrowest of those rules — the domain under the wildcard has to be one
18
+ * registrant's — is decided by the Public Suffix List, injected as
19
+ * {@link IsPublicSuffix} so this module carries no data. Pass `isPublicSuffix`
20
+ * from `@udibo/oauth2/server/public-suffix`; a server that never accepts
21
+ * patterns can leave it out and refuse them all.
22
+ *
23
+ * A registration whose host is a **loopback IP literal** (`127.0.0.1` or
24
+ * `[::1]`) is the one other departure from exact matching: RFC 8252 §7.3
25
+ * requires the authorization server to allow any port at request time, because
26
+ * a native app binds an OS-assigned port it cannot know when it registers.
27
+ * Only the port is relaxed, and only for the IP literals — `localhost` is a
28
+ * name resolved by a host file this server does not control (RFC 8252 §8.3),
29
+ * so it keeps exact matching.
30
+ *
31
+ * This module has no notion of environments. Deciding *which* clients may
32
+ * register a pattern at all is the application's call — the usual policy is to
33
+ * permit them for development registrations and refuse them for production
34
+ * ones, which an application enforces by validating at registration time and by
35
+ * not handing a pattern to the authorization server for a production client.
36
+ * The loopback relaxation is likewise only reachable once the application has
37
+ * chosen to register a loopback URI.
38
+ *
39
+ * @module
40
+ */
41
+ /**
42
+ * A label used to ask whether the *children* of a parent domain are public
43
+ * suffixes, which is a different question from whether the parent is one.
44
+ *
45
+ * `r.appspot.com` is a registrable domain by the list's reckoning, but the rule
46
+ * `*.r.appspot.com` makes every one of its subdomains a public suffix belonging
47
+ * to a different registrant — so a wildcard over it hands codes to strangers
48
+ * even though the parent itself passes. Probing with a label no registry has
49
+ * ever issued answers that in one lookup.
50
+ */
51
+ const CHILD_PROBE_LABEL = "udibo-public-suffix-probe";
52
+ /**
53
+ * Split a hostname into labels, or `null` when it is not usable for matching.
54
+ *
55
+ * A single trailing dot is the DNS root and is dropped, so `example.com.` and
56
+ * `example.com` are the same host — without this, the extra empty label would
57
+ * shift every label the public-suffix check looks at and let `*.deno.net.`
58
+ * through. Any *other* empty label (`a..b`, a leading `.`) is refused outright
59
+ * rather than normalized: it cannot resolve, and an empty leftmost label would
60
+ * otherwise satisfy any prefix/suffix test.
61
+ */
62
+ function hostLabels(hostname) {
63
+ const normalized = hostname.endsWith(".") ? hostname.slice(0, -1) : hostname;
64
+ if (normalized.length === 0)
65
+ return null;
66
+ const labels = normalized.split(".");
67
+ if (labels.some((label) => label.length === 0))
68
+ return null;
69
+ return labels;
70
+ }
71
+ /**
72
+ * Whether a registered redirect URI is a wildcard pattern rather than a literal
73
+ * URI. Says nothing about whether the pattern is *valid* — use
74
+ * {@link checkRedirectUriPattern} for that.
75
+ *
76
+ * @example
77
+ * ```ts
78
+ * import { isRedirectUriPattern } from "@udibo/oauth2/server";
79
+ *
80
+ * isRedirectUriPattern("https://myapp-*.myorg.deno.net/cb"); // true
81
+ * isRedirectUriPattern("https://myapp.example.com/cb"); // false
82
+ * ```
83
+ */
84
+ export function isRedirectUriPattern(redirectUri) {
85
+ return redirectUri.includes("*");
86
+ }
87
+ function violation(rule, message) {
88
+ return { rule, message };
89
+ }
90
+ /**
91
+ * Check a registered redirect URI pattern against the pattern rules.
92
+ *
93
+ * Returns `null` when the value is safe to register — which includes any value
94
+ * with no `*` in it at all, since a literal redirect URI is matched exactly and
95
+ * has no pattern rules to break. Otherwise it returns the first
96
+ * {@link RedirectUriPatternViolation}, whose `message` is written to be shown
97
+ * to whoever is registering the URI.
98
+ *
99
+ * Use this at registration time to reject a bad pattern where the person
100
+ * responsible can fix it. {@link matchRedirectUri} applies the same check at
101
+ * request time, so a pattern that slipped into storage never matches.
102
+ *
103
+ * **Patterns need `isPublicSuffix`.** Without it there is no way to tell
104
+ * `myorg.deno.net` (yours) from `deno.net` (everyone's), so every pattern is
105
+ * refused. Pass `isPublicSuffix` from `@udibo/oauth2/server/public-suffix`, or
106
+ * omit it deliberately on a server that only accepts literal redirect URIs.
107
+ *
108
+ * @param pattern The registered redirect URI to check.
109
+ * @param isPublicSuffix Decides whether the domain under the wildcard is a
110
+ * public suffix. Omitting it refuses every pattern.
111
+ * @returns The violated rule and an explanation, or `null` when there is none.
112
+ *
113
+ * @example
114
+ * ```ts
115
+ * import { checkRedirectUriPattern } from "@udibo/oauth2/server";
116
+ * import { isPublicSuffix } from "@udibo/oauth2/server/public-suffix";
117
+ *
118
+ * checkRedirectUriPattern("https://myapp-*.myorg.deno.net/cb", isPublicSuffix); // null
119
+ * checkRedirectUriPattern("https://*.deno.net/cb", isPublicSuffix)?.rule; // "parent-domain"
120
+ * checkRedirectUriPattern("http://*.a.example.com/cb", isPublicSuffix)?.rule; // "scheme"
121
+ * ```
122
+ */
123
+ export function checkRedirectUriPattern(pattern, isPublicSuffix) {
124
+ if (!isRedirectUriPattern(pattern))
125
+ return null;
126
+ let url;
127
+ try {
128
+ url = new URL(pattern);
129
+ }
130
+ catch {
131
+ return violation("syntax", `"${pattern}" is not a valid absolute URL, so it cannot be matched ` +
132
+ `against a redirect_uri. Register the full callback URL, for example ` +
133
+ `https://myapp-*.myorg.example.com/auth/callback.`);
134
+ }
135
+ if (url.protocol !== "https:") {
136
+ return violation("scheme", `"${pattern}" must use https. A wildcard registration covers hosts that ` +
137
+ `do not exist yet, so the authorization code it receives has to be ` +
138
+ `protected in transit.`);
139
+ }
140
+ if ((pattern.match(/\*/g) ?? []).length !== 1) {
141
+ return violation("wildcard-count", `"${pattern}" must contain exactly one "*". More than one wildcard ` +
142
+ `widens the set of matching hosts past what can be reasoned about.`);
143
+ }
144
+ const labels = hostLabels(url.hostname);
145
+ if (!labels) {
146
+ return violation("syntax", `"${pattern}" has an empty host label. Remove the repeated or leading ` +
147
+ `"." — a host like "a..example.com" cannot resolve, and an empty ` +
148
+ `label beside the wildcard would match anything.`);
149
+ }
150
+ if (!url.hostname.includes("*") || !labels[0].includes("*")) {
151
+ return violation("wildcard-placement", `"${pattern}" may only use "*" in the leftmost part of the host — never ` +
152
+ `in the scheme, port, path, query, or fragment. A wildcard elsewhere ` +
153
+ `would let an attacker choose where the authorization code is sent.`);
154
+ }
155
+ const parentDomain = labels.slice(1).join(".");
156
+ if (!isPublicSuffix) {
157
+ return violation("parent-domain", `"${pattern}" cannot be registered: this server has no Public Suffix ` +
158
+ `List, so it cannot tell whether "${parentDomain}" is a namespace ` +
159
+ `your organization controls or one anyone can obtain a host under. ` +
160
+ `Register the callback URLs in full, or ask the operator to configure ` +
161
+ `isPublicSuffix.`);
162
+ }
163
+ if (isPublicSuffix(parentDomain)) {
164
+ return violation("parent-domain", `"${pattern}" wildcards "${parentDomain}", which is a public suffix — ` +
165
+ `anyone can register a name directly under it, obtain a neighbouring ` +
166
+ `host, and receive your authorization codes. Put the wildcard under a ` +
167
+ `domain your organization registered, for example ` +
168
+ `https://myapp-*.myorg.${parentDomain}/callback.`);
169
+ }
170
+ if (isPublicSuffix(`${CHILD_PROBE_LABEL}.${parentDomain}`)) {
171
+ return violation("parent-domain", `"${pattern}" wildcards "${parentDomain}", whose subdomains are each a ` +
172
+ `public suffix belonging to a different registrant, so a neighbouring ` +
173
+ `host is available to anyone. Put the wildcard under a domain your ` +
174
+ `organization registered.`);
175
+ }
176
+ return null;
177
+ }
178
+ /**
179
+ * The loopback IP literals RFC 8252 §7.3 covers, in the form
180
+ * `URL.hostname` normalizes them to. `localhost` is deliberately absent: RFC
181
+ * 8252 §8.3 advises against it because its resolution depends on a host file
182
+ * the authorization server does not control.
183
+ */
184
+ const LOOPBACK_HOSTNAMES = new Set(["127.0.0.1", "[::1]"]);
185
+ function matchesLoopback(registration, redirectUri) {
186
+ if (isRedirectUriPattern(registration))
187
+ return false;
188
+ let registeredUrl;
189
+ let url;
190
+ try {
191
+ registeredUrl = new URL(registration);
192
+ url = new URL(redirectUri);
193
+ }
194
+ catch {
195
+ return false;
196
+ }
197
+ if (!LOOPBACK_HOSTNAMES.has(registeredUrl.hostname))
198
+ return false;
199
+ return registeredUrl.protocol === url.protocol &&
200
+ registeredUrl.hostname === url.hostname &&
201
+ registeredUrl.username === url.username &&
202
+ registeredUrl.password === url.password &&
203
+ registeredUrl.pathname === url.pathname &&
204
+ registeredUrl.search === url.search &&
205
+ registeredUrl.hash === url.hash;
206
+ }
207
+ function matchesPattern(pattern, redirectUri, isPublicSuffix) {
208
+ if (checkRedirectUriPattern(pattern, isPublicSuffix) !== null)
209
+ return false;
210
+ let patternUrl;
211
+ let url;
212
+ try {
213
+ patternUrl = new URL(pattern);
214
+ url = new URL(redirectUri);
215
+ }
216
+ catch {
217
+ return false;
218
+ }
219
+ if (url.protocol !== "https:")
220
+ return false;
221
+ if (url.port !== patternUrl.port)
222
+ return false;
223
+ if (url.username !== patternUrl.username)
224
+ return false;
225
+ if (url.password !== patternUrl.password)
226
+ return false;
227
+ if (url.pathname !== patternUrl.pathname)
228
+ return false;
229
+ if (url.search !== patternUrl.search)
230
+ return false;
231
+ if (url.hash !== patternUrl.hash)
232
+ return false;
233
+ if (url.hostname.includes("*"))
234
+ return false;
235
+ const patternLabels = hostLabels(patternUrl.hostname);
236
+ const labels = hostLabels(url.hostname);
237
+ if (!patternLabels || !labels)
238
+ return false;
239
+ if (patternLabels.length !== labels.length)
240
+ return false;
241
+ for (let i = 1; i < patternLabels.length; i++) {
242
+ if (patternLabels[i] !== labels[i])
243
+ return false;
244
+ }
245
+ const [prefix, suffix] = patternLabels[0].split("*");
246
+ const label = labels[0];
247
+ return label.length >= prefix.length + suffix.length &&
248
+ label.startsWith(prefix) && label.endsWith(suffix);
249
+ }
250
+ /**
251
+ * Find the registered redirect URI that authorizes a requested `redirect_uri`.
252
+ *
253
+ * Literal registrations are compared by exact string match (RFC 6749
254
+ * §3.1.2.3), and an exact match always wins.
255
+ *
256
+ * A registration whose host is a **loopback IP literal** — `127.0.0.1` or
257
+ * `[::1]`, after `URL` normalizes forms like `127.1` and
258
+ * `[0:0:0:0:0:0:0:1]` — is tried next, matching the request on every part
259
+ * *except* the port (RFC 8252 §7.3: "the authorization server MUST allow any
260
+ * port to be specified at the time of the request for loopback IP redirect
261
+ * URIs"). Scheme, host, userinfo, path, query, and fragment must still be
262
+ * equal, and `localhost` is not covered — it is a name resolved by a host file
263
+ * this server does not control (RFC 8252 §8.3), so it matches exactly like any
264
+ * other host.
265
+ *
266
+ * Only if neither matches are the pattern registrations tried, under the rules
267
+ * in {@link checkRedirectUriPattern} plus:
268
+ *
269
+ * - The requested URI must be `https`, so a pattern can never be satisfied over
270
+ * plaintext.
271
+ * - `*` matches within one host label and never across a `.`, so
272
+ * `https://a-*.example.com/cb` does not match
273
+ * `https://a-x.evil.example.com/cb`.
274
+ * - Port, userinfo, path, query, and fragment must match the pattern exactly.
275
+ * - A host label may never be empty, and a single trailing dot is treated as
276
+ * the same host, so `example.com.` cannot smuggle an extra label past the
277
+ * parent-domain rule.
278
+ * - A requested URI containing `*` never matches anything, checked both on the
279
+ * raw string and on the percent-decoded host, so a pattern can never be
280
+ * replayed back as a literal redirect target.
281
+ *
282
+ * That last rule is a deliberate tightening: `*` is a legal host character, so
283
+ * a registration containing one that was previously matched by exact string
284
+ * comparison no longer matches at all. Such a registration cannot be created
285
+ * any more — a `*` now makes the value a pattern, which must satisfy the rules
286
+ * above — so this only affects rows written before patterns existed.
287
+ *
288
+ * @param registered The client's registered redirect URIs.
289
+ * @param redirectUri The `redirect_uri` from the authorization request.
290
+ * @param isPublicSuffix Decides whether the domain under a wildcard is a public
291
+ * suffix. Omitting it makes every pattern registration inert; literal
292
+ * registrations are unaffected.
293
+ * @returns The registered entry that authorized the request, or `undefined`
294
+ * when none did.
295
+ *
296
+ * @example
297
+ * ```ts
298
+ * import { matchRedirectUri } from "@udibo/oauth2/server";
299
+ * import { isPublicSuffix } from "@udibo/oauth2/server/public-suffix";
300
+ *
301
+ * const registered = ["https://myapp-*.myorg.deno.net/auth/callback"];
302
+ * matchRedirectUri(registered, "https://myapp-a1b2.myorg.deno.net/auth/callback", isPublicSuffix);
303
+ * // "https://myapp-*.myorg.deno.net/auth/callback"
304
+ * matchRedirectUri(registered, "https://myapp-a1b2.evil.myorg.deno.net/auth/callback", isPublicSuffix);
305
+ * // undefined
306
+ *
307
+ * matchRedirectUri(["http://127.0.0.1/callback"], "http://127.0.0.1:53211/callback");
308
+ * // "http://127.0.0.1/callback"
309
+ * matchRedirectUri(["http://localhost/callback"], "http://localhost:53211/callback");
310
+ * // undefined
311
+ * ```
312
+ */
313
+ export function matchRedirectUri(registered, redirectUri, isPublicSuffix) {
314
+ if (isRedirectUriPattern(redirectUri))
315
+ return undefined;
316
+ for (const entry of registered) {
317
+ if (entry === redirectUri)
318
+ return entry;
319
+ }
320
+ for (const entry of registered) {
321
+ if (matchesLoopback(entry, redirectUri))
322
+ return entry;
323
+ }
324
+ for (const entry of registered) {
325
+ if (isRedirectUriPattern(entry) &&
326
+ matchesPattern(entry, redirectUri, isPublicSuffix)) {
327
+ return entry;
328
+ }
329
+ }
330
+ return undefined;
331
+ }
@@ -0,0 +1,286 @@
1
+ /**
2
+ * Resource Server implementation for protecting resources with OAuth2 tokens.
3
+ *
4
+ * Implements bearer token validation per RFC 6750.
5
+ *
6
+ * @see https://datatracker.ietf.org/doc/html/rfc6750
7
+ * @module
8
+ */
9
+ import "../_dnt.polyfills.js";
10
+ import type { ClientInterface } from "../models/client.js";
11
+ import type { Token } from "../models/token.js";
12
+ import type { AbstractScope, ScopeConstructor } from "../models/scope.js";
13
+ import { BasicScope } from "../models/scope.js";
14
+ import { type OAuth2Error } from "../errors.js";
15
+ import { type Authorization, type RequireConditions } from "../models/authorization.js";
16
+ import type { TokenReaderInterface } from "./services/token.js";
17
+ /** Bearer token regex pattern. */
18
+ export declare const BEARER_TOKEN: RegExp;
19
+ /** Services required by the resource server. */
20
+ export interface ResourceServerServices<Client extends ClientInterface, User, S extends AbstractScope> {
21
+ /** Reads and validates access tokens for this request. */
22
+ tokenService: TokenReaderInterface<Client, User, S>;
23
+ }
24
+ /** Per-request context resolved by a {@link ResourceServer}. */
25
+ export interface ResourceServerContext<Client extends ClientInterface, User, S extends AbstractScope> {
26
+ /** Tenant-scoped services to use for this request. */
27
+ services: ResourceServerServices<Client, User, S>;
28
+ }
29
+ /** Options for configuring the resource server. */
30
+ export interface ResourceServerOptions<Client extends ClientInterface, User, S extends AbstractScope> {
31
+ /**
32
+ * Resolves the per-request context — the (e.g. tenant-scoped) {@link
33
+ * ResourceServerServices} for THIS request — so a single instance serves
34
+ * every tenant/origin. This is the only services seam: for a single-tenant
35
+ * server it is a constant function returning the same services every time
36
+ * (create the services once, outside `resolve`, and return them here).
37
+ */
38
+ resolve: (request: Request) => ResourceServerContext<Client, User, S> | Promise<ResourceServerContext<Client, User, S>>;
39
+ /** Scope constructor used to parse and compare scopes. Defaults to {@linkcode BasicScope}. */
40
+ Scope?: ScopeConstructor<S>;
41
+ /** Protection space named in `WWW-Authenticate` challenges. Defaults to `"Service"`. */
42
+ realm?: string;
43
+ /**
44
+ * Leeway in seconds applied to the access token's expiry, to absorb clock
45
+ * drift between whoever issued the token and this server. Defaults to `0`:
46
+ * a token whose expiry has passed is refused immediately.
47
+ *
48
+ * This is the one expiry check every token reader's result passes through,
49
+ * which is why the leeway belongs here rather than in a reader:
50
+ * {@linkcode IntrospectionTokenReader} reports the authorization server's
51
+ * `exp` verbatim and has no notion of skew at all, and
52
+ * {@linkcode JwksTokenReaderOptions.clockSkewSeconds} governs only that
53
+ * reader's own claim checks. Set this whenever you need drift tolerance, no
54
+ * matter which reader is in play.
55
+ */
56
+ clockSkewSeconds?: number;
57
+ /**
58
+ * Format for error responses.
59
+ * - `"oauth2"` (default): Standard OAuth2 error format with `error`,
60
+ * `error_description`, and `error_uri` fields.
61
+ * - `"problem-details"`: RFC 9457 Problem Details format with OAuth2
62
+ * extensions. `type` and `error_uri` carry the same URI; `detail` and
63
+ * `error_description` carry the same message.
64
+ */
65
+ errorFormat?: "oauth2" | "problem-details";
66
+ /**
67
+ * If true, handlers rethrow errors (as {@link OAuth2Error}) instead of
68
+ * catching them and returning a response. Framework adapters that want to
69
+ * build responses themselves should enable this. Default: false.
70
+ */
71
+ throwOnError?: boolean;
72
+ }
73
+ /** Authentication context returned by the resource server. */
74
+ export interface AuthenticatedContext<Client extends ClientInterface, User, S extends AbstractScope> {
75
+ /** The validated access token backing this request. */
76
+ token: Token<Client, User, S>;
77
+ /** The client the token was issued to. */
78
+ client: Client;
79
+ /** The resource owner, absent for client-credentials tokens. */
80
+ user?: User;
81
+ /** The scope granted to the token, if any. */
82
+ scope?: S | null;
83
+ /**
84
+ * The token's claims as one checkable object — scope, roles, permissions,
85
+ * and the active organization. Built from {@linkcode Token.claims}; a token
86
+ * with no claims yields an authorization that answers scope checks only.
87
+ */
88
+ authorization: Authorization;
89
+ }
90
+ /**
91
+ * Validates OAuth2 bearer access tokens (RFC 6750) so API endpoints can require
92
+ * authentication. Framework-agnostic: it works on web `Request`/`Response`, so
93
+ * an adapter (Hono, etc.) wires {@linkcode authenticate} into its middleware.
94
+ *
95
+ * A single instance serves every tenant/origin; per-request services come from
96
+ * the `resolve` callback in {@linkcode ResourceServerOptions}. For a
97
+ * single-tenant server, `resolve` is a constant function returning the same
98
+ * services every time.
99
+ *
100
+ * {@linkcode authenticate} throws {@linkcode HttpError} subclasses on failure
101
+ * ({@linkcode AccessDeniedError} when no token is sent,
102
+ * {@linkcode InvalidTokenError} for an invalid/expired token, and
103
+ * {@linkcode InsufficientScopeError} when scope is lacking); use
104
+ * {@linkcode handleAuthError} to turn them into RFC 6750 responses.
105
+ *
106
+ * @template Client The client entity type.
107
+ * @template User The resource-owner entity type.
108
+ * @template S The scope type used for granted/required scope comparisons.
109
+ *
110
+ * @example
111
+ * ```ts
112
+ * import { Hono } from "hono";
113
+ * import type { ClientInterface, TokenReaderInterface } from "@udibo/oauth2/server";
114
+ * import { ResourceServer } from "@udibo/oauth2/server/resource";
115
+ *
116
+ * interface User { id: string }
117
+ *
118
+ * declare const app: Hono;
119
+ * declare const tokenService: TokenReaderInterface<ClientInterface, User>;
120
+ *
121
+ * const server = new ResourceServer({
122
+ * resolve: () => ({ services: { tokenService } }),
123
+ * });
124
+ *
125
+ * app.get("/api/me", async (c) => {
126
+ * try {
127
+ * const { user } = await server.authenticate(c.req.raw, "identity:read");
128
+ * return c.json(user ?? null);
129
+ * } catch (error) {
130
+ * return server.handleAuthError(error);
131
+ * }
132
+ * });
133
+ * ```
134
+ */
135
+ export declare class ResourceServer<Client extends ClientInterface, User, S extends AbstractScope = BasicScope> {
136
+ #private;
137
+ /** Scope constructor used to parse and compare scopes. */
138
+ Scope: ScopeConstructor<S>;
139
+ /** Protection space named in `WWW-Authenticate` challenges. */
140
+ realm: string;
141
+ /** Leeway in seconds applied to the access token's expiry. Defaults to `0`. */
142
+ clockSkewSeconds: number;
143
+ /** Body format used for error responses: OAuth2 or RFC 9457 problem details. */
144
+ errorFormat: "oauth2" | "problem-details";
145
+ /** When true, handler boundaries rethrow {@linkcode OAuth2Error} instead of returning a response. */
146
+ throwOnError: boolean;
147
+ /** Resolves the per-request {@link ResourceServerContext}. */
148
+ protected resolveContext: (request: Request) => ResourceServerContext<Client, User, S> | Promise<ResourceServerContext<Client, User, S>>;
149
+ /** Creates a resource server from the given {@linkcode ResourceServerOptions}. */
150
+ constructor(options: ResourceServerOptions<Client, User, S>);
151
+ /**
152
+ * Builds a WWW-Authenticate header value per RFC 6750 Section 3.
153
+ *
154
+ * The header includes:
155
+ * - realm: The protection space
156
+ * - error: The error code (for 401/403 responses)
157
+ * - error_description: Human-readable error description
158
+ * - scope: Required scope (for insufficient_scope errors)
159
+ *
160
+ * RFC 6750 Section 3.1 registers exactly three challenge codes —
161
+ * `invalid_request`, `invalid_token`, `insufficient_scope` — so an error
162
+ * carrying anything else (including the `access_denied` this server raises
163
+ * when a request presents no credentials at all, which the same section says
164
+ * MUST NOT be given a code) produces a bare `realm` challenge. Pick the error
165
+ * class accordingly: a client reads a coded challenge and acts on it, and
166
+ * {@linkcode InsufficientScopeError} is the one that tells it "your token is
167
+ * fine, it just lacks scope" rather than sending it off to refresh.
168
+ *
169
+ * @see https://datatracker.ietf.org/doc/html/rfc6750#section-3
170
+ */
171
+ buildWwwAuthenticate(error?: OAuth2Error, requiredScope?: string): string;
172
+ /**
173
+ * Creates an error response for an OAuth2 error.
174
+ *
175
+ * The response body is formatted according to {@link errorFormat}:
176
+ * - `"oauth2"`: `{ error, error_description?, error_uri? }` as JSON.
177
+ * - `"problem-details"`: RFC 9457 Problem Details with OAuth2 extensions.
178
+ *
179
+ * Does **not** set any response headers beyond `Content-Type`. Any extra
180
+ * response headers (`WWW-Authenticate`, `Cache-Control`, `Pragma`, …) must
181
+ * be set on the error via its `headers` property before calling this
182
+ * method; they are copied through verbatim.
183
+ */
184
+ createErrorResponse(error: unknown): Response;
185
+ /**
186
+ * Normalizes an error at a handler boundary and either rethrows it (when
187
+ * {@link throwOnError} is true) or converts it to a response.
188
+ *
189
+ * The optional `prepare` callback lets a handler annotate the error —
190
+ * usually by setting headers like `Cache-Control` or `WWW-Authenticate`
191
+ * that belong on both the thrown error and the response — before the
192
+ * throw/respond decision is made.
193
+ */
194
+ handleError(error: unknown, prepare?: (error: OAuth2Error) => void): Response;
195
+ /**
196
+ * {@link handleError} variant that automatically attaches a
197
+ * `WWW-Authenticate` header (per RFC 6750 Section 3) when the error's
198
+ * status is 401 or 403. Use this at bearer-token boundaries to avoid the
199
+ * boilerplate of building the header for each error response.
200
+ *
201
+ * @example
202
+ * ```ts
203
+ * import { Hono } from "hono";
204
+ * import type { ClientInterface } from "@udibo/oauth2/server";
205
+ * import { ResourceServer } from "@udibo/oauth2/server/resource";
206
+ *
207
+ * interface User { id: string }
208
+ *
209
+ * declare const app: Hono;
210
+ * declare const server: ResourceServer<ClientInterface, User>;
211
+ *
212
+ * app.get("/api/me", async (c) => {
213
+ * try {
214
+ * const ctx = await server.authenticate(c.req.raw);
215
+ * return c.json(ctx.user ?? null);
216
+ * } catch (error) {
217
+ * return server.handleAuthError(error);
218
+ * }
219
+ * });
220
+ * ```
221
+ */
222
+ handleAuthError(error: unknown): Response;
223
+ /**
224
+ * Extracts an access token from a request.
225
+ * Looks in the Authorization header (Bearer token) first,
226
+ * then in the request body for form-encoded requests.
227
+ */
228
+ getAccessToken(request: Request): Promise<string | null>;
229
+ /**
230
+ * Retrieves and validates a token by access token string.
231
+ *
232
+ * The token's expiry is compared against now with {@linkcode
233
+ * clockSkewSeconds} of leeway, so the same tolerance applies whichever
234
+ * token reader produced the token.
235
+ *
236
+ * @throws {InvalidTokenError} If the token is invalid, expired beyond the
237
+ * configured leeway, or revoked
238
+ * @see https://datatracker.ietf.org/doc/html/rfc6750#section-3.1
239
+ */
240
+ getToken(accessToken: string, services: ResourceServerServices<Client, User, S>): Promise<Token<Client, User, S>>;
241
+ /**
242
+ * Authenticates a request and verifies the token has the required scope.
243
+ *
244
+ * @param request The incoming request
245
+ * @param requiredScope Optional scope required to access the resource
246
+ * @returns The authenticated context with token, client, user, and scope
247
+ * @throws {AccessDeniedError} If no token is provided
248
+ * @throws {InvalidTokenError} If the token is invalid or expired
249
+ * @throws {InsufficientScopeError} If the token lacks required scope (HTTP 403)
250
+ * @see https://datatracker.ietf.org/doc/html/rfc6750#section-3.1
251
+ */
252
+ authenticate(request: Request, requiredScope?: S | string): Promise<AuthenticatedContext<Client, User, S>>;
253
+ /**
254
+ * Throws unless the authenticated context satisfies every condition —
255
+ * the assertion behind the adapters' `require()` middleware, public so a
256
+ * handler authenticating manually can reuse the same checks.
257
+ *
258
+ * Scope conditions go through {@linkcode assertScope}, so their failure is
259
+ * the same RFC 6750 `insufficient_scope` challenge `requireScope` sends.
260
+ * Every other condition is answered by the context's
261
+ * {@linkcode AuthenticatedContext.authorization}; the first unmet one
262
+ * throws a plain 403 naming the failed check.
263
+ *
264
+ * @throws {InsufficientScopeError} If the token lacks a required scope (403,
265
+ * `insufficient_scope` challenge).
266
+ * @throws {InsufficientPermissionsError} If a permission, role, or
267
+ * organization condition fails (403, no challenge code).
268
+ */
269
+ assertAuthorized(context: AuthenticatedContext<Client, User, S>, conditions: RequireConditions): void;
270
+ /**
271
+ * Throws {@link InsufficientScopeError} unless `granted` contains
272
+ * `requiredScope`. Shared by {@link authenticate} and the adapters'
273
+ * scope-only guards (`requireScope`) so the comparison and the RFC 6750
274
+ * error stay identical — a guard that checks an already-authenticated
275
+ * request's scope (without re-validating the token) calls this with the
276
+ * context's `scope`. Public so a handler authenticating manually can reuse
277
+ * the same check.
278
+ *
279
+ * @throws {InsufficientScopeError} If `granted` lacks `requiredScope` (403).
280
+ */
281
+ assertScope(granted: S | null | undefined, requiredScope: S | string): void;
282
+ }
283
+ export { IntrospectionTokenReader } from "./introspection-token-reader.js";
284
+ export type { IntrospectionTokenReaderOptions } from "./introspection-token-reader.js";
285
+ export { JwksTokenReader } from "./jwks-token-reader.js";
286
+ export type { JwksTokenReaderOptions, JwtAccessTokenClaims, } from "./jwks-token-reader.js";