@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,818 @@
1
+ import {
2
+ bindFetch,
3
+ Fetch,
4
+ fetchJsonProcessor,
5
+ fetchJsonZodProcessor,
6
+ fetchOkProcessor,
7
+ } from '@atproto-labs/fetch'
8
+ import { pipe } from '@atproto-labs/pipe'
9
+ import {
10
+ CachedGetter,
11
+ GetCachedOptions,
12
+ SimpleStore,
13
+ } from '@atproto-labs/simple-store'
14
+ import { Jwks, jwksSchema, Keyset } from '@atproto/jwk'
15
+ import {
16
+ isLoopbackHost,
17
+ isLoopbackUrl,
18
+ isOAuthClientIdDiscoverable,
19
+ isOAuthClientIdLoopback,
20
+ OAUTH_AUTHENTICATED_ENDPOINT_NAMES,
21
+ OAuthClientIdDiscoverable,
22
+ OAuthClientIdLoopback,
23
+ OAuthClientMetadata,
24
+ OAuthClientMetadataInput,
25
+ oauthClientMetadataSchema,
26
+ } from '@atproto/oauth-types'
27
+
28
+ import { ALLOW_LOOPBACK_CLIENT_REFRESH_TOKEN } from '../constants.js'
29
+ import { InvalidClientMetadataError } from '../errors/invalid-client-metadata-error.js'
30
+ import { InvalidRedirectUriError } from '../errors/invalid-redirect-uri-error.js'
31
+ import { OAuthError } from '../errors/oauth-error.js'
32
+ import { parseDomain, parseUrlDomain } from '../lib/util/hostname.js'
33
+ import { Awaitable } from '../lib/util/type.js'
34
+ import { OAuthHooks } from '../oauth-hooks.js'
35
+ import { ClientId } from './client-id.js'
36
+ import { ClientStore } from './client-store.js'
37
+ import { parseDiscoverableClientId, parseRedirectUri } from './client-utils.js'
38
+ import { Client } from './client.js'
39
+
40
+ const fetchMetadataHandler = pipe(
41
+ fetchOkProcessor(),
42
+ fetchJsonProcessor('application/json', false),
43
+ fetchJsonZodProcessor(oauthClientMetadataSchema),
44
+ )
45
+
46
+ const fetchJwksHandler = pipe(
47
+ fetchOkProcessor(),
48
+ fetchJsonProcessor('application/json', false),
49
+ fetchJsonZodProcessor(jwksSchema),
50
+ )
51
+
52
+ export type LoopbackMetadataGetter = (
53
+ url: string,
54
+ ) => Awaitable<OAuthClientMetadataInput>
55
+
56
+ export class ClientManager {
57
+ protected readonly jwks: CachedGetter<string, Jwks>
58
+ protected readonly metadata: CachedGetter<string, OAuthClientMetadata>
59
+
60
+ constructor(
61
+ protected readonly keyset: Keyset,
62
+ protected readonly hooks: OAuthHooks,
63
+ protected readonly store: ClientStore | null,
64
+ protected readonly loopbackMetadata: LoopbackMetadataGetter | null = null,
65
+ safeFetch: Fetch,
66
+ clientJwksCache: SimpleStore<string, Jwks>,
67
+ clientMetadataCache: SimpleStore<string, OAuthClientMetadata>,
68
+ ) {
69
+ const fetch = bindFetch(safeFetch)
70
+
71
+ this.jwks = new CachedGetter(async (uri, options) => {
72
+ const jwks = await fetch(buildJsonGetRequest(uri, options)).then(
73
+ fetchJwksHandler,
74
+ )
75
+
76
+ return jwks
77
+ }, clientJwksCache)
78
+
79
+ this.metadata = new CachedGetter(async (uri, options) => {
80
+ const metadata = await fetch(buildJsonGetRequest(uri, options)).then(
81
+ fetchMetadataHandler,
82
+ )
83
+
84
+ // Validate within the getter to avoid caching invalid metadata
85
+ return this.validateClientMetadata(uri, metadata)
86
+ }, clientMetadataCache)
87
+ }
88
+
89
+ /**
90
+ *
91
+ * @see {@link https://openid.net/specs/openid-connect-registration-1_0.html#rfc.section.2 OIDC Client Registration}
92
+ */
93
+ public async getClient(clientId: string) {
94
+ try {
95
+ const metadata = await this.getClientMetadata(clientId)
96
+
97
+ const jwks = metadata.jwks_uri
98
+ ? await this.jwks.get(metadata.jwks_uri)
99
+ : undefined
100
+
101
+ const partialInfo = await this.hooks.onClientInfo?.(clientId, {
102
+ metadata,
103
+ jwks,
104
+ })
105
+
106
+ const isFirstParty = partialInfo?.isFirstParty ?? false
107
+ const isTrusted =
108
+ partialInfo?.isTrusted ??
109
+ (isFirstParty ||
110
+ // If the client was loaded from the store, we consider it trusted:
111
+ (!isOAuthClientIdLoopback(clientId) &&
112
+ !isOAuthClientIdDiscoverable(clientId)))
113
+
114
+ return new Client(clientId, metadata, jwks, { isFirstParty, isTrusted })
115
+ } catch (err) {
116
+ if (err instanceof OAuthError) throw err
117
+ if (err?.['code'] === 'DEPTH_ZERO_SELF_SIGNED_CERT') {
118
+ throw new InvalidClientMetadataError('Self-signed certificate', err)
119
+ }
120
+ throw InvalidClientMetadataError.from(err)
121
+ }
122
+ }
123
+
124
+ protected async getClientMetadata(
125
+ clientId: ClientId,
126
+ ): Promise<OAuthClientMetadata> {
127
+ if (isOAuthClientIdLoopback(clientId)) {
128
+ return this.getLoopbackClientMetadata(clientId)
129
+ } else if (isOAuthClientIdDiscoverable(clientId)) {
130
+ return this.getDiscoverableClientMetadata(clientId)
131
+ } else if (this.store) {
132
+ return this.getStoredClientMetadata(clientId)
133
+ }
134
+
135
+ throw new InvalidClientMetadataError(`Invalid client ID "${clientId}"`)
136
+ }
137
+
138
+ protected async getLoopbackClientMetadata(
139
+ clientId: OAuthClientIdLoopback,
140
+ ): Promise<OAuthClientMetadata> {
141
+ const { loopbackMetadata } = this
142
+ if (!loopbackMetadata) {
143
+ throw new InvalidClientMetadataError('Loopback clients are not allowed')
144
+ }
145
+
146
+ const result = oauthClientMetadataSchema.safeParse(
147
+ await loopbackMetadata(clientId),
148
+ )
149
+
150
+ if (!result.success) {
151
+ throw InvalidClientMetadataError.from(result.error)
152
+ }
153
+
154
+ return this.validateClientMetadata(clientId, result.data)
155
+ }
156
+
157
+ protected async getDiscoverableClientMetadata(
158
+ clientId: OAuthClientIdDiscoverable,
159
+ ): Promise<OAuthClientMetadata> {
160
+ const metadataUrl = parseDiscoverableClientId(clientId)
161
+
162
+ const metadata = await this.metadata.get(metadataUrl.href)
163
+
164
+ // Note: we do *not* re-validate the metadata here, as the metadata is
165
+ // validated within the getter. This is to avoid double validation.
166
+ //
167
+ // return this.validateClientMetadata(metadataUrl.href, metadata)
168
+ return metadata
169
+ }
170
+
171
+ protected async getStoredClientMetadata(
172
+ clientId: ClientId,
173
+ ): Promise<OAuthClientMetadata> {
174
+ if (this.store) {
175
+ const metadata = await this.store.findClient(clientId)
176
+ return this.validateClientMetadata(clientId, metadata)
177
+ }
178
+
179
+ throw new InvalidClientMetadataError(`Invalid client ID "${clientId}"`)
180
+ }
181
+
182
+ /**
183
+ * This method will ensure that the client metadata is valid w.r.t. the OAuth
184
+ * and OIDC specifications. It will also ensure that the metadata is
185
+ * compatible with the implementation of this library, and ATPROTO's
186
+ * requirements.
187
+ */
188
+ protected validateClientMetadata(
189
+ clientId: ClientId,
190
+ metadata: OAuthClientMetadata,
191
+ ): OAuthClientMetadata {
192
+ if (metadata.jwks && metadata.jwks_uri) {
193
+ throw new InvalidClientMetadataError(
194
+ 'jwks_uri and jwks are mutually exclusive',
195
+ )
196
+ }
197
+
198
+ const clientUriUrl = metadata.client_uri
199
+ ? new URL(metadata.client_uri)
200
+ : null
201
+ const clientUriParsed = clientUriUrl ? parseUrlDomain(clientUriUrl) : null
202
+
203
+ if (clientUriUrl && !clientUriParsed) {
204
+ throw new InvalidClientMetadataError('client_uri must be a valid URL')
205
+ }
206
+
207
+ const scopes = metadata.scope?.split(' ')
208
+ if (
209
+ metadata.grant_types.includes('refresh_token') !==
210
+ (scopes?.includes('offline_access') ?? false)
211
+ ) {
212
+ throw new InvalidClientMetadataError(
213
+ 'Grant type "refresh_token" requires scope "offline_access" (and vice versa)',
214
+ )
215
+ }
216
+
217
+ for (const grantType of metadata.grant_types) {
218
+ switch (grantType) {
219
+ case 'authorization_code':
220
+ case 'refresh_token':
221
+ case 'implicit': // Required by OIDC (for id_token)
222
+ continue
223
+ case 'password':
224
+ throw new InvalidClientMetadataError(
225
+ `Grant type "${grantType}" is not allowed`,
226
+ )
227
+ default:
228
+ throw new InvalidClientMetadataError(
229
+ `Grant type "${grantType}" is not supported`,
230
+ )
231
+ }
232
+ }
233
+
234
+ if (metadata.client_id && metadata.client_id !== clientId) {
235
+ throw new InvalidClientMetadataError('client_id does not match')
236
+ }
237
+
238
+ if (metadata.subject_type && metadata.subject_type !== 'public') {
239
+ throw new InvalidClientMetadataError(
240
+ 'Only "public" subject_type is supported',
241
+ )
242
+ }
243
+
244
+ if (
245
+ metadata.userinfo_signed_response_alg &&
246
+ !this.keyset.signAlgorithms.includes(
247
+ metadata.userinfo_signed_response_alg,
248
+ )
249
+ ) {
250
+ throw new InvalidClientMetadataError(
251
+ `Unsupported "userinfo_signed_response_alg" ${metadata.userinfo_signed_response_alg}`,
252
+ )
253
+ }
254
+
255
+ if (
256
+ metadata.id_token_signed_response_alg &&
257
+ !this.keyset.signAlgorithms.includes(
258
+ metadata.id_token_signed_response_alg,
259
+ )
260
+ ) {
261
+ throw new InvalidClientMetadataError(
262
+ `Unsupported "id_token_signed_response_alg" ${metadata.id_token_signed_response_alg}`,
263
+ )
264
+ }
265
+
266
+ if (metadata.userinfo_encrypted_response_alg) {
267
+ // We only support signature for now.
268
+ throw new InvalidClientMetadataError(
269
+ 'Encrypted userinfo response is not supported',
270
+ )
271
+ }
272
+
273
+ if (!metadata[`token_endpoint_auth_method`]) {
274
+ throw new InvalidClientMetadataError(
275
+ 'Missing token_endpoint_auth_method client metadata',
276
+ )
277
+ }
278
+
279
+ for (const endpoint of OAUTH_AUTHENTICATED_ENDPOINT_NAMES) {
280
+ const method =
281
+ metadata[`${endpoint}_endpoint_auth_method`] ||
282
+ metadata[`token_endpoint_auth_method`]
283
+
284
+ switch (method) {
285
+ case 'none':
286
+ if (metadata.token_endpoint_auth_signing_alg) {
287
+ throw new InvalidClientMetadataError(
288
+ `${endpoint}_endpoint_auth_method "none" must not have ${endpoint}_endpoint_auth_signing_alg`,
289
+ )
290
+ }
291
+ break
292
+
293
+ case 'private_key_jwt':
294
+ if (!metadata.jwks && !metadata.jwks_uri) {
295
+ throw new InvalidClientMetadataError(
296
+ `private_key_jwt auth method requires jwks or jwks_uri`,
297
+ )
298
+ }
299
+ if (metadata.jwks?.keys.length === 0) {
300
+ throw new InvalidClientMetadataError(
301
+ `private_key_jwt auth method requires at least one key in jwks`,
302
+ )
303
+ }
304
+ if (!metadata.token_endpoint_auth_signing_alg) {
305
+ throw new InvalidClientMetadataError(
306
+ `Missing token_endpoint_auth_signing_alg client metadata`,
307
+ )
308
+ }
309
+ break
310
+
311
+ default:
312
+ throw new InvalidClientMetadataError(
313
+ `${method} is not a supported "${endpoint}_endpoint_auth_method". Use "private_key_jwt" or "none".`,
314
+ )
315
+ }
316
+ }
317
+
318
+ if (metadata.authorization_encrypted_response_enc) {
319
+ throw new InvalidClientMetadataError(
320
+ 'Encrypted authorization response is not supported',
321
+ )
322
+ }
323
+
324
+ if (metadata.tls_client_certificate_bound_access_tokens) {
325
+ throw new InvalidClientMetadataError(
326
+ 'Mutual-TLS bound access tokens are not supported',
327
+ )
328
+ }
329
+
330
+ if (
331
+ metadata.authorization_encrypted_response_enc &&
332
+ !metadata.authorization_encrypted_response_alg
333
+ ) {
334
+ throw new InvalidClientMetadataError(
335
+ 'authorization_encrypted_response_enc requires authorization_encrypted_response_alg',
336
+ )
337
+ }
338
+
339
+ // ATPROTO spec requires the use of DPoP (OAuth spec defaults to false)
340
+ if (metadata.dpop_bound_access_tokens !== true) {
341
+ throw new InvalidClientMetadataError(
342
+ '"dpop_bound_access_tokens" must be true',
343
+ )
344
+ }
345
+
346
+ for (const responseType of metadata.response_types) {
347
+ const rt = responseType.split(' ')
348
+
349
+ // ATPROTO spec requires the use of PKCE
350
+ if (rt.includes('token')) {
351
+ throw new InvalidClientMetadataError(
352
+ '"token" response type is not compatible with PKCE (use "code" instead)',
353
+ )
354
+ }
355
+
356
+ // Consistency check
357
+ if (
358
+ rt.includes('code') &&
359
+ !metadata.grant_types.includes('authorization_code')
360
+ ) {
361
+ throw new InvalidClientMetadataError(
362
+ `Response type "${responseType}" requires the "authorization_code" grant type`,
363
+ )
364
+ }
365
+
366
+ // Asking for "code token" or "code id_token" is fine (as long as the
367
+ // grant_types includes "authorization_code" and the scope includes
368
+ // "openid"). Asking for "token" or "id_token" (without "code") requires
369
+ // the "implicit" grant type.
370
+ if (
371
+ (rt.includes('token') || rt.includes('id_token')) &&
372
+ !metadata.grant_types.includes('implicit')
373
+ ) {
374
+ throw new InvalidClientMetadataError(
375
+ `Response type "${responseType}" requires the "implicit" grant type`,
376
+ )
377
+ }
378
+ }
379
+
380
+ if (metadata.application_type === 'native') {
381
+ // https://datatracker.ietf.org/doc/html/rfc8252#section-8.4
382
+ //
383
+ // > Except when using a mechanism like Dynamic Client Registration
384
+ // > [RFC7591] to provision per-instance secrets, native apps are
385
+ // > classified as public clients, as defined by Section 2.1 of OAuth 2.0
386
+ // > [RFC6749]; they MUST be registered with the authorization server as
387
+ // > such. Authorization servers MUST record the client type in the
388
+ // > client registration details in order to identify and process requests
389
+ // > accordingly.
390
+ }
391
+
392
+ if (!metadata.redirect_uris?.length) {
393
+ // https://openid.net/specs/openid-connect-registration-1_0.html#rfc.section.2
394
+ //
395
+ // > OPs can require that request_uri values used be pre-registered with
396
+ // > the require_request_uri_registration discovery parameter.
397
+
398
+ throw new InvalidClientMetadataError(
399
+ 'At least one redirect_uri is required',
400
+ )
401
+ }
402
+
403
+ if (
404
+ metadata.application_type === 'web' &&
405
+ metadata.grant_types.includes('implicit')
406
+ ) {
407
+ // https://openid.net/specs/openid-connect-registration-1_0.html#rfc.section.2
408
+ //
409
+ // > Web Clients [as defined by "application_type"] using the OAuth
410
+ // > Implicit Grant Type MUST only register URLs using the https
411
+ // > scheme as redirect_uris; they MUST NOT use localhost as the
412
+ // > hostname.
413
+
414
+ for (const redirectUri of metadata.redirect_uris) {
415
+ const url = parseRedirectUri(redirectUri)
416
+ if (url.protocol !== 'https:') {
417
+ throw new InvalidRedirectUriError(
418
+ `Web clients must use HTTPS redirect URIs`,
419
+ )
420
+ }
421
+
422
+ if (url.hostname === 'localhost') {
423
+ throw new InvalidRedirectUriError(
424
+ `Web clients must not use localhost as the hostname`,
425
+ )
426
+ }
427
+ }
428
+ }
429
+
430
+ if (metadata.application_type === 'native') {
431
+ // https://openid.net/specs/openid-connect-registration-1_0.html#rfc.section.2
432
+ //
433
+ // > Native Clients [as defined by "application_type"] MUST only
434
+ // > register redirect_uris using custom URI schemes or loopback URLs
435
+ // > using the http scheme; loopback URLs use localhost or the IP
436
+ // > loopback literals 127.0.0.1 or [::1] as the hostname.
437
+
438
+ for (const redirectUri of metadata.redirect_uris) {
439
+ const url = parseRedirectUri(redirectUri)
440
+ if (url.protocol !== 'http:') {
441
+ throw new InvalidRedirectUriError(
442
+ `Native clients must use HTTP redirect URIs (got ${url})`,
443
+ )
444
+ }
445
+
446
+ if (!isLoopbackHost(url.hostname) && !isPrivateUseUriScheme(url)) {
447
+ throw new InvalidRedirectUriError(
448
+ 'Loopback redirect URIs are only allowed for native apps',
449
+ )
450
+ }
451
+ }
452
+ }
453
+
454
+ if (metadata.application_type === 'native') {
455
+ // https://openid.net/specs/openid-connect-registration-1_0.html#rfc.section.2
456
+ //
457
+ // > Authorization Servers MAY reject Redirection URI values using
458
+ // > the http scheme, other than the loopback case for Native
459
+ // > Clients.
460
+
461
+ for (const redirectUri of metadata.redirect_uris) {
462
+ const url = parseRedirectUri(redirectUri)
463
+ if (url.protocol === 'http:' && !isLoopbackUrl(url)) {
464
+ throw new InvalidRedirectUriError(
465
+ `Native clients must not use HTTP redirect URIs (got ${url})`,
466
+ )
467
+ }
468
+ }
469
+ }
470
+
471
+ for (const redirectUri of metadata.redirect_uris) {
472
+ const url = parseRedirectUri(redirectUri)
473
+
474
+ if (url.username || url.password) {
475
+ // Is this a valid concern? Should we allow credentials in the URI?
476
+ throw new InvalidRedirectUriError(
477
+ `Redirect URI ${url} must not contain credentials`,
478
+ )
479
+ }
480
+
481
+ switch (true) {
482
+ // FIRST: Loopback redirect URI exception (only for native apps)
483
+
484
+ case url.hostname === 'localhost': {
485
+ // https://datatracker.ietf.org/doc/html/rfc8252#section-8.3
486
+ //
487
+ // > While redirect URIs using localhost (i.e.,
488
+ // > "http://localhost:{port}/{path}") function similarly to loopback IP
489
+ // > redirects described in Section 7.3, the use of localhost is NOT
490
+ // > RECOMMENDED. Specifying a redirect URI with the loopback IP literal
491
+ // > rather than localhost avoids inadvertently listening on network
492
+ // > interfaces other than the loopback interface. It is also less
493
+ // > susceptible to client-side firewalls and misconfigured host name
494
+ // > resolution on the user's device.
495
+ throw new InvalidRedirectUriError(
496
+ `Loopback redirect URI ${url} is not allowed (use explicit IPs instead)`,
497
+ )
498
+ }
499
+ // falls through
500
+ case url.hostname === '127.0.0.1':
501
+ case url.hostname === '[::1]': {
502
+ // https://datatracker.ietf.org/doc/html/rfc8252#section-7.3
503
+ //
504
+ // > Loopback redirect URIs use the "http" scheme and are constructed
505
+ // > with the loopback IP literal and whatever port the client is
506
+ // > listening on. That is, "http://127.0.0.1:{port}/{path}" for IPv4,
507
+ // > and "http://[::1]:{port}/{path}" for IPv6.
508
+
509
+ if (metadata.application_type !== 'native') {
510
+ throw new InvalidRedirectUriError(
511
+ `Loopback redirect URIs are only allowed for native apps`,
512
+ )
513
+ }
514
+
515
+ if (url.port) {
516
+ // https://datatracker.ietf.org/doc/html/rfc8252#section-7.3
517
+ //
518
+ // > The authorization server MUST allow any port to be specified at
519
+ // > the time of the request for loopback IP redirect URIs, to
520
+ // > accommodate clients that obtain an available ephemeral port
521
+ // > from the operating system at the time of the request.
522
+ //
523
+ // Note: although validation of the redirect_uri will ignore the
524
+ // port we still allow it to be specified, as the spec does not
525
+ // forbid it. If a port number is specified, ports will need to
526
+ // match when validating authorization requests. See
527
+ // "compareRedirectUri()".
528
+ }
529
+
530
+ if (url.protocol !== 'http:') {
531
+ throw new InvalidRedirectUriError(
532
+ `Loopback redirect URI ${url} must use HTTP`,
533
+ )
534
+ }
535
+
536
+ break
537
+ }
538
+
539
+ // SECOND: Protocol-based URI Redirection
540
+
541
+ case url.protocol === 'http:': {
542
+ // https://openid.net/specs/openid-connect-registration-1_0.html#rfc.section.2
543
+ //
544
+ // > request_uri [...] URLs MUST use the https scheme unless the
545
+ // > target Request Object is signed in a way that is verifiable by
546
+ // > the OP.
547
+ //
548
+ // TODO: Should we allow this (and check for signed request objects)?
549
+ throw new InvalidRedirectUriError(
550
+ `Non loopback redirect URI ${url} must use HTTPS`,
551
+ )
552
+ }
553
+
554
+ case url.protocol === 'https:': {
555
+ const redirectUriDomain = parseUrlDomain(url)
556
+ if (!redirectUriDomain) {
557
+ throw new InvalidRedirectUriError(
558
+ `Redirect URI ${url} must be a valid URL`,
559
+ )
560
+ }
561
+
562
+ // https://datatracker.ietf.org/doc/html/rfc8252#section-8.4
563
+ //
564
+ // > In addition to the collision-resistant properties, requiring a
565
+ // > URI scheme based on a domain name that is under the control of
566
+ // > the app can help to prove ownership in the event of a dispute
567
+ // > where two apps claim the same private-use URI scheme (where one
568
+ // > app is acting maliciously).
569
+ //
570
+ // Although this only applies to "native" clients (extract being from
571
+ // rfc8252), we apply this rule to "web" clients as well.
572
+ if (!clientUriParsed) {
573
+ throw new InvalidClientMetadataError(
574
+ 'client_uri is required for HTTPS redirect URIs',
575
+ )
576
+ } else {
577
+ if (redirectUriDomain.domain !== clientUriParsed.domain) {
578
+ throw new InvalidRedirectUriError(
579
+ `Redirect URI ${url} must be under the same domain as client_uri ${metadata.client_uri}`,
580
+ )
581
+ }
582
+ }
583
+
584
+ break
585
+ }
586
+
587
+ case isPrivateUseUriScheme(url): {
588
+ // https://datatracker.ietf.org/doc/html/rfc8252#section-7.1
589
+ //
590
+ // > When choosing a URI scheme to associate with the app, apps MUST
591
+ // > use a URI scheme based on a domain name under their control,
592
+ // > expressed in reverse order, as recommended by Section 3.8 of
593
+ // > [RFC7595] for private-use URI schemes.
594
+
595
+ if (metadata.application_type !== 'native') {
596
+ throw new InvalidRedirectUriError(
597
+ `Private-Use URI Scheme redirect URI are only allowed for native apps`,
598
+ )
599
+ }
600
+
601
+ const redirectUriDomain = parseDomain(
602
+ reverseDomain(url.protocol.slice(0, -1)),
603
+ )
604
+
605
+ if (!redirectUriDomain) {
606
+ throw new InvalidRedirectUriError(
607
+ `Private-use URI Scheme redirect URI must be based on a valid domain name`,
608
+ )
609
+ }
610
+
611
+ // https://datatracker.ietf.org/doc/html/rfc8252#section-8.4
612
+ //
613
+ // > In addition to the collision-resistant properties, requiring a
614
+ // > URI scheme based on a domain name that is under the control of
615
+ // > the app can help to prove ownership in the event of a dispute
616
+ // > where two apps claim the same private-use URI scheme (where one
617
+ // > app is acting maliciously).
618
+ if (!clientUriParsed) {
619
+ throw new InvalidClientMetadataError(
620
+ 'client_uri is required for native apps using private-use URI Scheme redirect URIs',
621
+ )
622
+ } else {
623
+ if (redirectUriDomain.domain !== clientUriParsed.domain) {
624
+ throw new InvalidRedirectUriError(
625
+ `Private-Use URI Scheme redirect URI ${url} must be under the same domain as client_uri ${metadata.client_uri}`,
626
+ )
627
+ }
628
+ }
629
+
630
+ // https://datatracker.ietf.org/doc/html/rfc8252#section-7.1
631
+ //
632
+ // > Following the requirements of Section 3.2 of [RFC3986], as there
633
+ // > is no naming authority for private-use URI scheme redirects, only
634
+ // > a single slash ("/") appears after the scheme component.
635
+ if (
636
+ url.href.startsWith(`${url.protocol}//`) ||
637
+ url.username ||
638
+ url.password ||
639
+ url.hostname ||
640
+ url.port
641
+ ) {
642
+ throw new InvalidRedirectUriError(
643
+ `Private-Use URI Scheme must be in the form ${url.protocol}/<path>`,
644
+ )
645
+ }
646
+
647
+ break
648
+ }
649
+
650
+ default:
651
+ // https://datatracker.ietf.org/doc/html/rfc8252#section-8.4
652
+ //
653
+ // > At a minimum, any private-use URI scheme that doesn't contain a
654
+ // > period character (".") SHOULD be rejected.
655
+ throw new InvalidRedirectUriError(
656
+ `Invalid redirect URI scheme "${url.protocol}"`,
657
+ )
658
+ }
659
+ }
660
+
661
+ if (isOAuthClientIdLoopback(clientId)) {
662
+ return this.validateLoopbackClientMetadata(clientId, metadata)
663
+ } else if (isOAuthClientIdDiscoverable(clientId)) {
664
+ return this.validateDiscoverableClientMetadata(clientId, metadata)
665
+ } else {
666
+ return metadata
667
+ }
668
+ }
669
+
670
+ validateLoopbackClientMetadata(
671
+ clientId: OAuthClientIdLoopback,
672
+ metadata: OAuthClientMetadata,
673
+ ): OAuthClientMetadata {
674
+ if (metadata.client_uri) {
675
+ throw new InvalidClientMetadataError(
676
+ 'client_uri is not allowed for loopback clients',
677
+ )
678
+ }
679
+
680
+ if (metadata.application_type !== 'native') {
681
+ throw new InvalidClientMetadataError(
682
+ 'Loopback clients must have application_type "native"',
683
+ )
684
+ }
685
+
686
+ if (
687
+ !ALLOW_LOOPBACK_CLIENT_REFRESH_TOKEN &&
688
+ metadata.grant_types.includes('refresh_token')
689
+ ) {
690
+ throw new InvalidClientMetadataError(
691
+ 'Loopback clients are not allowed to use the "refresh_token" grant type',
692
+ )
693
+ }
694
+
695
+ for (const endpoint of OAUTH_AUTHENTICATED_ENDPOINT_NAMES) {
696
+ const method =
697
+ metadata[`${endpoint}_endpoint_auth_method`] ||
698
+ metadata[`token_endpoint_auth_method`]
699
+
700
+ if (method !== 'none') {
701
+ throw new InvalidClientMetadataError(
702
+ `Loopback clients are not allowed to use "${endpoint}_endpoint_auth_method" ${method}`,
703
+ )
704
+ }
705
+ }
706
+
707
+ for (const redirectUri of metadata.redirect_uris) {
708
+ const url = parseRedirectUri(redirectUri)
709
+
710
+ if (url.protocol !== 'http:') {
711
+ throw new InvalidRedirectUriError(
712
+ `Loopback clients must use HTTP redirect URIs`,
713
+ )
714
+ }
715
+
716
+ if (!isLoopbackHost(url.hostname)) {
717
+ throw new InvalidRedirectUriError(
718
+ `Loopback clients must use loopback redirect URIs`,
719
+ )
720
+ }
721
+ }
722
+
723
+ return metadata
724
+ }
725
+
726
+ validateDiscoverableClientMetadata(
727
+ clientId: OAuthClientIdDiscoverable,
728
+ metadata: OAuthClientMetadata,
729
+ ): OAuthClientMetadata {
730
+ if (!metadata.client_id) {
731
+ // https://drafts.aaronpk.com/draft-parecki-oauth-client-id-metadata-document/draft-parecki-oauth-client-id-metadata-document.html
732
+ throw new InvalidClientMetadataError(
733
+ `client_id is required for discoverable clients`,
734
+ )
735
+ }
736
+
737
+ const clientIdUrl = parseDiscoverableClientId(clientId)
738
+
739
+ if (metadata.client_uri) {
740
+ // https://drafts.aaronpk.com/draft-parecki-oauth-client-id-metadata-document/draft-parecki-oauth-client-id-metadata-document.html
741
+ //
742
+ // The client_uri must be a parent of the client_id URL. This might be
743
+ // relaxed in the future.
744
+
745
+ const clientUriUrl = new URL(metadata.client_uri)
746
+
747
+ if (clientUriUrl.origin !== clientIdUrl.origin) {
748
+ throw new InvalidClientMetadataError(
749
+ `client_uri must have the same origin as the client_id`,
750
+ )
751
+ }
752
+
753
+ if (clientIdUrl.pathname !== clientUriUrl.pathname) {
754
+ if (
755
+ !clientIdUrl.pathname.startsWith(
756
+ clientUriUrl.pathname.endsWith('/')
757
+ ? clientUriUrl.pathname
758
+ : `${clientUriUrl.pathname}/`,
759
+ )
760
+ ) {
761
+ throw new InvalidClientMetadataError(
762
+ `client_uri must be a parent URL of the client_id`,
763
+ )
764
+ }
765
+ }
766
+ }
767
+
768
+ for (const endpoint of OAUTH_AUTHENTICATED_ENDPOINT_NAMES) {
769
+ const method = metadata[`${endpoint}_endpoint_auth_method`]
770
+ switch (method) {
771
+ case 'client_secret_post':
772
+ case 'client_secret_basic':
773
+ case 'client_secret_jwt':
774
+ throw new InvalidClientMetadataError(
775
+ `Client authentication method "${method}" is not allowed for discoverable clients`,
776
+ )
777
+ }
778
+ }
779
+
780
+ for (const redirectUri of metadata.redirect_uris) {
781
+ const url = parseRedirectUri(redirectUri)
782
+
783
+ if (isPrivateUseUriScheme(url)) {
784
+ // https://drafts.aaronpk.com/draft-parecki-oauth-client-id-metadata-document/draft-parecki-oauth-client-id-metadata-document.html
785
+ //
786
+ // Fully qualified domain name (FQDN) of the client_id, in reverse
787
+ // order. This could be relaxed to allow same apex domain names, or
788
+ // parent domains, but for now we require an exact match.
789
+ const protocol = `${reverseDomain(clientIdUrl.hostname)}:`
790
+ if (url.protocol !== protocol) {
791
+ throw new InvalidRedirectUriError(
792
+ `Private-Use URI Scheme redirect URI, for discoverable client metadata, must be the fully qualified domain name (FQDN) of the client_id, in reverse order (${protocol})`,
793
+ )
794
+ }
795
+ }
796
+ }
797
+
798
+ return metadata
799
+ }
800
+ }
801
+
802
+ function reverseDomain(domain: string) {
803
+ return domain.split('.').reverse().join('.')
804
+ }
805
+
806
+ function isPrivateUseUriScheme(uri: URL) {
807
+ return uri.protocol.includes('.')
808
+ }
809
+
810
+ function buildJsonGetRequest(uri: string, options?: GetCachedOptions) {
811
+ const headers = new Headers([['accept', 'application/json']])
812
+ if (options?.noCache) headers.set('cache-control', 'no-cache')
813
+ return new Request(uri, {
814
+ headers,
815
+ signal: options?.signal,
816
+ redirect: 'error',
817
+ })
818
+ }