@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,707 @@
1
+ /**
2
+ * OAuth2 client that talks to the authorization server directly and holds the
3
+ * resulting tokens (RFC 6749 + RFC 7636 PKCE + RFC 7009 revocation +
4
+ * RFC 7662 introspection + RFC 8414 metadata + RFC 8628 device authorization).
5
+ *
6
+ * Works against any RFC-compliant authorization server. Use it for SPAs
7
+ * without a Backend-for-Frontend, CLIs, mobile shells, and server-side apps —
8
+ * anywhere this process is the one that keeps the access and refresh tokens.
9
+ * When a BFF holds them instead, use `BffClient`.
10
+ *
11
+ * @module
12
+ */
13
+ import type { AuthorizationServerMetadata, DeviceAuthorizationResponse } from "../models/responses.js";
14
+ import type { IntrospectionResponse, TokenResponse } from "../models/token.js";
15
+ import { type BaseLoginOptions, type BaseOptions, type LogoutOptions, type LogoutRedirect, OAuth2ClientBase, type SessionState, type UserInfoClaims } from "./base.js";
16
+ import { type DiscoveryCache } from "./discovery-cache.js";
17
+ import { type AuthRequestStorage, type RefreshTokenStorage, type TokenBundle, type TokenStorage } from "./storage.js";
18
+ /** Endpoints resolved via discovery or provided explicitly by the caller. */
19
+ export interface AuthorizationServerEndpoints {
20
+ /** URL of the authorization endpoint (required for the auth-code flow). */
21
+ authorization?: string;
22
+ /**
23
+ * URL of the token endpoint. Required by every grant; methods that need it
24
+ * throw a clear error if it is missing both here and from the server's
25
+ * discovery metadata.
26
+ */
27
+ token?: string;
28
+ /** URL of the revocation endpoint (RFC 7009). */
29
+ revocation?: string;
30
+ /** URL of the introspection endpoint (RFC 7662). */
31
+ introspection?: string;
32
+ /** URL of the device authorization endpoint (RFC 8628). */
33
+ deviceAuthorization?: string;
34
+ /** URL of the OIDC userinfo endpoint. */
35
+ userInfo?: string;
36
+ /** URL of the OIDC end-session endpoint (for logout redirect). */
37
+ endSession?: string;
38
+ }
39
+ /** Options accepted by {@link DirectClient}. */
40
+ export interface DirectClientOptions extends BaseOptions {
41
+ /** OAuth2 client identifier. */
42
+ clientId: string;
43
+ /**
44
+ * The client secret, sent via HTTP Basic auth on token-endpoint calls.
45
+ *
46
+ * Supplying one makes this a **confidential** client, which unlocks
47
+ * {@link DirectClient.getClientCredentialsToken} and
48
+ * {@link DirectClient.introspect}. **Omit the property** for a **public**
49
+ * client (a browser or a native app, where a secret cannot be kept) — those
50
+ * require refresh-token rotation with reuse detection on the server side.
51
+ *
52
+ * `clientSecret: undefined` reads as omitted, so a wrapper can forward an
53
+ * optional secret. An **empty string** is a construction error rather than a
54
+ * request for a public client — nobody spells "public" `""`, so it is a
55
+ * variable that resolved to blank. Note that `clientSecret: getEnv("X")`
56
+ * with `X` unset therefore yields a *public* client; require it at the
57
+ * source if the deployment must be confidential.
58
+ */
59
+ clientSecret?: string;
60
+ /** Registered redirect URI; required for the auth-code flow. */
61
+ redirectUri?: string;
62
+ /** Default scope string to request when none is passed explicitly. */
63
+ scope?: string;
64
+ /**
65
+ * Issuer URL. If provided, endpoints are fetched from
66
+ * `${issuer}/.well-known/oauth-authorization-server` on first use.
67
+ * Mutually exclusive with an explicit `endpoints` record below.
68
+ */
69
+ issuer?: string;
70
+ /** Explicit endpoint URLs, bypassing discovery. */
71
+ endpoints?: AuthorizationServerEndpoints;
72
+ /**
73
+ * Cache the discovery result is read from and written to, shared with any
74
+ * other client given the same instance. Without one, metadata is cached on
75
+ * this client only — a server that builds a client per request then
76
+ * re-fetches discovery on every request. `MemoryDiscoveryCache` is the
77
+ * ready-made implementation.
78
+ */
79
+ discoveryCache?: DiscoveryCache;
80
+ /** Access-token storage. Defaults to {@link MemoryTokenStorage}. */
81
+ tokenStorage?: TokenStorage;
82
+ /** Refresh-token storage. Defaults to {@link MemoryRefreshTokenStorage}. */
83
+ refreshTokenStorage?: RefreshTokenStorage;
84
+ /**
85
+ * Auth-request storage.
86
+ *
87
+ * Defaults to {@link SessionStorageAuthRequestStorage} in a browser document
88
+ * and {@link MemoryAuthRequestStorage} everywhere else. The browser default
89
+ * is what makes the authorize redirect work at all: an in-memory record does
90
+ * not survive the navigation away and back, so the callback rejects every
91
+ * `state` as unknown. Servers keep the in-memory default so a per-request
92
+ * client does not write pending logins into one process-wide store.
93
+ *
94
+ * Override it when the record must live somewhere else — a per-request
95
+ * cookie store on a server, or a store scoped to something other than the
96
+ * tab.
97
+ */
98
+ authRequestStorage?: AuthRequestStorage;
99
+ /**
100
+ * Max age of a pending auth-request (`state`) record before
101
+ * {@link DirectClient.exchangeAuthorizationCode} rejects it as stale, in ms.
102
+ * Bounds the callback replay window and unbounded growth of the in-memory
103
+ * store. Defaults to 10 minutes; set `Infinity` to disable the check.
104
+ */
105
+ authRequestTtlMs?: number;
106
+ }
107
+ /** Options accepted by {@link DirectClient.login}. */
108
+ export interface LoginOptions extends BaseLoginOptions {
109
+ /** Override the default scope string. */
110
+ scope?: string;
111
+ /** OIDC `prompt` parameter. */
112
+ prompt?: string;
113
+ /** Extra query parameters to append to the authorize URL. */
114
+ extraParams?: Record<string, string>;
115
+ /**
116
+ * Override the origin (scheme + host) of the authorize endpoint and the
117
+ * `redirect_uri` for THIS call, keeping their configured paths. Lets one
118
+ * build-once client serve multiple deployment origins (preview URLs,
119
+ * multi-tenant subdomains) — e.g. the Hono BFF passes the trusted request
120
+ * origin so sign-in works on whichever host the request arrived at. The
121
+ * callback returns to the same origin, so the matching `exchange` call is
122
+ * given the same origin.
123
+ */
124
+ origin?: string;
125
+ /**
126
+ * Store the pending authorization request here instead of in the client's
127
+ * configured `authRequestStorage`, for THIS call. Lets a server bind the
128
+ * record to the request it belongs to — a per-request cookie store, or a
129
+ * per-tenant table — rather than sharing one process-wide store. The
130
+ * matching `exchangeAuthorizationCode` call MUST be given a storage that
131
+ * can read the record back.
132
+ */
133
+ authRequestStorage?: AuthRequestStorage;
134
+ /**
135
+ * Override the `redirect_uri` for THIS call (used verbatim, not retargeted
136
+ * by `origin`). Lets a Backend-for-Frontend derive `redirect_uri` from its
137
+ * mounted callback path instead of restating it in the client config. The
138
+ * matching `exchangeAuthorizationCode` call MUST be given the same value
139
+ * (RFC 6749 §4.1.3 — the token-exchange `redirect_uri` must match
140
+ * authorize).
141
+ */
142
+ redirectUri?: string;
143
+ }
144
+ /** Result of {@link DirectClient.login}. */
145
+ export interface AuthorizationRedirect {
146
+ /** Fully-built authorize URL for the caller to navigate to. */
147
+ url: string;
148
+ /** Opaque `state` value the callback will echo back. */
149
+ state: string;
150
+ }
151
+ /** Result of {@link DirectClient.handleAuthorizationCallback}. */
152
+ export interface AuthorizationCallbackResult {
153
+ /** Token bundle saved on the client. */
154
+ tokens: TokenBundle;
155
+ /** `returnTo` that was recorded when `login` ran. */
156
+ returnTo?: string;
157
+ }
158
+ /** Options accepted by {@link DirectClient.startDeviceAuthorization}. */
159
+ export interface DeviceAuthorizationOptions {
160
+ /** Override the default scope string requested for the device grant. */
161
+ scope?: string;
162
+ }
163
+ /** Options accepted by {@link DirectClient.pollDeviceToken}. */
164
+ export interface PollDeviceTokenOptions {
165
+ /** Minimum seconds between polls. Defaults to the RFC 8628 fallback of 5. */
166
+ interval?: number;
167
+ /** Unix ms at which polling should give up. */
168
+ expiresAt?: number;
169
+ /** Abort signal to cancel polling. */
170
+ signal?: AbortSignal;
171
+ }
172
+ /** Generic token introspection response. */
173
+ export type IntrospectionResult = IntrospectionResponse;
174
+ /** Options accepted by the low-level exchange primitives. */
175
+ export interface ExchangeOptions {
176
+ /** Retarget the configured `redirect_uri` at this origin. */
177
+ origin?: string;
178
+ /** Use this `redirect_uri` verbatim. */
179
+ redirectUri?: string;
180
+ /** Read the pending auth-request record from here. */
181
+ authRequestStorage?: AuthRequestStorage;
182
+ }
183
+ /** Result of the low-level exchange primitives. */
184
+ export interface ExchangeResult {
185
+ /** The token bundle, not persisted to this client's storage. */
186
+ tokens: TokenBundle;
187
+ /** The rotated refresh token, when the server issued one. */
188
+ refreshToken?: string;
189
+ /** `returnTo` recorded at authorize time, for the code exchange. */
190
+ returnTo?: string;
191
+ /** The raw token-endpoint response. */
192
+ raw: TokenResponse;
193
+ }
194
+ /**
195
+ * OAuth2 client that drives the standard grants against an authorization
196
+ * server and keeps the tokens in its own storage.
197
+ *
198
+ * Public vs confidential is decided by whether `clientSecret` was supplied:
199
+ * with a secret the client authenticates via HTTP Basic (RFC 6749 §2.3.1) and
200
+ * may use `client_credentials` and introspection; without one it sends
201
+ * `client_id` in the body and is limited to the grants a public client may
202
+ * run.
203
+ *
204
+ * **Advanced — multi-session servers.**
205
+ * {@link exchangeAuthorizationCode} and {@link exchangeRefreshToken} are
206
+ * lower-level variants that bypass this client's token storage and event bus.
207
+ * They exist so server-side adapters (e.g. the Hono BFF) can drive many
208
+ * concurrent sessions through a single shared client without their tokens
209
+ * clobbering each other. SPA / mobile / CLI consumers should never reach for
210
+ * them — call {@link handleAuthorizationCallback} and {@link refresh}
211
+ * instead.
212
+ *
213
+ * @example SPA with PKCE against a discovered issuer
214
+ * ```ts
215
+ * import {
216
+ * DirectClient,
217
+ * IndexedDBRefreshTokenStorage,
218
+ * } from "@udibo/oauth2/client";
219
+ *
220
+ * const client = new DirectClient({
221
+ * clientId: "spa",
222
+ * issuer: "https://auth.example.com",
223
+ * redirectUri: "https://app.example.com/callback",
224
+ * scope: "openid profile",
225
+ * refreshTokenStorage: new IndexedDBRefreshTokenStorage({ clientId: "spa" }),
226
+ * });
227
+ *
228
+ * const { url } = await client.login({ returnTo: "/dashboard" });
229
+ * location.assign(url);
230
+ * ```
231
+ *
232
+ * @example Confidential client issuing a machine token
233
+ * ```ts
234
+ * import { DirectClient } from "@udibo/oauth2/client";
235
+ *
236
+ * const client = new DirectClient({
237
+ * clientId: "worker",
238
+ * clientSecret: Deno.env.get("CLIENT_SECRET")!,
239
+ * endpoints: { token: "https://auth.example.com/token" },
240
+ * });
241
+ *
242
+ * const tokens = await client.getClientCredentialsToken({ scope: "jobs:run" });
243
+ * ```
244
+ */
245
+ export declare class DirectClient extends OAuth2ClientBase {
246
+ #private;
247
+ /**
248
+ * Builds a client for one OAuth2 client registration.
249
+ *
250
+ * @param options Must carry `clientId`, plus either `issuer` (endpoints come
251
+ * from discovery) or `endpoints` (discovery is skipped). Supply
252
+ * `clientSecret` for a confidential client; **omit the property entirely**
253
+ * for a public one.
254
+ * @throws {TypeError} when both `endpoints` and `issuer` are supplied (they
255
+ * are mutually exclusive), or when `clientSecret` is an empty string.
256
+ * @throws {Error} when a secret is supplied in a document context, where it
257
+ * would ship to every visitor in the bundle.
258
+ */
259
+ constructor(options: DirectClientOptions);
260
+ /** True when the client was given a secret and authenticates via Basic. */
261
+ get isConfidential(): boolean;
262
+ /**
263
+ * Fetches authorization-server metadata and caches it on the instance.
264
+ *
265
+ * Tries `.well-known/oauth-authorization-server` (RFC 8414) first, then
266
+ * falls back to `.well-known/openid-configuration` (OIDC Discovery) — the
267
+ * two use the same field names, and real IdPs serve one or the other, so
268
+ * this works against any compliant server. **Lazy + cached**: it only runs
269
+ * on the first endpoint use of an `issuer`-configured client (never at
270
+ * construction), so there is no startup cost and no per-request fetch.
271
+ * Concurrent calls share one in-flight request; a failure clears the cache
272
+ * so a later call can retry.
273
+ *
274
+ * **Re-resolution contract.** The document this client holds is never
275
+ * permanent: every endpoint use re-resolves once the copy in hand is past
276
+ * its expiry, so a long-lived client picks up a rotated `jwks_uri` or a
277
+ * moved endpoint without a restart. Without a `discoveryCache` the copy
278
+ * expires {@link DEFAULT_DISCOVERY_TTL_MS} after it was fetched. With one,
279
+ * the cache owns freshness: the copy expires when the cache says its entry
280
+ * does (the `expiresAt` it reports), so the client reads the cache once
281
+ * per entry lifetime rather than once per endpoint lookup — a Redis- or
282
+ * file-backed cache costs one round trip per TTL window, not one per call.
283
+ * Either way expiry only schedules the *next* resolve; nothing re-fetches on
284
+ * a timer, and a client that is idle past its expiry makes no requests.
285
+ *
286
+ * A server that builds a client per request should supply a
287
+ * `discoveryCache`, or it re-fetches discovery on every request.
288
+ *
289
+ * @returns The server's metadata document.
290
+ * @throws {Error} when the client was configured with explicit `endpoints`
291
+ * rather than an `issuer` — there is nothing to discover.
292
+ * @throws {ServerError} when both well-known paths fail.
293
+ *
294
+ * @example
295
+ * ```ts
296
+ * import { DirectClient } from "@udibo/oauth2/client";
297
+ *
298
+ * const client = new DirectClient({
299
+ * clientId: "cli",
300
+ * issuer: "https://auth.example.com",
301
+ * });
302
+ * const meta = await client.discover();
303
+ * ```
304
+ */
305
+ discover(): Promise<AuthorizationServerMetadata>;
306
+ /** Last-seen authorization server metadata, if discovery has run. */
307
+ get metadata(): AuthorizationServerMetadata | undefined;
308
+ /**
309
+ * The configured authorization endpoint URL, if known **synchronously** —
310
+ * set explicitly via `endpoints.authorization`, or learned from a previous
311
+ * {@link discover}. `undefined` for an issuer-only client that has not
312
+ * discovered yet.
313
+ *
314
+ * Exposed so a Backend-for-Frontend can recognize an in-flight authorize URL
315
+ * (e.g. to decide whether to *resume* it or *start* a fresh login) without
316
+ * re-running discovery. See `HonoBff.loginContinuation`.
317
+ */
318
+ get authorizationEndpoint(): string | undefined;
319
+ /**
320
+ * The configured OIDC end-session endpoint URL, if known **synchronously** —
321
+ * set explicitly via `endpoints.endSession`, or learned from a previous
322
+ * {@link discover}. `undefined` when the server advertises none.
323
+ *
324
+ * Exposed so a Backend-for-Frontend can drive RP-Initiated Logout (redirect
325
+ * to the OP's end-session endpoint) without re-running discovery. See
326
+ * `HonoBffOptions.rpInitiatedLogout`.
327
+ */
328
+ get endSessionEndpoint(): string | undefined;
329
+ /**
330
+ * This client's `client_id`.
331
+ *
332
+ * Exposed for the requests that identify the client without authenticating
333
+ * it — RP-Initiated Logout's `client_id`, which is how the OP knows whose
334
+ * registered `post_logout_redirect_uris` to check when no `id_token_hint` is
335
+ * available. It is a public identifier, never a credential.
336
+ */
337
+ get clientId(): string;
338
+ /**
339
+ * Builds the PKCE-protected authorize URL and persists the verifier under
340
+ * the returned `state`. Navigate the browser to `url`; the callback route
341
+ * then calls {@link handleAuthorizationCallback}. Non-browser callers can
342
+ * use the URL for out-of-band flows.
343
+ *
344
+ * @param options `returnTo` is stored with the pending request and handed
345
+ * back by the callback. The remaining fields let a server retarget the
346
+ * authorize URL, override `redirect_uri`, or bind the pending request to a
347
+ * per-request store.
348
+ * @returns The authorize URL and the `state` the callback will echo back.
349
+ * @throws {Error} when no authorization endpoint is configured or
350
+ * discoverable.
351
+ *
352
+ * @example
353
+ * ```ts
354
+ * import { DirectClient } from "@udibo/oauth2/client";
355
+ *
356
+ * const client = new DirectClient({
357
+ * clientId: "spa",
358
+ * endpoints: { authorization: "https://auth.example.com/authorize" },
359
+ * redirectUri: "https://app.example.com/callback",
360
+ * });
361
+ * const { url, state } = await client.login({ returnTo: "/dashboard" });
362
+ * ```
363
+ */
364
+ login(options?: LoginOptions): Promise<AuthorizationRedirect>;
365
+ /**
366
+ * Completes the auth-code flow: reads `code` + `state` from the callback
367
+ * URL, exchanges the code at the token endpoint, persists the token bundle,
368
+ * and emits `authenticated`.
369
+ *
370
+ * Idempotent on duplicate calls with the same `code` — React strict-mode
371
+ * double-mounts would otherwise double-redeem a single-use code and fail the
372
+ * second call, so the first in-flight promise is returned again.
373
+ *
374
+ * @param input The callback URL, its query string, or the parsed params.
375
+ * @returns The persisted tokens and the `returnTo` recorded at login.
376
+ * @throws {OAuth2Error} when the callback carries `?error=…`, or the token
377
+ * exchange fails.
378
+ * @throws {TypeError} when `code` or `state` is missing.
379
+ * @throws {InvalidGrantError} when `state` is unknown or expired.
380
+ *
381
+ * @example
382
+ * ```ts
383
+ * import { DirectClient } from "@udibo/oauth2/client";
384
+ *
385
+ * declare const client: DirectClient;
386
+ * const { returnTo } = await client.handleAuthorizationCallback(
387
+ * location.href,
388
+ * );
389
+ * location.replace(returnTo ?? "/");
390
+ * ```
391
+ */
392
+ handleAuthorizationCallback(input: URL | URLSearchParams | string): Promise<AuthorizationCallbackResult>;
393
+ /**
394
+ * **Advanced (BFF / multi-session servers).** SPA, mobile, and CLI consumers
395
+ * should call {@link handleAuthorizationCallback} instead — that variant
396
+ * persists the token bundle to this client's storage and emits the
397
+ * `authenticated` event the React adapter listens for.
398
+ *
399
+ * Exchanges an authorization code for tokens **without persisting them**.
400
+ * Used by server-side adapters that manage their own per-session storage
401
+ * (e.g. the Hono BFF, which keeps tokens in a `SessionStore` keyed by an
402
+ * HttpOnly cookie). Calling this from a single-session client splits the
403
+ * token state across this client's storage and the caller's external store,
404
+ * so refresh, revocation, and logout all stop working as expected.
405
+ *
406
+ * The verifier and `returnTo` are looked up under `state`; on success the
407
+ * record is consumed. Emits nothing — the caller owns session semantics.
408
+ *
409
+ * @param code The authorization code from the callback.
410
+ * @param state The `state` the callback echoed back.
411
+ * @param options Per-call `redirect_uri` and auth-request storage overrides,
412
+ * which must match what {@link login} was given.
413
+ * @returns The tokens, the rotated refresh token, and the recorded
414
+ * `returnTo`, plus the raw response.
415
+ * @throws {InvalidGrantError} when `state` is unknown or older than
416
+ * `authRequestTtlMs`.
417
+ */
418
+ exchangeAuthorizationCode(code: string, state: string, options?: ExchangeOptions): Promise<ExchangeResult>;
419
+ /**
420
+ * **Advanced (BFF / multi-session servers).** SPA, mobile, and CLI consumers
421
+ * should call {@link refresh} instead — that variant persists the rotated
422
+ * bundle, dedupes concurrent calls, and emits `token_refreshed`.
423
+ *
424
+ * Exchanges a refresh token for a fresh bundle **without persisting** it.
425
+ * Used by server-side adapters that manage their own per-session storage
426
+ * (the Hono BFF's `attachToken` middleware calls this when refreshing on
427
+ * expiry). Mixing this with this client's own token storage in a
428
+ * single-session deployment leaves the two out of sync.
429
+ *
430
+ * Does not share the single-flight promise with {@link refresh} and emits
431
+ * nothing — the caller owns concurrency control across its sessions.
432
+ *
433
+ * @param refreshToken The refresh token to redeem.
434
+ * @returns The new tokens, the rotated refresh token, and the raw response.
435
+ * @throws {OAuth2Error} when the token endpoint rejects the grant.
436
+ */
437
+ exchangeRefreshToken(refreshToken: string): Promise<ExchangeResult>;
438
+ /**
439
+ * Issues a token via the `client_credentials` grant, persists it, and emits
440
+ * `authenticated`. For machine-to-machine calls where there is no user.
441
+ *
442
+ * @param options `scope` overrides the client's default scope string.
443
+ * @returns The persisted token bundle.
444
+ * @throws {Error} when the client has no `clientSecret` — RFC 6749 §4.4
445
+ * restricts this grant to confidential clients.
446
+ * @throws {OAuth2Error} when the token endpoint rejects the grant.
447
+ *
448
+ * @example
449
+ * ```ts
450
+ * import { DirectClient } from "@udibo/oauth2/client";
451
+ *
452
+ * declare const client: DirectClient;
453
+ * const { accessToken } = await client.getClientCredentialsToken({
454
+ * scope: "jobs:run",
455
+ * });
456
+ * ```
457
+ */
458
+ getClientCredentialsToken(options?: {
459
+ scope?: string;
460
+ }): Promise<TokenBundle>;
461
+ /**
462
+ * Refreshes the access token using the stored refresh token, persists the
463
+ * result, and emits `token_refreshed`. Single-flight: concurrent callers
464
+ * share one in-flight promise.
465
+ *
466
+ * If the refresh fails with `invalid_grant` (the token was revoked or, under
467
+ * rotation, already consumed), all local token state is cleared and
468
+ * `logged_out` is emitted so the framework adapter can redirect to login.
469
+ *
470
+ * Single-flight has one consequence worth knowing: a call that **joins** a
471
+ * refresh already started by {@link renewSession} inherits that call's quiet
472
+ * policy, so it will not emit `error` on a transport failure even though it
473
+ * still rejects. The rejection, not the event, is the contract for a caller
474
+ * that asked directly.
475
+ *
476
+ * A refresh-token storage that fails to read refuses the refresh: the
477
+ * rejection carries the storage's own error, `error` is emitted, and the
478
+ * stored session is left alone — a broken store is not evidence the grant
479
+ * died.
480
+ *
481
+ * @returns The new access token.
482
+ * @throws {InvalidGrantError} when no refresh token is stored, or the stored
483
+ * one is dead.
484
+ * @throws {Error} whatever the configured `RefreshTokenStorage` threw when
485
+ * the read itself failed.
486
+ */
487
+ refresh(): Promise<string>;
488
+ /**
489
+ * Initiates the device authorization flow (RFC 8628 §3.1) for an input-
490
+ * constrained device. Show the returned `user_code` and
491
+ * `verification_uri`, then hand `device_code` to {@link pollDeviceToken}.
492
+ *
493
+ * @param options `scope` overrides the client's default scope string.
494
+ * @returns The server's device authorization response.
495
+ * @throws {Error} when no device authorization endpoint is configured or
496
+ * discoverable.
497
+ * @throws {OAuth2Error} when the server rejects the request.
498
+ *
499
+ * @example
500
+ * ```ts
501
+ * import { DirectClient } from "@udibo/oauth2/client";
502
+ *
503
+ * declare const client: DirectClient;
504
+ * const grant = await client.startDeviceAuthorization();
505
+ * console.log(`go to ${grant.verification_uri}, enter ${grant.user_code}`);
506
+ * const tokens = await client.pollDeviceToken(grant.device_code, {
507
+ * interval: grant.interval,
508
+ * expiresAt: Date.now() + grant.expires_in * 1000,
509
+ * });
510
+ * ```
511
+ */
512
+ startDeviceAuthorization(options?: DeviceAuthorizationOptions): Promise<DeviceAuthorizationResponse>;
513
+ /**
514
+ * Polls the token endpoint for a device-code exchange (RFC 8628 §3.4),
515
+ * persists the tokens, and emits `authenticated`. Handles
516
+ * `authorization_pending` (keep polling) and `slow_down` (add 5s to the
517
+ * interval) automatically.
518
+ *
519
+ * @param deviceCode The `device_code` from
520
+ * {@link startDeviceAuthorization}.
521
+ * @param options Pass `interval` and `expiresAt` from the device
522
+ * authorization response so polling respects the server's advertised
523
+ * minimum interval and deadline, and `signal` to cancel.
524
+ * @returns The persisted token bundle.
525
+ * @throws {AccessDeniedError} when `signal` aborts, or the user declines.
526
+ * @throws {InvalidGrantError} when the device code expires before approval.
527
+ * @throws {OAuth2Error} on any other terminal error from the server.
528
+ */
529
+ pollDeviceToken(deviceCode: string, options?: PollDeviceTokenOptions): Promise<TokenBundle>;
530
+ /**
531
+ * Calls the introspection endpoint (RFC 7662) to ask the server whether a
532
+ * token is still active and what it carries.
533
+ *
534
+ * @param token The token to introspect.
535
+ * @param options `tokenTypeHint` tells the server which kind to look up
536
+ * first.
537
+ * @returns The introspection response; check `active`.
538
+ * @throws {Error} when the client has no `clientSecret` — RFC 7662 requires
539
+ * an authenticated caller.
540
+ * @throws {OAuth2Error} when the endpoint rejects the request.
541
+ */
542
+ introspect(token: string, options?: {
543
+ tokenTypeHint?: "access_token" | "refresh_token";
544
+ }): Promise<IntrospectionResult>;
545
+ /**
546
+ * Calls the revocation endpoint (RFC 7009) to kill a token server-side.
547
+ * Does not touch this client's storage — {@link logout} does both.
548
+ *
549
+ * @param token The token to revoke.
550
+ * @param options `tokenTypeHint` tells the server which kind to look up
551
+ * first.
552
+ * @throws {Error} when no revocation endpoint is configured or discoverable.
553
+ * @throws {OAuth2Error} when the endpoint rejects the request.
554
+ */
555
+ revoke(token: string, options?: {
556
+ tokenTypeHint?: "access_token" | "refresh_token";
557
+ }): Promise<void>;
558
+ /**
559
+ * Fetches the OIDC userinfo endpoint with the current access token,
560
+ * refreshing it first if it is close to expiry.
561
+ *
562
+ * @returns The claims the server returns.
563
+ * @throws {Error} when no userinfo endpoint is configured or discoverable.
564
+ * @throws {AccessDeniedError} when no token is stored and none can be
565
+ * refreshed.
566
+ */
567
+ getUserInfo(): Promise<UserInfoClaims>;
568
+ /**
569
+ * Base64url-decodes an OIDC `id_token` payload and returns the claims.
570
+ *
571
+ * **Does not verify the signature** — the token arrives from the token
572
+ * endpoint over TLS, so verification would only defend against a compromised
573
+ * TLS chain and is not a normal client concern. If you need verification
574
+ * (e.g. the token was obtained out-of-band), use a dedicated JWT library
575
+ * with your server's JWKS.
576
+ *
577
+ * @param idToken A compact-serialized JWS.
578
+ * @returns The decoded payload claims.
579
+ * @throws {TypeError | RangeError | SyntaxError} on a token that isn't a
580
+ * decodable JWS with a JSON payload. Callers that surface an authorization
581
+ * server's response to a user should catch, since a broken or hostile
582
+ * server controls this input.
583
+ */
584
+ decodeIdToken(idToken: string): UserInfoClaims;
585
+ /**
586
+ * Fetches with `Authorization: Bearer <access token>` attached, retrying
587
+ * once after a silent {@link refresh} if the response is a `401` carrying
588
+ * `WWW-Authenticate: … error="invalid_token"`.
589
+ *
590
+ * A `401` without that challenge is returned as-is — it means "not allowed",
591
+ * not "token stale", and re-minting would not help.
592
+ *
593
+ * @param input Request target, as for `fetch`. A `Request` keeps the headers
594
+ * and body it was built with; it is cloned up front so the retry has an
595
+ * unread body.
596
+ * @param init Request options. A caller-set `Authorization` header wins, and
597
+ * `init.headers` override same-named headers on a `Request` input.
598
+ * @returns The response; the original `401` when no new token could be
599
+ * minted. A transport failure on the retry itself rejects rather than
600
+ * masquerading as the original `401`.
601
+ *
602
+ * @example
603
+ * ```ts
604
+ * import { DirectClient } from "@udibo/oauth2/client";
605
+ *
606
+ * declare const client: DirectClient;
607
+ * const res = await client.fetch("https://api.example.com/items");
608
+ * ```
609
+ */
610
+ fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
611
+ /**
612
+ * Revokes the stored refresh token (best effort), clears all local token
613
+ * state, emits `logged_out`, and returns the OIDC end-session URL when the
614
+ * server advertises one.
615
+ *
616
+ * Best effort covers the read too: a refresh-token store that cannot be read
617
+ * skips the revocation rather than failing the sign-out, because a client
618
+ * that stays signed in locally because its store broke is the worse outcome.
619
+ *
620
+ * @param options `returnTo` becomes `post_logout_redirect_uri` on the
621
+ * end-session URL.
622
+ * @returns `{ url }` when the browser should visit the OP's end-session
623
+ * endpoint to drop the upstream SSO session, `{}` when sign-out completed
624
+ * locally.
625
+ *
626
+ * @example
627
+ * ```ts
628
+ * import { DirectClient } from "@udibo/oauth2/client";
629
+ *
630
+ * declare const client: DirectClient;
631
+ * const { url } = await client.logout({ returnTo: "https://app.test/" });
632
+ * if (url) location.assign(url);
633
+ * ```
634
+ */
635
+ logout(options?: LogoutOptions): Promise<LogoutRedirect>;
636
+ /**
637
+ * The signed-in user's claims: the decoded `id_token` when one was issued,
638
+ * otherwise the userinfo endpoint when one is configured, otherwise `null`.
639
+ *
640
+ * @returns The claims, or `null` when no token is stored or neither source
641
+ * is available.
642
+ */
643
+ getUser(): Promise<UserInfoClaims | null>;
644
+ /**
645
+ * The session as this client sees it, derived from stored tokens — no
646
+ * network call unless the claims come from a userinfo endpoint.
647
+ *
648
+ * `isAuthenticated` requires a usable access token: a stored bundle whose
649
+ * `accessToken` is non-empty and not past its expiry. A holder of a valid
650
+ * token therefore still reads as signed in when the server issues neither an
651
+ * `id_token` nor a userinfo endpoint, while an expired one reads as signed
652
+ * out rather than leaving the UI authenticated over a dead token. An expired
653
+ * bundle that a stored refresh token could still revive also reads as signed
654
+ * in, with `sessionExpiresIn: 0` — call {@link renewSession} to revive it.
655
+ *
656
+ * `logoutUrl` is always `null`: sign-out runs through {@link logout}, which
657
+ * revokes and clears locally rather than sending the browser somewhere.
658
+ *
659
+ * Never rejects — a failure to resolve claims reports a signed-out session
660
+ * and emits `error`, per {@link OAuth2ClientBase.getSession}.
661
+ *
662
+ * @returns The current {@link SessionState}.
663
+ */
664
+ getSession(): Promise<SessionState>;
665
+ /**
666
+ * Refreshes the access token, then reports the resulting session.
667
+ *
668
+ * Never rejects: a dead grant has already cleared the session and emitted
669
+ * `logged_out`, so the reported state is signed out, while a transient
670
+ * network failure leaves the stored tokens — and the reported state — as
671
+ * they were. Unlike {@link refresh}, nothing on this path emits `error`:
672
+ * it runs on a background timer, and a blip the client will simply retry
673
+ * must not paint a user-visible error over a session that is still perfectly
674
+ * good. A dead grant still emits `logged_out`, because the UI does have to
675
+ * react to that.
676
+ *
677
+ * "Transient" here means only "not `invalid_grant`", so a durable failure —
678
+ * a rotated client secret answering `invalid_client`, or a token endpoint
679
+ * returning `500` indefinitely — is retried silently for as long as the
680
+ * timer runs. The session ends when the access token finally expires and a
681
+ * request 401s, not when renewal starts failing. Subscribe to
682
+ * `token_refreshed` if you need to notice renewals that stopped landing.
683
+ *
684
+ * **A client with no refresh token cannot renew.** That includes the
685
+ * `client_credentials` case, where re-running the grant would be possible in
686
+ * principle: doing it automatically is refused because a confidential client
687
+ * that had signed a *user* in would silently swap that user's session for a
688
+ * machine identity. Re-run {@link getClientCredentialsToken} yourself.
689
+ *
690
+ * @returns The {@link SessionState} after the refresh attempt.
691
+ */
692
+ renewSession(): Promise<SessionState>;
693
+ /**
694
+ * Returns a usable access token, refreshing first when the stored one is
695
+ * within 30 seconds of expiry.
696
+ *
697
+ * Reach for this when you must attach `Authorization: Bearer <token>` to a
698
+ * request {@link fetch} can't carry (a custom transport, a third-party SDK).
699
+ * For ordinary HTTP calls prefer {@link fetch}, which attaches the token and
700
+ * handles the 401/refresh dance for you.
701
+ *
702
+ * @returns A non-expired access token.
703
+ * @throws {InvalidGrantError} when nothing is stored and no refresh token is
704
+ * available.
705
+ */
706
+ getAccessToken(): Promise<string>;
707
+ }