@atproto/oauth-provider 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 (631) hide show
  1. package/.postcssrc.yml +3 -0
  2. package/CHANGELOG.md +19 -0
  3. package/LICENSE.txt +7 -0
  4. package/dist/access-token/access-token-type.d.ts +6 -0
  5. package/dist/access-token/access-token-type.d.ts.map +1 -0
  6. package/dist/access-token/access-token-type.js +10 -0
  7. package/dist/access-token/access-token-type.js.map +1 -0
  8. package/dist/account/account-manager.d.ts +14 -0
  9. package/dist/account/account-manager.d.ts.map +1 -0
  10. package/dist/account/account-manager.js +39 -0
  11. package/dist/account/account-manager.js.map +1 -0
  12. package/dist/account/account-store.d.ts +39 -0
  13. package/dist/account/account-store.d.ts.map +1 -0
  14. package/dist/account/account-store.js +19 -0
  15. package/dist/account/account-store.js.map +1 -0
  16. package/dist/account/account.d.ts +8 -0
  17. package/dist/account/account.d.ts.map +1 -0
  18. package/dist/account/account.js +3 -0
  19. package/dist/account/account.js.map +1 -0
  20. package/dist/assets/app/bundle-manifest.json +22 -0
  21. package/dist/assets/app/main.css +3 -0
  22. package/dist/assets/app/main.js +20 -0
  23. package/dist/assets/app/main.js.map +1 -0
  24. package/dist/assets/asset.d.ts +9 -0
  25. package/dist/assets/asset.d.ts.map +1 -0
  26. package/dist/assets/asset.js +3 -0
  27. package/dist/assets/asset.js.map +1 -0
  28. package/dist/assets/assets-middleware.d.ts +2 -0
  29. package/dist/assets/assets-middleware.d.ts.map +1 -0
  30. package/dist/assets/assets-middleware.js +30 -0
  31. package/dist/assets/assets-middleware.js.map +1 -0
  32. package/dist/assets/index.d.ts +4 -0
  33. package/dist/assets/index.d.ts.map +1 -0
  34. package/dist/assets/index.js +65 -0
  35. package/dist/assets/index.js.map +1 -0
  36. package/dist/client/client-auth.d.ts +13 -0
  37. package/dist/client/client-auth.d.ts.map +1 -0
  38. package/dist/client/client-auth.js +35 -0
  39. package/dist/client/client-auth.js.map +1 -0
  40. package/dist/client/client-data.d.ts +8 -0
  41. package/dist/client/client-data.d.ts.map +1 -0
  42. package/dist/client/client-data.js +3 -0
  43. package/dist/client/client-data.js.map +1 -0
  44. package/dist/client/client-id.d.ts +4 -0
  45. package/dist/client/client-id.d.ts.map +1 -0
  46. package/dist/client/client-id.js +6 -0
  47. package/dist/client/client-id.js.map +1 -0
  48. package/dist/client/client-info.d.ts +13 -0
  49. package/dist/client/client-info.d.ts.map +1 -0
  50. package/dist/client/client-info.js +3 -0
  51. package/dist/client/client-info.js.map +1 -0
  52. package/dist/client/client-manager.d.ts +38 -0
  53. package/dist/client/client-manager.d.ts.map +1 -0
  54. package/dist/client/client-manager.js +534 -0
  55. package/dist/client/client-manager.js.map +1 -0
  56. package/dist/client/client-store.d.ts +13 -0
  57. package/dist/client/client-store.d.ts.map +1 -0
  58. package/dist/client/client-store.js +39 -0
  59. package/dist/client/client-store.js.map +1 -0
  60. package/dist/client/client-utils.d.ts +6 -0
  61. package/dist/client/client-utils.d.ts.map +1 -0
  62. package/dist/client/client-utils.js +40 -0
  63. package/dist/client/client-utils.js.map +1 -0
  64. package/dist/client/client.d.ts +41 -0
  65. package/dist/client/client.d.ts.map +1 -0
  66. package/dist/client/client.js +163 -0
  67. package/dist/client/client.js.map +1 -0
  68. package/dist/constants.d.ts +42 -0
  69. package/dist/constants.d.ts.map +1 -0
  70. package/dist/constants.js +53 -0
  71. package/dist/constants.js.map +1 -0
  72. package/dist/device/device-data.d.ts +20 -0
  73. package/dist/device/device-data.d.ts.map +1 -0
  74. package/dist/device/device-data.js +11 -0
  75. package/dist/device/device-data.js.map +1 -0
  76. package/dist/device/device-details.d.ts +17 -0
  77. package/dist/device/device-details.d.ts.map +1 -0
  78. package/dist/device/device-details.js +34 -0
  79. package/dist/device/device-details.js.map +1 -0
  80. package/dist/device/device-id.d.ts +6 -0
  81. package/dist/device/device-id.d.ts.map +1 -0
  82. package/dist/device/device-id.js +18 -0
  83. package/dist/device/device-id.js.map +1 -0
  84. package/dist/device/device-manager.d.ts +88 -0
  85. package/dist/device/device-manager.d.ts.map +1 -0
  86. package/dist/device/device-manager.js +206 -0
  87. package/dist/device/device-manager.js.map +1 -0
  88. package/dist/device/device-store.d.ts +15 -0
  89. package/dist/device/device-store.d.ts.map +1 -0
  90. package/dist/device/device-store.js +36 -0
  91. package/dist/device/device-store.js.map +1 -0
  92. package/dist/device/session-id.d.ts +6 -0
  93. package/dist/device/session-id.d.ts.map +1 -0
  94. package/dist/device/session-id.js +18 -0
  95. package/dist/device/session-id.js.map +1 -0
  96. package/dist/dpop/dpop-manager.d.ts +33 -0
  97. package/dist/dpop/dpop-manager.d.ts.map +1 -0
  98. package/dist/dpop/dpop-manager.js +115 -0
  99. package/dist/dpop/dpop-manager.js.map +1 -0
  100. package/dist/dpop/dpop-nonce.d.ts +13 -0
  101. package/dist/dpop/dpop-nonce.d.ts.map +1 -0
  102. package/dist/dpop/dpop-nonce.js +94 -0
  103. package/dist/dpop/dpop-nonce.js.map +1 -0
  104. package/dist/errors/access-denied-error.d.ts +8 -0
  105. package/dist/errors/access-denied-error.d.ts.map +1 -0
  106. package/dist/errors/access-denied-error.js +21 -0
  107. package/dist/errors/access-denied-error.js.map +1 -0
  108. package/dist/errors/account-selection-required-error.d.ts +6 -0
  109. package/dist/errors/account-selection-required-error.d.ts.map +1 -0
  110. package/dist/errors/account-selection-required-error.js +11 -0
  111. package/dist/errors/account-selection-required-error.js.map +1 -0
  112. package/dist/errors/consent-required-error.d.ts +6 -0
  113. package/dist/errors/consent-required-error.d.ts.map +1 -0
  114. package/dist/errors/consent-required-error.js +11 -0
  115. package/dist/errors/consent-required-error.js.map +1 -0
  116. package/dist/errors/invalid-authorization-details-error.d.ts +20 -0
  117. package/dist/errors/invalid-authorization-details-error.d.ts.map +1 -0
  118. package/dist/errors/invalid-authorization-details-error.js +26 -0
  119. package/dist/errors/invalid-authorization-details-error.js.map +1 -0
  120. package/dist/errors/invalid-client-error.d.ts +18 -0
  121. package/dist/errors/invalid-client-error.d.ts.map +1 -0
  122. package/dist/errors/invalid-client-error.js +24 -0
  123. package/dist/errors/invalid-client-error.js.map +1 -0
  124. package/dist/errors/invalid-client-id-error.d.ts +13 -0
  125. package/dist/errors/invalid-client-id-error.d.ts.map +1 -0
  126. package/dist/errors/invalid-client-id-error.js +25 -0
  127. package/dist/errors/invalid-client-id-error.js.map +1 -0
  128. package/dist/errors/invalid-client-metadata-error.d.ts +13 -0
  129. package/dist/errors/invalid-client-metadata-error.d.ts.map +1 -0
  130. package/dist/errors/invalid-client-metadata-error.js +23 -0
  131. package/dist/errors/invalid-client-metadata-error.js.map +1 -0
  132. package/dist/errors/invalid-dpop-key-binding-error.d.ts +12 -0
  133. package/dist/errors/invalid-dpop-key-binding-error.d.ts.map +1 -0
  134. package/dist/errors/invalid-dpop-key-binding-error.js +20 -0
  135. package/dist/errors/invalid-dpop-key-binding-error.js.map +1 -0
  136. package/dist/errors/invalid-dpop-proof-error.d.ts +5 -0
  137. package/dist/errors/invalid-dpop-proof-error.d.ts.map +1 -0
  138. package/dist/errors/invalid-dpop-proof-error.js +12 -0
  139. package/dist/errors/invalid-dpop-proof-error.js.map +1 -0
  140. package/dist/errors/invalid-grant-error.d.ts +14 -0
  141. package/dist/errors/invalid-grant-error.d.ts.map +1 -0
  142. package/dist/errors/invalid-grant-error.js +20 -0
  143. package/dist/errors/invalid-grant-error.js.map +1 -0
  144. package/dist/errors/invalid-parameters-error.d.ts +6 -0
  145. package/dist/errors/invalid-parameters-error.d.ts.map +1 -0
  146. package/dist/errors/invalid-parameters-error.js +11 -0
  147. package/dist/errors/invalid-parameters-error.js.map +1 -0
  148. package/dist/errors/invalid-redirect-uri-error.d.ts +11 -0
  149. package/dist/errors/invalid-redirect-uri-error.d.ts.map +1 -0
  150. package/dist/errors/invalid-redirect-uri-error.js +21 -0
  151. package/dist/errors/invalid-redirect-uri-error.js.map +1 -0
  152. package/dist/errors/invalid-request-error.d.ts +28 -0
  153. package/dist/errors/invalid-request-error.d.ts.map +1 -0
  154. package/dist/errors/invalid-request-error.js +34 -0
  155. package/dist/errors/invalid-request-error.js.map +1 -0
  156. package/dist/errors/invalid-token-error.d.ts +16 -0
  157. package/dist/errors/invalid-token-error.d.ts.map +1 -0
  158. package/dist/errors/invalid-token-error.js +45 -0
  159. package/dist/errors/invalid-token-error.js.map +1 -0
  160. package/dist/errors/login-required-error.d.ts +6 -0
  161. package/dist/errors/login-required-error.d.ts.map +1 -0
  162. package/dist/errors/login-required-error.js +11 -0
  163. package/dist/errors/login-required-error.js.map +1 -0
  164. package/dist/errors/oauth-error.d.ts +13 -0
  165. package/dist/errors/oauth-error.d.ts.map +1 -0
  166. package/dist/errors/oauth-error.js +29 -0
  167. package/dist/errors/oauth-error.js.map +1 -0
  168. package/dist/errors/unauthorized-client-error.d.ts +18 -0
  169. package/dist/errors/unauthorized-client-error.d.ts.map +1 -0
  170. package/dist/errors/unauthorized-client-error.js +24 -0
  171. package/dist/errors/unauthorized-client-error.js.map +1 -0
  172. package/dist/errors/use-dpop-nonce-error.d.ts +18 -0
  173. package/dist/errors/use-dpop-nonce-error.d.ts.map +1 -0
  174. package/dist/errors/use-dpop-nonce-error.js +27 -0
  175. package/dist/errors/use-dpop-nonce-error.js.map +1 -0
  176. package/dist/errors/www-authenticate-error.d.ts +9 -0
  177. package/dist/errors/www-authenticate-error.d.ts.map +1 -0
  178. package/dist/errors/www-authenticate-error.js +46 -0
  179. package/dist/errors/www-authenticate-error.js.map +1 -0
  180. package/dist/index.d.ts +14 -0
  181. package/dist/index.d.ts.map +1 -0
  182. package/dist/index.js +31 -0
  183. package/dist/index.js.map +1 -0
  184. package/dist/lib/html/build-document.d.ts +32 -0
  185. package/dist/lib/html/build-document.d.ts.map +1 -0
  186. package/dist/lib/html/build-document.js +61 -0
  187. package/dist/lib/html/build-document.js.map +1 -0
  188. package/dist/lib/html/escapers.d.ts +9 -0
  189. package/dist/lib/html/escapers.d.ts.map +1 -0
  190. package/dist/lib/html/escapers.js +66 -0
  191. package/dist/lib/html/escapers.js.map +1 -0
  192. package/dist/lib/html/html.d.ts +13 -0
  193. package/dist/lib/html/html.d.ts.map +1 -0
  194. package/dist/lib/html/html.js +53 -0
  195. package/dist/lib/html/html.js.map +1 -0
  196. package/dist/lib/html/index.d.ts +4 -0
  197. package/dist/lib/html/index.d.ts.map +1 -0
  198. package/dist/lib/html/index.js +21 -0
  199. package/dist/lib/html/index.js.map +1 -0
  200. package/dist/lib/html/tags.d.ts +34 -0
  201. package/dist/lib/html/tags.d.ts.map +1 -0
  202. package/dist/lib/html/tags.js +47 -0
  203. package/dist/lib/html/tags.js.map +1 -0
  204. package/dist/lib/html/util.d.ts +4 -0
  205. package/dist/lib/html/util.d.ts.map +1 -0
  206. package/dist/lib/html/util.js +20 -0
  207. package/dist/lib/html/util.js.map +1 -0
  208. package/dist/lib/http/accept.d.ts +29 -0
  209. package/dist/lib/http/accept.d.ts.map +1 -0
  210. package/dist/lib/http/accept.js +67 -0
  211. package/dist/lib/http/accept.js.map +1 -0
  212. package/dist/lib/http/context.d.ts +5 -0
  213. package/dist/lib/http/context.d.ts.map +1 -0
  214. package/dist/lib/http/context.js +10 -0
  215. package/dist/lib/http/context.js.map +1 -0
  216. package/dist/lib/http/index.d.ts +10 -0
  217. package/dist/lib/http/index.d.ts.map +1 -0
  218. package/dist/lib/http/index.js +26 -0
  219. package/dist/lib/http/index.js.map +1 -0
  220. package/dist/lib/http/method.d.ts +6 -0
  221. package/dist/lib/http/method.d.ts.map +1 -0
  222. package/dist/lib/http/method.js +19 -0
  223. package/dist/lib/http/method.js.map +1 -0
  224. package/dist/lib/http/middleware.d.ts +18 -0
  225. package/dist/lib/http/middleware.d.ts.map +1 -0
  226. package/dist/lib/http/middleware.js +118 -0
  227. package/dist/lib/http/middleware.js.map +1 -0
  228. package/dist/lib/http/parser.d.ts +33 -0
  229. package/dist/lib/http/parser.d.ts.map +1 -0
  230. package/dist/lib/http/parser.js +48 -0
  231. package/dist/lib/http/parser.js.map +1 -0
  232. package/dist/lib/http/path.d.ts +9 -0
  233. package/dist/lib/http/path.d.ts.map +1 -0
  234. package/dist/lib/http/path.js +54 -0
  235. package/dist/lib/http/path.js.map +1 -0
  236. package/dist/lib/http/request.d.ts +33 -0
  237. package/dist/lib/http/request.d.ts.map +1 -0
  238. package/dist/lib/http/request.js +86 -0
  239. package/dist/lib/http/request.js.map +1 -0
  240. package/dist/lib/http/response.d.ts +13 -0
  241. package/dist/lib/http/response.d.ts.map +1 -0
  242. package/dist/lib/http/response.js +98 -0
  243. package/dist/lib/http/response.js.map +1 -0
  244. package/dist/lib/http/route.d.ts +25 -0
  245. package/dist/lib/http/route.d.ts.map +1 -0
  246. package/dist/lib/http/route.js +39 -0
  247. package/dist/lib/http/route.js.map +1 -0
  248. package/dist/lib/http/router.d.ts +32 -0
  249. package/dist/lib/http/router.d.ts.map +1 -0
  250. package/dist/lib/http/router.js +74 -0
  251. package/dist/lib/http/router.js.map +1 -0
  252. package/dist/lib/http/stream.d.ts +13 -0
  253. package/dist/lib/http/stream.d.ts.map +1 -0
  254. package/dist/lib/http/stream.js +46 -0
  255. package/dist/lib/http/stream.js.map +1 -0
  256. package/dist/lib/http/types.d.ts +7 -0
  257. package/dist/lib/http/types.d.ts.map +1 -0
  258. package/dist/lib/http/types.js +3 -0
  259. package/dist/lib/http/types.js.map +1 -0
  260. package/dist/lib/http/url.d.ts +8 -0
  261. package/dist/lib/http/url.d.ts.map +1 -0
  262. package/dist/lib/http/url.js +22 -0
  263. package/dist/lib/http/url.js.map +1 -0
  264. package/dist/lib/redis.d.ts +5 -0
  265. package/dist/lib/redis.d.ts.map +1 -0
  266. package/dist/lib/redis.js +22 -0
  267. package/dist/lib/redis.js.map +1 -0
  268. package/dist/lib/util/authorization-header.d.ts +4 -0
  269. package/dist/lib/util/authorization-header.d.ts.map +1 -0
  270. package/dist/lib/util/authorization-header.js +23 -0
  271. package/dist/lib/util/authorization-header.js.map +1 -0
  272. package/dist/lib/util/cast.d.ts +2 -0
  273. package/dist/lib/util/cast.d.ts.map +1 -0
  274. package/dist/lib/util/cast.js +10 -0
  275. package/dist/lib/util/cast.js.map +1 -0
  276. package/dist/lib/util/crypto.d.ts +3 -0
  277. package/dist/lib/util/crypto.d.ts.map +1 -0
  278. package/dist/lib/util/crypto.js +29 -0
  279. package/dist/lib/util/crypto.js.map +1 -0
  280. package/dist/lib/util/date.d.ts +3 -0
  281. package/dist/lib/util/date.d.ts.map +1 -0
  282. package/dist/lib/util/date.js +12 -0
  283. package/dist/lib/util/date.js.map +1 -0
  284. package/dist/lib/util/hostname.d.ts +6 -0
  285. package/dist/lib/util/hostname.d.ts.map +1 -0
  286. package/dist/lib/util/hostname.js +24 -0
  287. package/dist/lib/util/hostname.js.map +1 -0
  288. package/dist/lib/util/redirect-uri.d.ts +7 -0
  289. package/dist/lib/util/redirect-uri.d.ts.map +1 -0
  290. package/dist/lib/util/redirect-uri.js +44 -0
  291. package/dist/lib/util/redirect-uri.js.map +1 -0
  292. package/dist/lib/util/time.d.ts +6 -0
  293. package/dist/lib/util/time.d.ts.map +1 -0
  294. package/dist/lib/util/time.js +28 -0
  295. package/dist/lib/util/time.js.map +1 -0
  296. package/dist/lib/util/type.d.ts +6 -0
  297. package/dist/lib/util/type.d.ts.map +1 -0
  298. package/dist/lib/util/type.js +3 -0
  299. package/dist/lib/util/type.js.map +1 -0
  300. package/dist/lib/util/well-known.d.ts +3 -0
  301. package/dist/lib/util/well-known.d.ts.map +1 -0
  302. package/dist/lib/util/well-known.js +11 -0
  303. package/dist/lib/util/well-known.js.map +1 -0
  304. package/dist/metadata/build-metadata.d.ts +14 -0
  305. package/dist/metadata/build-metadata.d.ts.map +1 -0
  306. package/dist/metadata/build-metadata.js +132 -0
  307. package/dist/metadata/build-metadata.js.map +1 -0
  308. package/dist/oauth-client.d.ts +4 -0
  309. package/dist/oauth-client.d.ts.map +1 -0
  310. package/dist/oauth-client.js +19 -0
  311. package/dist/oauth-client.js.map +1 -0
  312. package/dist/oauth-dpop.d.ts +3 -0
  313. package/dist/oauth-dpop.d.ts.map +1 -0
  314. package/dist/oauth-dpop.js +19 -0
  315. package/dist/oauth-dpop.js.map +1 -0
  316. package/dist/oauth-errors.d.ts +20 -0
  317. package/dist/oauth-errors.d.ts.map +1 -0
  318. package/dist/oauth-errors.js +43 -0
  319. package/dist/oauth-errors.js.map +1 -0
  320. package/dist/oauth-hooks.d.ts +42 -0
  321. package/dist/oauth-hooks.d.ts.map +1 -0
  322. package/dist/oauth-hooks.js +3 -0
  323. package/dist/oauth-hooks.js.map +1 -0
  324. package/dist/oauth-provider.d.ts +179 -0
  325. package/dist/oauth-provider.d.ts.map +1 -0
  326. package/dist/oauth-provider.js +748 -0
  327. package/dist/oauth-provider.js.map +1 -0
  328. package/dist/oauth-store.d.ts +11 -0
  329. package/dist/oauth-store.d.ts.map +1 -0
  330. package/dist/oauth-store.js +27 -0
  331. package/dist/oauth-store.js.map +1 -0
  332. package/dist/oauth-verifier.d.ts +66 -0
  333. package/dist/oauth-verifier.d.ts.map +1 -0
  334. package/dist/oauth-verifier.js +94 -0
  335. package/dist/oauth-verifier.js.map +1 -0
  336. package/dist/oidc/claims.d.ts +16 -0
  337. package/dist/oidc/claims.d.ts.map +1 -0
  338. package/dist/oidc/claims.js +29 -0
  339. package/dist/oidc/claims.js.map +1 -0
  340. package/dist/oidc/sub.d.ts +4 -0
  341. package/dist/oidc/sub.d.ts.map +1 -0
  342. package/dist/oidc/sub.js +6 -0
  343. package/dist/oidc/sub.js.map +1 -0
  344. package/dist/oidc/userinfo.d.ts +7 -0
  345. package/dist/oidc/userinfo.d.ts.map +1 -0
  346. package/dist/oidc/userinfo.js +3 -0
  347. package/dist/oidc/userinfo.js.map +1 -0
  348. package/dist/output/build-error-payload.d.ts +6 -0
  349. package/dist/output/build-error-payload.d.ts.map +1 -0
  350. package/dist/output/build-error-payload.js +108 -0
  351. package/dist/output/build-error-payload.js.map +1 -0
  352. package/dist/output/customization.d.ts +37 -0
  353. package/dist/output/customization.d.ts.map +1 -0
  354. package/dist/output/customization.js +62 -0
  355. package/dist/output/customization.js.map +1 -0
  356. package/dist/output/send-authorize-page.d.ts +43 -0
  357. package/dist/output/send-authorize-page.d.ts.map +1 -0
  358. package/dist/output/send-authorize-page.js +49 -0
  359. package/dist/output/send-authorize-page.js.map +1 -0
  360. package/dist/output/send-authorize-redirect.d.ts +25 -0
  361. package/dist/output/send-authorize-redirect.d.ts.map +1 -0
  362. package/dist/output/send-authorize-redirect.js +72 -0
  363. package/dist/output/send-authorize-redirect.js.map +1 -0
  364. package/dist/output/send-error-page.d.ts +5 -0
  365. package/dist/output/send-error-page.d.ts.map +1 -0
  366. package/dist/output/send-error-page.js +31 -0
  367. package/dist/output/send-error-page.js.map +1 -0
  368. package/dist/output/send-web-page.d.ts +8 -0
  369. package/dist/output/send-web-page.d.ts.map +1 -0
  370. package/dist/output/send-web-page.js +48 -0
  371. package/dist/output/send-web-page.js.map +1 -0
  372. package/dist/parameters/claims-requested.d.ts +3 -0
  373. package/dist/parameters/claims-requested.d.ts.map +1 -0
  374. package/dist/parameters/claims-requested.js +77 -0
  375. package/dist/parameters/claims-requested.js.map +1 -0
  376. package/dist/parameters/oidc-payload.d.ts +31 -0
  377. package/dist/parameters/oidc-payload.d.ts.map +1 -0
  378. package/dist/parameters/oidc-payload.js +25 -0
  379. package/dist/parameters/oidc-payload.js.map +1 -0
  380. package/dist/replay/replay-manager.d.ts +10 -0
  381. package/dist/replay/replay-manager.d.ts.map +1 -0
  382. package/dist/replay/replay-manager.js +23 -0
  383. package/dist/replay/replay-manager.js.map +1 -0
  384. package/dist/replay/replay-store-memory.d.ts +11 -0
  385. package/dist/replay/replay-store-memory.d.ts.map +1 -0
  386. package/dist/replay/replay-store-memory.js +30 -0
  387. package/dist/replay/replay-store-memory.js.map +1 -0
  388. package/dist/replay/replay-store-redis.d.ts +16 -0
  389. package/dist/replay/replay-store-redis.d.ts.map +1 -0
  390. package/dist/replay/replay-store-redis.js +20 -0
  391. package/dist/replay/replay-store-redis.js.map +1 -0
  392. package/dist/replay/replay-store.d.ts +16 -0
  393. package/dist/replay/replay-store.d.ts.map +1 -0
  394. package/dist/replay/replay-store.js +22 -0
  395. package/dist/replay/replay-store.js.map +1 -0
  396. package/dist/request/code.d.ts +7 -0
  397. package/dist/request/code.d.ts.map +1 -0
  398. package/dist/request/code.js +20 -0
  399. package/dist/request/code.js.map +1 -0
  400. package/dist/request/request-data.d.ts +21 -0
  401. package/dist/request/request-data.d.ts.map +1 -0
  402. package/dist/request/request-data.js +6 -0
  403. package/dist/request/request-data.js.map +1 -0
  404. package/dist/request/request-id.d.ts +6 -0
  405. package/dist/request/request-id.d.ts.map +1 -0
  406. package/dist/request/request-id.js +18 -0
  407. package/dist/request/request-id.js.map +1 -0
  408. package/dist/request/request-info.d.ts +12 -0
  409. package/dist/request/request-info.d.ts.map +1 -0
  410. package/dist/request/request-info.js +3 -0
  411. package/dist/request/request-info.js.map +1 -0
  412. package/dist/request/request-manager.d.ts +40 -0
  413. package/dist/request/request-manager.d.ts.map +1 -0
  414. package/dist/request/request-manager.js +310 -0
  415. package/dist/request/request-manager.js.map +1 -0
  416. package/dist/request/request-store-memory.d.ts +16 -0
  417. package/dist/request/request-store-memory.d.ts.map +1 -0
  418. package/dist/request/request-store-memory.js +31 -0
  419. package/dist/request/request-store-memory.js.map +1 -0
  420. package/dist/request/request-store-redis.d.ts +24 -0
  421. package/dist/request/request-store-redis.d.ts.map +1 -0
  422. package/dist/request/request-store-redis.js +58 -0
  423. package/dist/request/request-store-redis.js.map +1 -0
  424. package/dist/request/request-store.d.ts +27 -0
  425. package/dist/request/request-store.d.ts.map +1 -0
  426. package/dist/request/request-store.js +37 -0
  427. package/dist/request/request-store.js.map +1 -0
  428. package/dist/request/request-uri.d.ts +8 -0
  429. package/dist/request/request-uri.d.ts.map +1 -0
  430. package/dist/request/request-uri.js +24 -0
  431. package/dist/request/request-uri.js.map +1 -0
  432. package/dist/request/types.d.ts +328 -0
  433. package/dist/request/types.d.ts.map +1 -0
  434. package/dist/request/types.js +27 -0
  435. package/dist/request/types.js.map +1 -0
  436. package/dist/signer/signed-token-payload.d.ts +1694 -0
  437. package/dist/signer/signed-token-payload.d.ts.map +1 -0
  438. package/dist/signer/signed-token-payload.js +32 -0
  439. package/dist/signer/signed-token-payload.js.map +1 -0
  440. package/dist/signer/signer.d.ts +193 -0
  441. package/dist/signer/signer.d.ts.map +1 -0
  442. package/dist/signer/signer.js +101 -0
  443. package/dist/signer/signer.js.map +1 -0
  444. package/dist/token/refresh-token.d.ts +7 -0
  445. package/dist/token/refresh-token.d.ts.map +1 -0
  446. package/dist/token/refresh-token.js +20 -0
  447. package/dist/token/refresh-token.js.map +1 -0
  448. package/dist/token/token-claims.d.ts +1687 -0
  449. package/dist/token/token-claims.d.ts.map +1 -0
  450. package/dist/token/token-claims.js +30 -0
  451. package/dist/token/token-claims.js.map +1 -0
  452. package/dist/token/token-data.d.ts +20 -0
  453. package/dist/token/token-data.d.ts.map +1 -0
  454. package/dist/token/token-data.js +3 -0
  455. package/dist/token/token-data.js.map +1 -0
  456. package/dist/token/token-id.d.ts +7 -0
  457. package/dist/token/token-id.d.ts.map +1 -0
  458. package/dist/token/token-id.js +20 -0
  459. package/dist/token/token-id.js.map +1 -0
  460. package/dist/token/token-manager.d.ts +48 -0
  461. package/dist/token/token-manager.d.ts.map +1 -0
  462. package/dist/token/token-manager.js +421 -0
  463. package/dist/token/token-manager.js.map +1 -0
  464. package/dist/token/token-store.d.ts +35 -0
  465. package/dist/token/token-store.d.ts.map +1 -0
  466. package/dist/token/token-store.js +38 -0
  467. package/dist/token/token-store.js.map +1 -0
  468. package/dist/token/types.d.ts +250 -0
  469. package/dist/token/types.d.ts.map +1 -0
  470. package/dist/token/types.js +36 -0
  471. package/dist/token/types.js.map +1 -0
  472. package/dist/token/verify-token-claims.d.ts +17 -0
  473. package/dist/token/verify-token-claims.d.ts.map +1 -0
  474. package/dist/token/verify-token-claims.js +39 -0
  475. package/dist/token/verify-token-claims.js.map +1 -0
  476. package/package.json +83 -0
  477. package/rollup.config.js +55 -0
  478. package/src/access-token/access-token-type.ts +5 -0
  479. package/src/account/account-manager.ts +55 -0
  480. package/src/account/account-store.ts +74 -0
  481. package/src/account/account.ts +10 -0
  482. package/src/assets/app/app.tsx +28 -0
  483. package/src/assets/app/backend-data.ts +65 -0
  484. package/src/assets/app/components/accept-form.tsx +112 -0
  485. package/src/assets/app/components/account-identifier.tsx +18 -0
  486. package/src/assets/app/components/account-picker.tsx +108 -0
  487. package/src/assets/app/components/client-identifier.tsx +32 -0
  488. package/src/assets/app/components/client-name.tsx +30 -0
  489. package/src/assets/app/components/error-card.tsx +41 -0
  490. package/src/assets/app/components/help-card.tsx +42 -0
  491. package/src/assets/app/components/layout-title-page.tsx +43 -0
  492. package/src/assets/app/components/layout-welcome.tsx +58 -0
  493. package/src/assets/app/components/sign-in-form.tsx +290 -0
  494. package/src/assets/app/components/sign-up-account-form.tsx +210 -0
  495. package/src/assets/app/components/sign-up-disclaimer.tsx +44 -0
  496. package/src/assets/app/components/url-viewer.tsx +70 -0
  497. package/src/assets/app/cookies.ts +11 -0
  498. package/src/assets/app/hooks/use-api.ts +104 -0
  499. package/src/assets/app/hooks/use-bound-dispatch.ts +5 -0
  500. package/src/assets/app/hooks/use-csrf-token.ts +5 -0
  501. package/src/assets/app/lib/api.ts +64 -0
  502. package/src/assets/app/lib/clsx.ts +4 -0
  503. package/src/assets/app/lib/util.ts +10 -0
  504. package/src/assets/app/main.css +11 -0
  505. package/src/assets/app/main.tsx +28 -0
  506. package/src/assets/app/views/accept-view.tsx +51 -0
  507. package/src/assets/app/views/authorize-view.tsx +101 -0
  508. package/src/assets/app/views/error-view.tsx +27 -0
  509. package/src/assets/app/views/sign-in-view.tsx +121 -0
  510. package/src/assets/app/views/sign-up-view.tsx +93 -0
  511. package/src/assets/app/views/welcome-view.tsx +61 -0
  512. package/src/assets/asset.ts +8 -0
  513. package/src/assets/assets-middleware.ts +32 -0
  514. package/src/assets/index.ts +74 -0
  515. package/src/client/client-auth.ts +45 -0
  516. package/src/client/client-data.ts +9 -0
  517. package/src/client/client-id.ts +4 -0
  518. package/src/client/client-info.ts +13 -0
  519. package/src/client/client-manager.ts +818 -0
  520. package/src/client/client-store.ts +38 -0
  521. package/src/client/client-utils.ts +43 -0
  522. package/src/client/client.ts +231 -0
  523. package/src/constants.ts +69 -0
  524. package/src/device/device-data.ts +11 -0
  525. package/src/device/device-details.ts +43 -0
  526. package/src/device/device-id.ts +23 -0
  527. package/src/device/device-manager.ts +287 -0
  528. package/src/device/device-store.ts +35 -0
  529. package/src/device/session-id.ts +22 -0
  530. package/src/dpop/dpop-manager.ts +147 -0
  531. package/src/dpop/dpop-nonce.ts +104 -0
  532. package/src/errors/access-denied-error.ts +26 -0
  533. package/src/errors/account-selection-required-error.ts +12 -0
  534. package/src/errors/consent-required-error.ts +12 -0
  535. package/src/errors/invalid-authorization-details-error.ts +22 -0
  536. package/src/errors/invalid-client-error.ts +20 -0
  537. package/src/errors/invalid-client-id-error.ts +20 -0
  538. package/src/errors/invalid-client-metadata-error.ts +19 -0
  539. package/src/errors/invalid-dpop-key-binding-error.ts +21 -0
  540. package/src/errors/invalid-dpop-proof-error.ts +13 -0
  541. package/src/errors/invalid-grant-error.ts +16 -0
  542. package/src/errors/invalid-parameters-error.ts +12 -0
  543. package/src/errors/invalid-redirect-uri-error.ts +17 -0
  544. package/src/errors/invalid-request-error.ts +30 -0
  545. package/src/errors/invalid-token-error.ts +59 -0
  546. package/src/errors/login-required-error.ts +12 -0
  547. package/src/errors/oauth-error.ts +28 -0
  548. package/src/errors/unauthorized-client-error.ts +20 -0
  549. package/src/errors/use-dpop-nonce-error.ts +32 -0
  550. package/src/errors/www-authenticate-error.ts +65 -0
  551. package/src/index.ts +15 -0
  552. package/src/lib/html/README.md +9 -0
  553. package/src/lib/html/build-document.ts +98 -0
  554. package/src/lib/html/escapers.ts +66 -0
  555. package/src/lib/html/html.ts +61 -0
  556. package/src/lib/html/index.ts +5 -0
  557. package/src/lib/html/tags.ts +58 -0
  558. package/src/lib/html/util.ts +21 -0
  559. package/src/lib/http/README.md +11 -0
  560. package/src/lib/http/accept.ts +91 -0
  561. package/src/lib/http/context.ts +11 -0
  562. package/src/lib/http/index.ts +9 -0
  563. package/src/lib/http/method.ts +18 -0
  564. package/src/lib/http/middleware.ts +183 -0
  565. package/src/lib/http/parser.ts +64 -0
  566. package/src/lib/http/path.ts +82 -0
  567. package/src/lib/http/request.ts +141 -0
  568. package/src/lib/http/response.ts +133 -0
  569. package/src/lib/http/route.ts +56 -0
  570. package/src/lib/http/router.ts +118 -0
  571. package/src/lib/http/stream.ts +78 -0
  572. package/src/lib/http/types.ts +22 -0
  573. package/src/lib/http/url.ts +23 -0
  574. package/src/lib/redis.ts +23 -0
  575. package/src/lib/util/authorization-header.ts +26 -0
  576. package/src/lib/util/cast.ts +4 -0
  577. package/src/lib/util/crypto.ts +27 -0
  578. package/src/lib/util/date.ts +7 -0
  579. package/src/lib/util/hostname.ts +19 -0
  580. package/src/lib/util/redirect-uri.ts +46 -0
  581. package/src/lib/util/time.ts +33 -0
  582. package/src/lib/util/type.ts +4 -0
  583. package/src/lib/util/well-known.ts +8 -0
  584. package/src/metadata/build-metadata.ts +165 -0
  585. package/src/oauth-client.ts +3 -0
  586. package/src/oauth-dpop.ts +2 -0
  587. package/src/oauth-errors.ts +21 -0
  588. package/src/oauth-hooks.ts +66 -0
  589. package/src/oauth-provider.ts +1409 -0
  590. package/src/oauth-store.ts +11 -0
  591. package/src/oauth-verifier.ts +219 -0
  592. package/src/oidc/claims.ts +35 -0
  593. package/src/oidc/sub.ts +4 -0
  594. package/src/oidc/userinfo.ts +11 -0
  595. package/src/output/build-error-payload.ts +143 -0
  596. package/src/output/customization.ts +96 -0
  597. package/src/output/send-authorize-page.ts +111 -0
  598. package/src/output/send-authorize-redirect.ts +130 -0
  599. package/src/output/send-error-page.ts +41 -0
  600. package/src/output/send-web-page.ts +66 -0
  601. package/src/parameters/claims-requested.ts +106 -0
  602. package/src/parameters/oidc-payload.ts +28 -0
  603. package/src/replay/replay-manager.ts +38 -0
  604. package/src/replay/replay-store-memory.ts +36 -0
  605. package/src/replay/replay-store-redis.ts +31 -0
  606. package/src/replay/replay-store.ts +44 -0
  607. package/src/request/code.ts +24 -0
  608. package/src/request/request-data.ts +26 -0
  609. package/src/request/request-id.ts +23 -0
  610. package/src/request/request-info.ts +12 -0
  611. package/src/request/request-manager.ts +479 -0
  612. package/src/request/request-store-memory.ts +39 -0
  613. package/src/request/request-store-redis.ts +71 -0
  614. package/src/request/request-store.ts +54 -0
  615. package/src/request/request-uri.ts +29 -0
  616. package/src/request/types.ts +48 -0
  617. package/src/signer/signed-token-payload.ts +35 -0
  618. package/src/signer/signer.ts +165 -0
  619. package/src/token/refresh-token.ts +31 -0
  620. package/src/token/token-claims.ts +31 -0
  621. package/src/token/token-data.ts +33 -0
  622. package/src/token/token-id.ts +26 -0
  623. package/src/token/token-manager.ts +591 -0
  624. package/src/token/token-store.ts +78 -0
  625. package/src/token/types.ts +86 -0
  626. package/src/token/verify-token-claims.ts +65 -0
  627. package/tailwind.config.js +13 -0
  628. package/tsconfig.backend.json +9 -0
  629. package/tsconfig.frontend.json +11 -0
  630. package/tsconfig.json +8 -0
  631. package/tsconfig.tools.json +8 -0
@@ -0,0 +1,479 @@
1
+ import {
2
+ CLIENT_ASSERTION_TYPE_JWT_BEARER,
3
+ OAuthAuthenticationRequestParameters,
4
+ OAuthAuthorizationServerMetadata,
5
+ } from '@atproto/oauth-types'
6
+
7
+ import { DeviceAccountInfo } from '../account/account-store.js'
8
+ import { Account } from '../account/account.js'
9
+ import { ClientAuth } from '../client/client-auth.js'
10
+ import { ClientId } from '../client/client-id.js'
11
+ import { Client } from '../client/client.js'
12
+ import {
13
+ AUTHORIZATION_INACTIVITY_TIMEOUT,
14
+ PAR_EXPIRES_IN,
15
+ TOKEN_MAX_AGE,
16
+ } from '../constants.js'
17
+ import { DeviceId } from '../device/device-id.js'
18
+ import { AccessDeniedError } from '../errors/access-denied-error.js'
19
+ import { ConsentRequiredError } from '../errors/consent-required-error.js'
20
+ import { InvalidGrantError } from '../errors/invalid-grant-error.js'
21
+ import { InvalidParametersError } from '../errors/invalid-parameters-error.js'
22
+ import { InvalidRequestError } from '../errors/invalid-request-error.js'
23
+ import { compareRedirectUri } from '../lib/util/redirect-uri.js'
24
+ import { OAuthHooks } from '../oauth-hooks.js'
25
+ import { OIDC_SCOPE_CLAIMS } from '../oidc/claims.js'
26
+ import { Signer } from '../signer/signer.js'
27
+ import { Code, generateCode } from './code.js'
28
+ import {
29
+ isRequestDataAuthorized,
30
+ RequestDataAuthorized,
31
+ } from './request-data.js'
32
+ import { generateRequestId } from './request-id.js'
33
+ import { RequestInfo } from './request-info.js'
34
+ import { RequestStore, UpdateRequestData } from './request-store.js'
35
+ import {
36
+ decodeRequestUri,
37
+ encodeRequestUri,
38
+ RequestUri,
39
+ } from './request-uri.js'
40
+
41
+ export class RequestManager {
42
+ constructor(
43
+ protected readonly store: RequestStore,
44
+ protected readonly signer: Signer,
45
+ protected readonly metadata: OAuthAuthorizationServerMetadata,
46
+ protected readonly hooks: OAuthHooks,
47
+ protected readonly pkceRequired = true,
48
+ protected readonly tokenMaxAge = TOKEN_MAX_AGE,
49
+ ) {}
50
+
51
+ protected createTokenExpiry() {
52
+ return new Date(Date.now() + this.tokenMaxAge)
53
+ }
54
+
55
+ async createAuthorizationRequest(
56
+ client: Client,
57
+ clientAuth: ClientAuth,
58
+ input: Readonly<OAuthAuthenticationRequestParameters>,
59
+ deviceId: null | DeviceId,
60
+ dpopJkt: null | string,
61
+ ): Promise<RequestInfo> {
62
+ const parameters = await this.validate(client, clientAuth, input, dpopJkt)
63
+ return this.create(client, clientAuth, parameters, deviceId)
64
+ }
65
+
66
+ protected async create(
67
+ client: Client,
68
+ clientAuth: ClientAuth,
69
+ parameters: Readonly<OAuthAuthenticationRequestParameters>,
70
+ deviceId: null | DeviceId = null,
71
+ ): Promise<RequestInfo> {
72
+ const expiresAt = new Date(Date.now() + PAR_EXPIRES_IN)
73
+ const id = await generateRequestId()
74
+
75
+ await this.store.createRequest(id, {
76
+ clientId: client.id,
77
+ clientAuth,
78
+ parameters,
79
+ expiresAt,
80
+ deviceId,
81
+ sub: null,
82
+ code: null,
83
+ })
84
+
85
+ const uri = encodeRequestUri(id)
86
+ return { id, uri, expiresAt, parameters, clientAuth }
87
+ }
88
+
89
+ async validate(
90
+ client: Client,
91
+ clientAuth: ClientAuth,
92
+ parameters: Readonly<OAuthAuthenticationRequestParameters>,
93
+ dpopJkt: null | string,
94
+ pkceRequired = this.pkceRequired,
95
+ ): Promise<Readonly<OAuthAuthenticationRequestParameters>> {
96
+ // https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-10#section-1.4.1
97
+ // > The authorization server MAY fully or partially ignore the scope
98
+ // > requested by the client, based on the authorization server policy or
99
+ // > the resource owner's instructions. If the issued access token scope is
100
+ // > different from the one requested by the client, the authorization
101
+ // > server MUST include the scope response parameter in the token response
102
+ // > (Section 3.2.3) to inform the client of the actual scope granted.
103
+
104
+ const cScopes = client.metadata.scope?.split(' ')
105
+ const sScopes = this.metadata.scopes_supported
106
+
107
+ const scopes =
108
+ (parameters.scope || client.metadata.scope)
109
+ ?.split(' ')
110
+ .filter((scope) => !!scope && (sScopes?.includes(scope) ?? true)) ?? []
111
+
112
+ for (const scope of scopes) {
113
+ if (!cScopes?.includes(scope)) {
114
+ throw new InvalidParametersError(
115
+ parameters,
116
+ `Scope "${scope}" is not registered for this client`,
117
+ )
118
+ }
119
+ }
120
+
121
+ for (const [scope, claims] of Object.entries(OIDC_SCOPE_CLAIMS)) {
122
+ for (const claim of claims) {
123
+ if (
124
+ parameters?.claims?.id_token?.[claim]?.essential === true ||
125
+ parameters?.claims?.userinfo?.[claim]?.essential === true
126
+ ) {
127
+ if (!scopes?.includes(scope)) {
128
+ throw new InvalidParametersError(
129
+ parameters,
130
+ `Essential ${claim} claim requires "${scope}" scope`,
131
+ )
132
+ }
133
+ }
134
+ }
135
+ }
136
+
137
+ parameters = { ...parameters, scope: scopes.join(' ') }
138
+
139
+ const responseTypes = parameters.response_type.split(' ')
140
+
141
+ if (parameters.authorization_details) {
142
+ const clientAuthDetailsTypes = client.metadata.authorization_details_types
143
+ if (!clientAuthDetailsTypes) {
144
+ throw new InvalidParametersError(
145
+ parameters,
146
+ 'Client Metadata does not declare any "authorization_details"',
147
+ )
148
+ }
149
+
150
+ for (const detail of parameters.authorization_details) {
151
+ if (!clientAuthDetailsTypes?.includes(detail.type)) {
152
+ throw new InvalidParametersError(
153
+ parameters,
154
+ `Unsupported "authorization_details" type "${detail.type}"`,
155
+ )
156
+ }
157
+ }
158
+ }
159
+
160
+ const { redirect_uri } = parameters
161
+ if (
162
+ redirect_uri &&
163
+ !client.metadata.redirect_uris.some((uri) =>
164
+ compareRedirectUri(uri, redirect_uri),
165
+ )
166
+ ) {
167
+ throw new InvalidParametersError(
168
+ parameters,
169
+ `Invalid redirect_uri ${redirect_uri} (allowed: ${client.metadata.redirect_uris.join(' ')})`,
170
+ )
171
+ }
172
+
173
+ // https://datatracker.ietf.org/doc/html/rfc9449#section-10
174
+ if (!parameters.dpop_jkt) {
175
+ if (dpopJkt) parameters = { ...parameters, dpop_jkt: dpopJkt }
176
+ } else if (parameters.dpop_jkt !== dpopJkt) {
177
+ throw new InvalidParametersError(
178
+ parameters,
179
+ 'DPoP header and dpop_jkt do not match',
180
+ )
181
+ }
182
+
183
+ if (clientAuth.method === CLIENT_ASSERTION_TYPE_JWT_BEARER) {
184
+ if (parameters.dpop_jkt && clientAuth.jkt === parameters.dpop_jkt) {
185
+ throw new InvalidParametersError(
186
+ parameters,
187
+ 'The DPoP proof must be signed with a different key than the client assertion',
188
+ )
189
+ }
190
+ }
191
+
192
+ if (!client.metadata.response_types.includes(parameters.response_type)) {
193
+ throw new InvalidParametersError(
194
+ parameters,
195
+ `Unsupported response_type "${parameters.response_type}"`,
196
+ 'unsupported_response_type',
197
+ )
198
+ }
199
+
200
+ if (pkceRequired && responseTypes.includes('token')) {
201
+ throw new InvalidParametersError(
202
+ parameters,
203
+ `Response type "${parameters.response_type}" is incompatible with PKCE`,
204
+ 'unsupported_response_type',
205
+ )
206
+ }
207
+
208
+ // https://datatracker.ietf.org/doc/html/rfc7636#section-4.4.1
209
+ if (pkceRequired && !parameters.code_challenge) {
210
+ throw new InvalidParametersError(parameters, 'code_challenge is required')
211
+ }
212
+
213
+ if (
214
+ parameters.code_challenge &&
215
+ clientAuth.method === 'none' &&
216
+ (parameters.code_challenge_method ?? 'plain') === 'plain'
217
+ ) {
218
+ throw new InvalidParametersError(
219
+ parameters,
220
+ 'code_challenge_method=plain requires client authentication',
221
+ )
222
+ }
223
+
224
+ // https://datatracker.ietf.org/doc/html/rfc7636#section-4.3
225
+ if (parameters.code_challenge_method && !parameters.code_challenge) {
226
+ throw new InvalidParametersError(
227
+ parameters,
228
+ 'code_challenge_method requires code_challenge',
229
+ )
230
+ }
231
+
232
+ // https://openid.net/specs/openid-connect-core-1_0.html#HybridAuthRequest
233
+ //
234
+ // > nonce: REQUIRED if the Response Type of the request is "code id_token" or
235
+ // > "code id_token token" and OPTIONAL when the Response Type of the
236
+ // > request is "code token". It is a string value used to associate a
237
+ // > Client session with an ID Token, and to mitigate replay attacks. The
238
+ // > value is passed through unmodified from the Authentication Request to
239
+ // > the ID Token. Sufficient entropy MUST be present in the nonce values
240
+ // > used to prevent attackers from guessing values. For implementation
241
+ // > notes, see Section 15.5.2.
242
+ if (responseTypes.includes('id_token') && !parameters.nonce) {
243
+ throw new InvalidParametersError(
244
+ parameters,
245
+ 'nonce is required for implicit and hybrid flows',
246
+ )
247
+ }
248
+
249
+ // Make "expensive" checks after the "cheaper" checks
250
+
251
+ if (parameters.id_token_hint != null) {
252
+ const { payload } = await this.signer.verify(parameters.id_token_hint, {
253
+ // these are meant to be outdated when used as a hint
254
+ clockTolerance: Infinity,
255
+ })
256
+
257
+ if (!payload.sub) {
258
+ throw new InvalidParametersError(
259
+ parameters,
260
+ `Unexpected empty id_token_hint "sub"`,
261
+ )
262
+ } else if (parameters.login_hint == null) {
263
+ parameters = { ...parameters, login_hint: payload.sub }
264
+ } else if (parameters.login_hint !== payload.sub) {
265
+ throw new InvalidParametersError(
266
+ parameters,
267
+ 'login_hint does not match "sub" of id_token_hint',
268
+ )
269
+ }
270
+ }
271
+
272
+ // ATPROTO extension: if the client is not trusted, force users to consent
273
+ // to authorization requests. We do this to avoid unauthenticated clients
274
+ // from being able to silently re-authenticate users.
275
+ if (clientAuth.method === 'none' && !client.info.isFirstParty) {
276
+ if (parameters.prompt === 'none') {
277
+ throw new ConsentRequiredError(
278
+ parameters,
279
+ 'Public clients are not allowed to use silent-sign-on',
280
+ )
281
+ }
282
+
283
+ // force "consent" for unauthenticated, third party clients
284
+ parameters = { ...parameters, prompt: 'consent' }
285
+ }
286
+
287
+ return parameters
288
+ }
289
+
290
+ async get(
291
+ uri: RequestUri,
292
+ clientId: ClientId,
293
+ deviceId: DeviceId,
294
+ ): Promise<RequestInfo> {
295
+ const id = decodeRequestUri(uri)
296
+
297
+ const data = await this.store.readRequest(id)
298
+ if (!data) throw new InvalidRequestError(`Unknown request_uri "${uri}"`)
299
+
300
+ const updates: UpdateRequestData = {}
301
+
302
+ try {
303
+ if (data.sub || data.code) {
304
+ // If an account was linked to the request, the next step is to exchange
305
+ // the code for a token.
306
+ throw new AccessDeniedError(
307
+ data.parameters,
308
+ 'This request was already authorized',
309
+ )
310
+ }
311
+
312
+ if (data.expiresAt < new Date()) {
313
+ throw new AccessDeniedError(data.parameters, 'This request has expired')
314
+ } else {
315
+ updates.expiresAt = new Date(
316
+ Date.now() + AUTHORIZATION_INACTIVITY_TIMEOUT,
317
+ )
318
+ }
319
+
320
+ if (data.clientId !== clientId) {
321
+ throw new AccessDeniedError(
322
+ data.parameters,
323
+ 'This request was initiated for another client',
324
+ )
325
+ }
326
+
327
+ if (!data.deviceId) {
328
+ updates.deviceId = deviceId
329
+ } else if (data.deviceId !== deviceId) {
330
+ throw new AccessDeniedError(
331
+ data.parameters,
332
+ 'This request was initiated from another device',
333
+ )
334
+ }
335
+ } catch (err) {
336
+ await this.store.deleteRequest(id)
337
+ throw err
338
+ }
339
+
340
+ if (Object.keys(updates).length > 0) {
341
+ await this.store.updateRequest(id, updates)
342
+ }
343
+
344
+ return {
345
+ id,
346
+ uri,
347
+ expiresAt: updates.expiresAt || data.expiresAt,
348
+ parameters: data.parameters,
349
+ clientAuth: data.clientAuth,
350
+ }
351
+ }
352
+
353
+ async setAuthorized(
354
+ client: Client,
355
+ uri: RequestUri,
356
+ deviceId: DeviceId,
357
+ account: Account,
358
+ info: DeviceAccountInfo,
359
+ ): Promise<{ code?: Code; token?: string; id_token?: string }> {
360
+ const id = decodeRequestUri(uri)
361
+
362
+ const data = await this.store.readRequest(id)
363
+ if (!data) throw new InvalidRequestError(`Unknown request_uri "${uri}"`)
364
+
365
+ try {
366
+ if (data.expiresAt < new Date()) {
367
+ throw new AccessDeniedError(data.parameters, 'This request has expired')
368
+ }
369
+ if (!data.deviceId) {
370
+ throw new AccessDeniedError(
371
+ data.parameters,
372
+ 'This request was not initiated',
373
+ )
374
+ }
375
+ if (data.deviceId !== deviceId) {
376
+ throw new AccessDeniedError(
377
+ data.parameters,
378
+ 'This request was initiated from another device',
379
+ )
380
+ }
381
+ if (data.sub || data.code) {
382
+ throw new AccessDeniedError(
383
+ data.parameters,
384
+ 'This request was already authorized',
385
+ )
386
+ }
387
+
388
+ const responseType = data.parameters.response_type.split(' ')
389
+
390
+ if (responseType.includes('token')) {
391
+ throw new AccessDeniedError(
392
+ data.parameters,
393
+ 'Implicit "token" forbidden (use "code" with PKCE instead)',
394
+ )
395
+ }
396
+
397
+ const code = responseType.includes('code')
398
+ ? await generateCode()
399
+ : undefined
400
+
401
+ // Bind the request to the account, preventing it from being used again.
402
+ await this.store.updateRequest(id, {
403
+ sub: account.sub,
404
+ code,
405
+ // Allow the client to exchange the code for a token within the next 60 seconds.
406
+ expiresAt: new Date(Date.now() + AUTHORIZATION_INACTIVITY_TIMEOUT),
407
+ })
408
+
409
+ const id_token = responseType.includes('id_token')
410
+ ? await this.signer.idToken(client, data.parameters, account, {
411
+ auth_time: info.authenticatedAt,
412
+ exp: this.createTokenExpiry(),
413
+ code,
414
+ })
415
+ : undefined
416
+
417
+ return { code, id_token }
418
+ } catch (err) {
419
+ await this.store.deleteRequest(id)
420
+ throw err
421
+ }
422
+ }
423
+
424
+ /**
425
+ * @note If this method throws an error, any token previously generated from
426
+ * the same `code` **must** me revoked.
427
+ */
428
+ public async findCode(
429
+ client: Client,
430
+ clientAuth: ClientAuth,
431
+ code: Code,
432
+ ): Promise<RequestDataAuthorized> {
433
+ const result = await this.store.findRequestByCode(code)
434
+ if (!result) throw new InvalidGrantError('Invalid code')
435
+
436
+ try {
437
+ const { data } = result
438
+
439
+ if (!isRequestDataAuthorized(data)) {
440
+ // Should never happen: maybe the store implementation is faulty ?
441
+ throw new Error('Unexpected request state')
442
+ }
443
+
444
+ if (data.clientId !== client.id) {
445
+ throw new InvalidGrantError('This code was issued for another client')
446
+ }
447
+
448
+ if (data.expiresAt < new Date()) {
449
+ throw new InvalidGrantError('This code has expired')
450
+ }
451
+
452
+ if (data.clientAuth.method === 'none') {
453
+ // If the client did not use PAR, it was not authenticated when the
454
+ // request was created (see authorize() method above). Since PAR is not
455
+ // mandatory, and since the token exchange currently taking place *is*
456
+ // authenticated (`clientAuth`), we allow "upgrading" the authentication
457
+ // method (the token created will be bound to the current clientAuth).
458
+ } else {
459
+ if (clientAuth.method !== data.clientAuth.method) {
460
+ throw new InvalidGrantError('Invalid client authentication')
461
+ }
462
+
463
+ if (!(await client.validateClientAuth(data.clientAuth))) {
464
+ throw new InvalidGrantError('Invalid client authentication')
465
+ }
466
+ }
467
+
468
+ return data
469
+ } finally {
470
+ // A "code" can only be used once
471
+ await this.store.deleteRequest(result.id)
472
+ }
473
+ }
474
+
475
+ async delete(uri: RequestUri): Promise<void> {
476
+ const id = decodeRequestUri(uri)
477
+ await this.store.deleteRequest(id)
478
+ }
479
+ }
@@ -0,0 +1,39 @@
1
+ import { Code } from './code.js'
2
+ import { RequestId } from './request-id.js'
3
+ import { RequestData } from './request-data.js'
4
+ import { RequestStore } from './request-store.js'
5
+
6
+ export class RequestStoreMemory implements RequestStore {
7
+ #requests = new Map<RequestId, RequestData>()
8
+
9
+ async readRequest(id: RequestId): Promise<RequestData | null> {
10
+ return this.#requests.get(id) ?? null
11
+ }
12
+
13
+ async createRequest(id: RequestId, data: RequestData): Promise<void> {
14
+ this.#requests.set(id, data)
15
+ }
16
+
17
+ async updateRequest(
18
+ id: RequestId,
19
+ data: Partial<RequestData>,
20
+ ): Promise<void> {
21
+ const current = this.#requests.get(id)
22
+ if (!current) throw new Error('Request not found')
23
+ const newData = { ...current, ...data }
24
+ this.#requests.set(id, newData)
25
+ }
26
+
27
+ async deleteRequest(id: RequestId): Promise<void> {
28
+ this.#requests.delete(id)
29
+ }
30
+
31
+ async findRequestByCode(
32
+ code: Code,
33
+ ): Promise<{ id: RequestId; data: RequestData } | null> {
34
+ for (const [id, data] of this.#requests) {
35
+ if (data.code === code) return { id, data }
36
+ }
37
+ return null
38
+ }
39
+ }
@@ -0,0 +1,71 @@
1
+ import { Redis } from 'ioredis'
2
+ import { CreateRedisOptions, createRedis } from '../lib/redis.js'
3
+ import { Code } from './code.js'
4
+ import { RequestData } from './request-data.js'
5
+ import { RequestId, requestIdSchema } from './request-id.js'
6
+ import { RequestStore } from './request-store.js'
7
+
8
+ export type { Redis, CreateRedisOptions }
9
+
10
+ export type ReplayStoreRedisOptions = {
11
+ redis: CreateRedisOptions
12
+ }
13
+
14
+ export class RequestStoreRedis implements RequestStore {
15
+ private readonly redis: Redis
16
+
17
+ constructor(options: ReplayStoreRedisOptions) {
18
+ this.redis = createRedis(options.redis)
19
+ }
20
+
21
+ async readRequest(id: RequestId): Promise<RequestData | null> {
22
+ const data = await this.redis.get(id)
23
+ return data ? JSON.parse(data) : null
24
+ }
25
+
26
+ async createRequest(id: RequestId, data: RequestData): Promise<void> {
27
+ const timeFrame = data.expiresAt.getTime() - Date.now()
28
+ await this.redis.set(id, JSON.stringify(data), 'PX', timeFrame)
29
+ if (data.code) await this.redis.set(data.code, id, 'PX', timeFrame)
30
+ }
31
+
32
+ async updateRequest(
33
+ id: RequestId,
34
+ data: Partial<RequestData>,
35
+ ): Promise<void> {
36
+ const current = await this.readRequest(id)
37
+ if (!current) throw new Error('Request not found')
38
+ if (current.code) await this.redis.del(current.code)
39
+ const newData = { ...current, ...data }
40
+ await this.createRequest(id, newData)
41
+ }
42
+
43
+ async deleteRequest(id: RequestId): Promise<void> {
44
+ const data = await this.readRequest(id)
45
+ if (!data) return
46
+ if (data.code) await this.redis.del(data.code)
47
+ await this.redis.del(id)
48
+ }
49
+
50
+ private async findRequestIdByCode(code: Code): Promise<RequestId | null> {
51
+ const value = await this.redis.get(code)
52
+ if (!value) return null
53
+
54
+ const parsed = requestIdSchema.safeParse(value)
55
+ if (!parsed.success) return null
56
+
57
+ return parsed.data
58
+ }
59
+
60
+ async findRequestByCode(
61
+ code: Code,
62
+ ): Promise<{ id: RequestId; data: RequestData } | null> {
63
+ const id = await this.findRequestIdByCode(code)
64
+ if (!id) return null
65
+
66
+ const data = await this.readRequest(id)
67
+ if (!data) return null
68
+
69
+ return { id, data }
70
+ }
71
+ }
@@ -0,0 +1,54 @@
1
+ import { Awaitable } from '../lib/util/type.js'
2
+ import { Code } from './code.js'
3
+ import { RequestData } from './request-data.js'
4
+ import { RequestId } from './request-id.js'
5
+
6
+ // Export all types needed to implement the RequestStore interface
7
+ export * from './code.js'
8
+ export * from './request-id.js'
9
+ export * from './request-data.js'
10
+ export type { Awaitable }
11
+
12
+ export type UpdateRequestData = Pick<
13
+ Partial<RequestData>,
14
+ 'sub' | 'code' | 'deviceId' | 'expiresAt'
15
+ >
16
+
17
+ export type FoundRequestResult = {
18
+ id: RequestId
19
+ data: RequestData
20
+ }
21
+
22
+ export interface RequestStore {
23
+ createRequest(id: RequestId, data: RequestData): Awaitable<void>
24
+ /**
25
+ * Note that expired requests **can** be returned to yield a different error
26
+ * message than if the request was not found.
27
+ */
28
+ readRequest(id: RequestId): Awaitable<RequestData | null>
29
+ updateRequest(id: RequestId, data: UpdateRequestData): Awaitable<void>
30
+ deleteRequest(id: RequestId): void | Awaitable<void>
31
+ findRequestByCode(code: Code): Awaitable<FoundRequestResult | null>
32
+ }
33
+
34
+ export function isRequestStore(
35
+ implementation: Record<string, unknown> & Partial<RequestStore>,
36
+ ): implementation is Record<string, unknown> & RequestStore {
37
+ return (
38
+ typeof implementation.createRequest === 'function' &&
39
+ typeof implementation.readRequest === 'function' &&
40
+ typeof implementation.updateRequest === 'function' &&
41
+ typeof implementation.deleteRequest === 'function' &&
42
+ typeof implementation.findRequestByCode === 'function'
43
+ )
44
+ }
45
+
46
+ export function ifRequestStore(
47
+ implementation?: Record<string, unknown> & Partial<RequestStore>,
48
+ ): RequestStore | undefined {
49
+ if (implementation && isRequestStore(implementation)) {
50
+ return implementation
51
+ }
52
+
53
+ return undefined
54
+ }
@@ -0,0 +1,29 @@
1
+ import { z } from 'zod'
2
+
3
+ import { RequestId, requestIdSchema } from './request-id.js'
4
+
5
+ export const REQUEST_URI_PREFIX = 'urn:ietf:params:oauth:request_uri:'
6
+
7
+ export const requestUriSchema = z
8
+ .string()
9
+ .url()
10
+ .refinement(
11
+ (data): data is `${typeof REQUEST_URI_PREFIX}${RequestId}` =>
12
+ data.startsWith(REQUEST_URI_PREFIX) &&
13
+ requestIdSchema.safeParse(decodeRequestUri(data as any)).success,
14
+ {
15
+ code: z.ZodIssueCode.custom,
16
+ message: 'Invalid request_uri format',
17
+ },
18
+ )
19
+
20
+ export type RequestUri = z.infer<typeof requestUriSchema>
21
+
22
+ export function encodeRequestUri(requestId: RequestId): RequestUri {
23
+ return `${REQUEST_URI_PREFIX}${encodeURIComponent(requestId) as RequestId}`
24
+ }
25
+
26
+ export function decodeRequestUri(requestUri: RequestUri): RequestId {
27
+ const requestIdEnc = requestUri.slice(REQUEST_URI_PREFIX.length)
28
+ return decodeURIComponent(requestIdEnc) as RequestId
29
+ }