@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,591 @@
1
+ import { isSignedJwt, SignedJwt } from '@atproto/jwk'
2
+ import {
3
+ AccessToken,
4
+ CLIENT_ASSERTION_TYPE_JWT_BEARER,
5
+ OAuthAuthenticationRequestParameters,
6
+ OAuthTokenResponse,
7
+ OAuthTokenType,
8
+ } from '@atproto/oauth-types'
9
+ import { createHash } from 'node:crypto'
10
+
11
+ import { AccessTokenType } from '../access-token/access-token-type.js'
12
+ import { DeviceAccountInfo } from '../account/account-store.js'
13
+ import { Account } from '../account/account.js'
14
+ import { ClientAuth } from '../client/client-auth.js'
15
+ import { Client } from '../client/client.js'
16
+ import {
17
+ AUTHENTICATED_REFRESH_INACTIVITY_TIMEOUT,
18
+ AUTHENTICATED_REFRESH_LIFETIME,
19
+ TOKEN_MAX_AGE,
20
+ UNAUTHENTICATED_REFRESH_INACTIVITY_TIMEOUT,
21
+ UNAUTHENTICATED_REFRESH_LIFETIME,
22
+ } from '../constants.js'
23
+ import { DeviceId } from '../device/device-id.js'
24
+ import { InvalidDpopKeyBindingError } from '../errors/invalid-dpop-key-binding-error.js'
25
+ import { InvalidDpopProofError } from '../errors/invalid-dpop-proof-error.js'
26
+ import { InvalidGrantError } from '../errors/invalid-grant-error.js'
27
+ import { InvalidRequestError } from '../errors/invalid-request-error.js'
28
+ import { InvalidTokenError } from '../errors/invalid-token-error.js'
29
+ import { dateToEpoch, dateToRelativeSeconds } from '../lib/util/date.js'
30
+ import { compareRedirectUri } from '../lib/util/redirect-uri.js'
31
+ import { OAuthHooks } from '../oauth-hooks.js'
32
+ import { isCode } from '../request/code.js'
33
+ import { Signer } from '../signer/signer.js'
34
+ import { generateRefreshToken, isRefreshToken } from './refresh-token.js'
35
+ import { TokenClaims } from './token-claims.js'
36
+ import { TokenData } from './token-data.js'
37
+ import {
38
+ TokenId,
39
+ generateTokenId,
40
+ isTokenId,
41
+ tokenIdSchema,
42
+ } from './token-id.js'
43
+ import { TokenInfo, TokenStore } from './token-store.js'
44
+ import { CodeGrantRequest, RefreshGrantRequest } from './types.js'
45
+ import {
46
+ VerifyTokenClaimsOptions,
47
+ VerifyTokenClaimsResult,
48
+ verifyTokenClaims,
49
+ } from './verify-token-claims.js'
50
+
51
+ export type AuthenticateTokenIdResult = VerifyTokenClaimsResult & {
52
+ tokenInfo: TokenInfo
53
+ }
54
+
55
+ export class TokenManager {
56
+ constructor(
57
+ protected readonly store: TokenStore,
58
+ protected readonly signer: Signer,
59
+ protected readonly hooks: OAuthHooks,
60
+ protected readonly accessTokenType: AccessTokenType,
61
+ protected readonly tokenMaxAge = TOKEN_MAX_AGE,
62
+ ) {}
63
+
64
+ protected createTokenExpiry(now = new Date()) {
65
+ return new Date(now.getTime() + this.tokenMaxAge)
66
+ }
67
+
68
+ protected useJwtAccessToken(account: Account) {
69
+ if (this.accessTokenType === AccessTokenType.auto) {
70
+ return this.signer.issuer !== account.aud
71
+ }
72
+
73
+ return this.accessTokenType === AccessTokenType.jwt
74
+ }
75
+
76
+ async create(
77
+ client: Client,
78
+ clientAuth: ClientAuth,
79
+ account: Account,
80
+ device: null | { id: DeviceId; info: DeviceAccountInfo },
81
+ parameters: OAuthAuthenticationRequestParameters,
82
+ input: CodeGrantRequest,
83
+ dpopJkt: null | string,
84
+ ): Promise<OAuthTokenResponse> {
85
+ if (client.metadata.dpop_bound_access_tokens && !dpopJkt) {
86
+ throw new InvalidDpopProofError('DPoP proof required')
87
+ }
88
+
89
+ if (!parameters.dpop_jkt) {
90
+ if (dpopJkt) parameters = { ...parameters, dpop_jkt: dpopJkt }
91
+ } else if (!dpopJkt) {
92
+ throw new InvalidDpopProofError('DPoP proof required')
93
+ } else if (parameters.dpop_jkt !== dpopJkt) {
94
+ throw new InvalidDpopKeyBindingError()
95
+ }
96
+
97
+ if (clientAuth.method === CLIENT_ASSERTION_TYPE_JWT_BEARER) {
98
+ // Clients **must not** use their private key to sign DPoP proofs.
99
+ if (parameters.dpop_jkt && clientAuth.jkt === parameters.dpop_jkt) {
100
+ throw new InvalidRequestError(
101
+ 'The DPoP proof must be signed with a different key than the client assertion',
102
+ )
103
+ }
104
+ }
105
+
106
+ if (!client.metadata.grant_types.includes(input.grant_type)) {
107
+ throw new InvalidGrantError(
108
+ `This client is not allowed to use the "${input.grant_type}" grant type`,
109
+ )
110
+ }
111
+
112
+ switch (input.grant_type) {
113
+ case 'authorization_code':
114
+ if (!parameters.code_challenge || !parameters.code_challenge_method) {
115
+ throw new InvalidGrantError('PKCE is required')
116
+ }
117
+
118
+ if (!parameters.redirect_uri) {
119
+ const redirect_uri = client.metadata.redirect_uris.find((uri) =>
120
+ compareRedirectUri(uri, input.redirect_uri),
121
+ )
122
+ if (redirect_uri) {
123
+ parameters = { ...parameters, redirect_uri }
124
+ } else {
125
+ throw new InvalidGrantError(`Invalid redirect_uri`)
126
+ }
127
+ } else if (parameters.redirect_uri !== input.redirect_uri) {
128
+ throw new InvalidGrantError(
129
+ 'This code was issued for another redirect_uri',
130
+ )
131
+ }
132
+
133
+ break
134
+
135
+ default:
136
+ throw new Error(`Unsupported grant type "${input.grant_type}"`)
137
+ }
138
+
139
+ if (parameters.code_challenge) {
140
+ if (!('code_verifier' in input) || !input.code_verifier) {
141
+ throw new InvalidGrantError('code_verifier is required')
142
+ }
143
+ switch (parameters.code_challenge_method) {
144
+ case undefined: // Default is "plain" (per spec)
145
+ case 'plain': {
146
+ if (parameters.code_challenge !== input.code_verifier) {
147
+ throw new InvalidGrantError('Invalid code_verifier')
148
+ }
149
+ break
150
+ }
151
+ case 'S256': {
152
+ // Because the code_challenge is base64url-encoded, we will decode
153
+ // it in order to compare based on bytes.
154
+ const inputChallenge = Buffer.from(
155
+ parameters.code_challenge,
156
+ 'base64',
157
+ )
158
+ const computedChallenge = createHash('sha256')
159
+ .update(input.code_verifier)
160
+ .digest()
161
+ if (inputChallenge.compare(computedChallenge) !== 0) {
162
+ throw new InvalidGrantError('Invalid code_verifier')
163
+ }
164
+ break
165
+ }
166
+ default: {
167
+ throw new InvalidRequestError(
168
+ `Unsupported code_challenge_method ${parameters.code_challenge_method}`,
169
+ )
170
+ }
171
+ }
172
+ }
173
+
174
+ const code = 'code' in input ? input.code : undefined
175
+ if (code) {
176
+ const tokenInfo = await this.store.findTokenByCode(code)
177
+ if (tokenInfo) {
178
+ await this.store.deleteToken(tokenInfo.id)
179
+ throw new InvalidGrantError(`Code replayed`)
180
+ }
181
+ }
182
+
183
+ const tokenId = await generateTokenId()
184
+ const scopes = parameters.scope?.split(' ')
185
+ const refreshToken = scopes?.includes('offline_access')
186
+ ? await generateRefreshToken()
187
+ : undefined
188
+
189
+ const now = new Date()
190
+ const expiresAt = this.createTokenExpiry(now)
191
+
192
+ const authorizationDetails = await this.hooks.onAuthorizationDetails?.call(
193
+ null,
194
+ { client, parameters, account },
195
+ )
196
+
197
+ const tokenData: TokenData = {
198
+ createdAt: now,
199
+ updatedAt: now,
200
+ expiresAt,
201
+ clientId: client.id,
202
+ clientAuth,
203
+ deviceId: device?.id ?? null,
204
+ sub: account.sub,
205
+ parameters,
206
+ details: authorizationDetails ?? null,
207
+ code: code ?? null,
208
+ }
209
+
210
+ await this.store.createToken(tokenId, tokenData, refreshToken)
211
+
212
+ const accessToken: AccessToken = !this.useJwtAccessToken(account)
213
+ ? tokenId
214
+ : await this.signer.accessToken(client, parameters, account, {
215
+ // We don't specify the alg here. We suppose the Resource server will be
216
+ // able to verify the token using any alg.
217
+ alg: undefined,
218
+ exp: expiresAt,
219
+ iat: now,
220
+ jti: tokenId,
221
+ cnf: parameters.dpop_jkt ? { jkt: parameters.dpop_jkt } : undefined,
222
+ authorization_details: authorizationDetails,
223
+ })
224
+
225
+ const idToken = scopes?.includes('openid')
226
+ ? await this.signer.idToken(client, parameters, account, {
227
+ exp: expiresAt,
228
+ iat: now,
229
+ // If there is no deviceInfo, we are in a "password_grant" context
230
+ auth_time: device?.info.authenticatedAt || new Date(),
231
+ access_token: accessToken,
232
+ code,
233
+ })
234
+ : undefined
235
+
236
+ return this.buildTokenResponse(
237
+ client,
238
+ accessToken,
239
+ refreshToken,
240
+ idToken,
241
+ expiresAt,
242
+ parameters,
243
+ account,
244
+ authorizationDetails,
245
+ )
246
+ }
247
+
248
+ protected async buildTokenResponse(
249
+ client: Client,
250
+ accessToken: AccessToken,
251
+ refreshToken: string | undefined,
252
+ idToken: SignedJwt | undefined,
253
+ expiresAt: Date,
254
+ parameters: OAuthAuthenticationRequestParameters,
255
+ account: Account,
256
+ authorizationDetails: null | any,
257
+ ): Promise<OAuthTokenResponse> {
258
+ const tokenResponse: OAuthTokenResponse = {
259
+ access_token: accessToken,
260
+ token_type: parameters.dpop_jkt ? 'DPoP' : 'Bearer',
261
+ refresh_token: refreshToken,
262
+ id_token: idToken,
263
+ scope: parameters.scope ?? '',
264
+ authorization_details: authorizationDetails,
265
+ get expires_in() {
266
+ return dateToRelativeSeconds(expiresAt)
267
+ },
268
+
269
+ // ATPROTO extension: add the sub claim to the token response to allow
270
+ // clients to resolve the PDS url (audience) using the did resolution
271
+ // mechanism.
272
+ sub: account.sub,
273
+ }
274
+
275
+ await this.hooks.onTokenResponse?.call(null, tokenResponse, {
276
+ client,
277
+ parameters,
278
+ account,
279
+ })
280
+
281
+ return tokenResponse
282
+ }
283
+
284
+ protected async validateAccess(
285
+ client: Client,
286
+ clientAuth: ClientAuth,
287
+ tokenInfo: TokenInfo,
288
+ ) {
289
+ if (tokenInfo.data.clientId !== client.id) {
290
+ throw new InvalidGrantError(`Token was not issued to this client`)
291
+ }
292
+
293
+ if (tokenInfo.info?.authorizedClients.includes(client.id) === false) {
294
+ throw new InvalidGrantError(`Client no longer trusted by user`)
295
+ }
296
+
297
+ if (tokenInfo.data.clientAuth.method !== clientAuth.method) {
298
+ throw new InvalidGrantError(`Client authentication method mismatch`)
299
+ }
300
+
301
+ if (!(await client.validateClientAuth(tokenInfo.data.clientAuth))) {
302
+ throw new InvalidGrantError(`Client authentication mismatch`)
303
+ }
304
+ }
305
+
306
+ async refresh(
307
+ client: Client,
308
+ clientAuth: ClientAuth,
309
+ input: RefreshGrantRequest,
310
+ dpopJkt: null | string,
311
+ ): Promise<OAuthTokenResponse> {
312
+ const tokenInfo = await this.store.findTokenByRefreshToken(
313
+ input.refresh_token,
314
+ )
315
+ if (!tokenInfo?.currentRefreshToken) {
316
+ throw new InvalidGrantError(`Invalid refresh token`)
317
+ }
318
+
319
+ const { account, info, data } = tokenInfo
320
+ const { parameters } = data
321
+
322
+ try {
323
+ if (tokenInfo.currentRefreshToken !== input.refresh_token) {
324
+ throw new InvalidGrantError(`refresh token replayed`)
325
+ }
326
+
327
+ await this.validateAccess(client, clientAuth, tokenInfo)
328
+
329
+ if (parameters.dpop_jkt) {
330
+ if (!dpopJkt) {
331
+ throw new InvalidDpopProofError('DPoP proof required')
332
+ } else if (parameters.dpop_jkt !== dpopJkt) {
333
+ throw new InvalidDpopKeyBindingError()
334
+ }
335
+ }
336
+
337
+ const lastActivity = data.updatedAt
338
+ const inactivityTimeout =
339
+ clientAuth.method === 'none' && !client.info.isFirstParty
340
+ ? UNAUTHENTICATED_REFRESH_INACTIVITY_TIMEOUT
341
+ : AUTHENTICATED_REFRESH_INACTIVITY_TIMEOUT
342
+ if (lastActivity.getTime() + inactivityTimeout < Date.now()) {
343
+ throw new InvalidGrantError(`Refresh token exceeded inactivity timeout`)
344
+ }
345
+
346
+ const lifetime =
347
+ clientAuth.method === 'none' && !client.info.isFirstParty
348
+ ? UNAUTHENTICATED_REFRESH_LIFETIME
349
+ : AUTHENTICATED_REFRESH_LIFETIME
350
+ if (data.createdAt.getTime() + lifetime < Date.now()) {
351
+ throw new InvalidGrantError(`Refresh token expired`)
352
+ }
353
+
354
+ const authorization_details =
355
+ await this.hooks.onAuthorizationDetails?.call(null, {
356
+ client,
357
+ parameters,
358
+ account,
359
+ })
360
+
361
+ const nextTokenId = await generateTokenId()
362
+ const nextRefreshToken = await generateRefreshToken()
363
+
364
+ const now = new Date()
365
+ const expiresAt = this.createTokenExpiry(now)
366
+
367
+ await this.store.rotateToken(
368
+ tokenInfo.id,
369
+ nextTokenId,
370
+ nextRefreshToken,
371
+ {
372
+ updatedAt: now,
373
+ expiresAt,
374
+ // When clients rotate their public keys, we store the key that was
375
+ // used by the client to authenticate itself while requesting new
376
+ // tokens. The validateAccess() method will ensure that the client
377
+ // still advertises the key that was used to issue the previous
378
+ // refresh token. If a client stops advertising a key, all tokens
379
+ // bound to that key will no longer be be refreshable. This allows
380
+ // clients to proactively invalidate tokens when a key is compromised.
381
+ // Note that the original DPoP key cannot be rotated. This protects
382
+ // users in case the ownership of the client id changes. In the latter
383
+ // case, a malicious actor could still advertises the public keys of
384
+ // the previous owner, but the new owner would not be able to present
385
+ // a valid DPoP proof.
386
+ clientAuth,
387
+ },
388
+ )
389
+
390
+ const accessToken: AccessToken = !this.useJwtAccessToken(account)
391
+ ? nextTokenId
392
+ : await this.signer.accessToken(client, parameters, account, {
393
+ // We don't specify the alg here. We suppose the Resource server will be
394
+ // able to verify the token using any alg.
395
+ alg: undefined,
396
+ exp: expiresAt,
397
+ iat: now,
398
+ jti: nextTokenId,
399
+ cnf: parameters.dpop_jkt ? { jkt: parameters.dpop_jkt } : undefined,
400
+ authorization_details,
401
+ })
402
+
403
+ // https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.3.3
404
+ //
405
+ // > In addition to the response parameters specified by OAuth 2.0, the
406
+ // > following parameters MUST be included in the response:
407
+ // > - id_token: ID Token value associated with the authenticated session.
408
+ const scopes = parameters.scope?.split(' ')
409
+ const idToken = scopes?.includes('openid')
410
+ ? await this.signer.idToken(client, parameters, account, {
411
+ exp: expiresAt,
412
+ iat: now,
413
+ auth_time: info?.authenticatedAt,
414
+ access_token: accessToken,
415
+ })
416
+ : undefined
417
+
418
+ return this.buildTokenResponse(
419
+ client,
420
+ accessToken,
421
+ nextRefreshToken,
422
+ idToken,
423
+ expiresAt,
424
+ parameters,
425
+ account,
426
+ authorization_details,
427
+ )
428
+ } catch (err) {
429
+ if (err instanceof InvalidRequestError) {
430
+ // Consider the refresh token might be compromised if sanity checks
431
+ // failed.
432
+ await this.store.deleteToken(tokenInfo.id)
433
+ }
434
+ throw err
435
+ }
436
+ }
437
+
438
+ /**
439
+ * @see {@link https://datatracker.ietf.org/doc/html/rfc7009#section-2.2 | RFC7009 Section 2.2}
440
+ */
441
+ async revoke(token: string): Promise<void> {
442
+ switch (true) {
443
+ case isTokenId(token): {
444
+ await this.store.deleteToken(token)
445
+ return
446
+ }
447
+
448
+ case isSignedJwt(token): {
449
+ const { payload } = await this.signer.verify(token, {
450
+ clockTolerance: Infinity,
451
+ })
452
+ const tokenId = tokenIdSchema.parse(payload.jti)
453
+ await this.store.deleteToken(tokenId)
454
+ return
455
+ }
456
+
457
+ case isRefreshToken(token): {
458
+ const tokenInfo = await this.store.findTokenByRefreshToken(token)
459
+ if (tokenInfo) await this.store.deleteToken(tokenInfo.id)
460
+ return
461
+ }
462
+
463
+ case isCode(token): {
464
+ const tokenInfo = await this.store.findTokenByCode(token)
465
+ if (tokenInfo) await this.store.deleteToken(tokenInfo.id)
466
+ return
467
+ }
468
+
469
+ default:
470
+ // No error should be returned if the token is not valid
471
+ return
472
+ }
473
+ }
474
+
475
+ /**
476
+ * Allows an (authenticated) client to obtain information about a token.
477
+ *
478
+ * @see {@link https://datatracker.ietf.org/doc/html/rfc7662 RFC7662}
479
+ */
480
+ async clientTokenInfo(
481
+ client: Client,
482
+ clientAuth: ClientAuth,
483
+ token: string,
484
+ ): Promise<TokenInfo> {
485
+ const tokenInfo = await this.findTokenInfo(token)
486
+ if (!tokenInfo) {
487
+ throw new InvalidGrantError(`Invalid token`)
488
+ }
489
+
490
+ try {
491
+ await this.validateAccess(client, clientAuth, tokenInfo)
492
+ } catch (err) {
493
+ await this.store.deleteToken(tokenInfo.id)
494
+ throw err
495
+ }
496
+
497
+ if (tokenInfo.data.expiresAt.getTime() < Date.now()) {
498
+ throw new InvalidGrantError(`Token expired`)
499
+ }
500
+
501
+ return tokenInfo
502
+ }
503
+
504
+ protected async findTokenInfo(token: string): Promise<TokenInfo | null> {
505
+ switch (true) {
506
+ case isTokenId(token):
507
+ return this.store.readToken(token)
508
+
509
+ case isSignedJwt(token): {
510
+ const { payload } = await this.signer
511
+ .verifyAccessToken(token)
512
+ .catch((_) => ({ payload: null }))
513
+ if (!payload) return null
514
+
515
+ const tokenInfo = await this.store.readToken(payload.jti)
516
+ if (!tokenInfo) return null
517
+
518
+ // Audience changed (e.g. user was moved to another resource server)
519
+ if (payload.aud !== tokenInfo.account.aud) {
520
+ return null
521
+ }
522
+
523
+ // Invalid store implementation ?
524
+ if (payload.sub !== tokenInfo.account.sub) {
525
+ throw new Error(
526
+ `Account sub (${tokenInfo.account.sub}) does not match token sub (${payload.sub})`,
527
+ )
528
+ }
529
+
530
+ return tokenInfo
531
+ }
532
+
533
+ case isRefreshToken(token): {
534
+ const tokenInfo = await this.store.findTokenByRefreshToken(token)
535
+ if (!tokenInfo?.currentRefreshToken) return null
536
+ if (tokenInfo.currentRefreshToken !== token) return null
537
+ return tokenInfo
538
+ }
539
+
540
+ default:
541
+ // Should never happen
542
+ return null
543
+ }
544
+ }
545
+
546
+ async getTokenInfo(tokenType: OAuthTokenType, tokenId: TokenId) {
547
+ const tokenInfo = await this.store.readToken(tokenId)
548
+
549
+ if (!tokenInfo) {
550
+ throw new InvalidTokenError(tokenType, `Invalid token`)
551
+ }
552
+
553
+ if (!(tokenInfo.data.expiresAt.getTime() > Date.now())) {
554
+ throw new InvalidTokenError(tokenType, `Token expired`)
555
+ }
556
+
557
+ return tokenInfo
558
+ }
559
+
560
+ async authenticateTokenId(
561
+ tokenType: OAuthTokenType,
562
+ token: TokenId,
563
+ dpopJkt: string | null,
564
+ verifyOptions?: VerifyTokenClaimsOptions,
565
+ ): Promise<AuthenticateTokenIdResult> {
566
+ const tokenInfo = await this.getTokenInfo(tokenType, token)
567
+ const { parameters } = tokenInfo.data
568
+
569
+ // Construct a list of claim, as if the token was a JWT.
570
+ const claims: TokenClaims = {
571
+ aud: tokenInfo.account.aud,
572
+ sub: tokenInfo.account.sub,
573
+ exp: dateToEpoch(tokenInfo.data.expiresAt),
574
+ iat: dateToEpoch(tokenInfo.data.updatedAt),
575
+ scope: tokenInfo.data.parameters.scope,
576
+ client_id: tokenInfo.data.clientId,
577
+ cnf: parameters.dpop_jkt ? { jkt: parameters.dpop_jkt } : undefined,
578
+ }
579
+
580
+ const result = verifyTokenClaims(
581
+ token,
582
+ token,
583
+ tokenType,
584
+ dpopJkt,
585
+ claims,
586
+ verifyOptions,
587
+ )
588
+
589
+ return { ...result, tokenInfo }
590
+ }
591
+ }
@@ -0,0 +1,78 @@
1
+ import { DeviceAccountInfo } from '../account/account-store.js'
2
+ import { Account } from '../account/account.js'
3
+ import { Awaitable } from '../lib/util/type.js'
4
+ import { Code } from '../request/code.js'
5
+ import { RefreshToken } from './refresh-token.js'
6
+ import { TokenData } from './token-data.js'
7
+ import { TokenId } from './token-id.js'
8
+
9
+ // Export all types needed to implement the TokenStore interface
10
+ export * from './token-id.js'
11
+ export * from './token-data.js'
12
+ export * from './refresh-token.js'
13
+ export type { Awaitable }
14
+
15
+ export type TokenInfo = {
16
+ id: TokenId
17
+ data: TokenData
18
+ account: Account
19
+ info?: DeviceAccountInfo
20
+ currentRefreshToken: null | RefreshToken
21
+ }
22
+
23
+ export type NewTokenData = Pick<
24
+ TokenData,
25
+ 'clientAuth' | 'expiresAt' | 'updatedAt'
26
+ >
27
+
28
+ export interface TokenStore {
29
+ createToken(
30
+ tokenId: TokenId,
31
+ data: TokenData,
32
+ refreshToken?: RefreshToken,
33
+ ): Awaitable<void>
34
+
35
+ readToken(tokenId: TokenId): Awaitable<null | TokenInfo>
36
+
37
+ deleteToken(tokenId: TokenId): Awaitable<void>
38
+
39
+ rotateToken(
40
+ tokenId: TokenId,
41
+ newTokenId: TokenId,
42
+ newRefreshToken: RefreshToken,
43
+ newData: NewTokenData,
44
+ ): Awaitable<void>
45
+
46
+ /**
47
+ * Find a token by its refresh token. Note that previous refresh tokens
48
+ * should also return the token. The data model is reponsible for storing
49
+ * old refresh tokens when a new one is issued.
50
+ */
51
+ findTokenByRefreshToken(
52
+ refreshToken: RefreshToken,
53
+ ): Awaitable<null | TokenInfo>
54
+
55
+ findTokenByCode(code: Code): Awaitable<null | TokenInfo>
56
+ }
57
+
58
+ export function isTokenStore(
59
+ implementation: Record<string, unknown> & Partial<TokenStore>,
60
+ ): implementation is Record<string, unknown> & TokenStore {
61
+ return (
62
+ typeof implementation.createToken === 'function' &&
63
+ typeof implementation.readToken === 'function' &&
64
+ typeof implementation.rotateToken === 'function' &&
65
+ typeof implementation.deleteToken === 'function' &&
66
+ typeof implementation.findTokenByCode === 'function' &&
67
+ typeof implementation.findTokenByRefreshToken === 'function'
68
+ )
69
+ }
70
+
71
+ export function asTokenStore(
72
+ implementation?: Record<string, unknown> & Partial<TokenStore>,
73
+ ): TokenStore {
74
+ if (!implementation || !isTokenStore(implementation)) {
75
+ throw new Error('Invalid TokenStore implementation')
76
+ }
77
+ return implementation
78
+ }