@atproto/oauth-provider 0.6.6 → 0.7.1

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 (465) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/dist/access-token/access-token-mode.d.ts +5 -0
  3. package/dist/access-token/access-token-mode.d.ts.map +1 -0
  4. package/dist/access-token/access-token-mode.js +9 -0
  5. package/dist/access-token/access-token-mode.js.map +1 -0
  6. package/dist/account/account-manager.d.ts +13 -7
  7. package/dist/account/account-manager.d.ts.map +1 -1
  8. package/dist/account/account-manager.js +69 -52
  9. package/dist/account/account-manager.js.map +1 -1
  10. package/dist/account/account-store.d.ts +88 -77
  11. package/dist/account/account-store.d.ts.map +1 -1
  12. package/dist/account/account-store.js +24 -73
  13. package/dist/account/account-store.js.map +1 -1
  14. package/dist/account/sign-in-data.d.ts +4 -13
  15. package/dist/account/sign-in-data.d.ts.map +1 -1
  16. package/dist/account/sign-in-data.js +9 -9
  17. package/dist/account/sign-in-data.js.map +1 -1
  18. package/dist/account/sign-up-input.d.ts +4 -5
  19. package/dist/account/sign-up-input.d.ts.map +1 -1
  20. package/dist/account/sign-up-input.js +13 -3
  21. package/dist/account/sign-up-input.js.map +1 -1
  22. package/dist/client/client-manager.d.ts +4 -1
  23. package/dist/client/client-manager.d.ts.map +1 -1
  24. package/dist/client/client-manager.js +13 -1
  25. package/dist/client/client-manager.js.map +1 -1
  26. package/dist/client/client-store.d.ts +1 -1
  27. package/dist/client/client-store.d.ts.map +1 -1
  28. package/dist/constants.d.ts +5 -1
  29. package/dist/constants.d.ts.map +1 -1
  30. package/dist/constants.js +6 -2
  31. package/dist/constants.js.map +1 -1
  32. package/dist/customization/branding.d.ts +54 -0
  33. package/dist/customization/branding.d.ts.map +1 -0
  34. package/dist/customization/branding.js +13 -0
  35. package/dist/customization/branding.js.map +1 -0
  36. package/dist/customization/build-customization-css.d.ts +3 -0
  37. package/dist/customization/build-customization-css.d.ts.map +1 -0
  38. package/dist/customization/build-customization-css.js +27 -0
  39. package/dist/customization/build-customization-css.js.map +1 -0
  40. package/dist/customization/build-customization-data.d.ts +4 -0
  41. package/dist/customization/build-customization-data.d.ts.map +1 -0
  42. package/dist/customization/build-customization-data.js +18 -0
  43. package/dist/customization/build-customization-data.js.map +1 -0
  44. package/dist/customization/colors.d.ts +7 -0
  45. package/dist/customization/colors.d.ts.map +1 -0
  46. package/dist/customization/colors.js +27 -0
  47. package/dist/customization/colors.js.map +1 -0
  48. package/dist/customization/customization.d.ts +129 -0
  49. package/dist/customization/customization.d.ts.map +1 -0
  50. package/dist/customization/customization.js +26 -0
  51. package/dist/customization/customization.js.map +1 -0
  52. package/dist/customization/links.d.ts +26 -0
  53. package/dist/customization/links.d.ts.map +1 -0
  54. package/dist/customization/links.js +12 -0
  55. package/dist/customization/links.js.map +1 -0
  56. package/dist/device/device-id.d.ts +1 -0
  57. package/dist/device/device-id.d.ts.map +1 -1
  58. package/dist/device/device-id.js +4 -0
  59. package/dist/device/device-id.js.map +1 -1
  60. package/dist/device/device-manager.d.ts +6 -36
  61. package/dist/device/device-manager.d.ts.map +1 -1
  62. package/dist/device/device-manager.js +49 -43
  63. package/dist/device/device-manager.js.map +1 -1
  64. package/dist/device/device-store.d.ts +1 -0
  65. package/dist/device/device-store.d.ts.map +1 -1
  66. package/dist/device/device-store.js.map +1 -1
  67. package/dist/dpop/dpop-manager.d.ts +3 -3
  68. package/dist/dpop/dpop-nonce.d.ts +3 -3
  69. package/dist/dpop/dpop-nonce.d.ts.map +1 -1
  70. package/dist/errors/access-denied-error.d.ts +4 -3
  71. package/dist/errors/access-denied-error.d.ts.map +1 -1
  72. package/dist/errors/access-denied-error.js +5 -6
  73. package/dist/errors/access-denied-error.js.map +1 -1
  74. package/dist/{output/build-error-payload.d.ts → errors/error-parser.d.ts} +1 -1
  75. package/dist/errors/error-parser.d.ts.map +1 -0
  76. package/dist/{output/build-error-payload.js → errors/error-parser.js} +2 -2
  77. package/dist/errors/error-parser.js.map +1 -0
  78. package/dist/errors/invalid-grant-error.d.ts +1 -0
  79. package/dist/errors/invalid-grant-error.d.ts.map +1 -1
  80. package/dist/errors/invalid-grant-error.js +5 -0
  81. package/dist/errors/invalid-grant-error.js.map +1 -1
  82. package/dist/errors/login-required-error.d.ts +1 -0
  83. package/dist/errors/login-required-error.d.ts.map +1 -1
  84. package/dist/errors/login-required-error.js +5 -0
  85. package/dist/errors/login-required-error.js.map +1 -1
  86. package/dist/index.d.ts +1 -0
  87. package/dist/index.d.ts.map +1 -1
  88. package/dist/index.js +1 -0
  89. package/dist/index.js.map +1 -1
  90. package/dist/lib/html/build-document.d.ts +2 -2
  91. package/dist/lib/html/build-document.d.ts.map +1 -1
  92. package/dist/lib/html/build-document.js +4 -0
  93. package/dist/lib/html/build-document.js.map +1 -1
  94. package/dist/lib/html/hydration-data.d.ts +4 -0
  95. package/dist/lib/html/hydration-data.d.ts.map +1 -0
  96. package/dist/{output/backend-data.js → lib/html/hydration-data.js} +8 -8
  97. package/dist/lib/html/hydration-data.js.map +1 -0
  98. package/dist/lib/html/tags.d.ts +1 -1
  99. package/dist/lib/html/tags.d.ts.map +1 -1
  100. package/dist/lib/html/tags.js +1 -1
  101. package/dist/lib/html/tags.js.map +1 -1
  102. package/dist/lib/http/accept.d.ts +2 -2
  103. package/dist/lib/http/accept.d.ts.map +1 -1
  104. package/dist/lib/http/accept.js +1 -1
  105. package/dist/lib/http/accept.js.map +1 -1
  106. package/dist/lib/http/context.d.ts +2 -4
  107. package/dist/lib/http/context.d.ts.map +1 -1
  108. package/dist/lib/http/context.js +29 -4
  109. package/dist/lib/http/context.js.map +1 -1
  110. package/dist/lib/http/headers.d.ts +3 -0
  111. package/dist/lib/http/headers.d.ts.map +1 -0
  112. package/dist/lib/http/headers.js +14 -0
  113. package/dist/lib/http/headers.js.map +1 -0
  114. package/dist/lib/http/index.d.ts +1 -0
  115. package/dist/lib/http/index.d.ts.map +1 -1
  116. package/dist/lib/http/index.js +1 -0
  117. package/dist/lib/http/index.js.map +1 -1
  118. package/dist/lib/http/middleware.d.ts +1 -1
  119. package/dist/lib/http/middleware.d.ts.map +1 -1
  120. package/dist/lib/http/middleware.js +8 -24
  121. package/dist/lib/http/middleware.js.map +1 -1
  122. package/dist/lib/http/parser.d.ts +3 -3
  123. package/dist/lib/http/parser.d.ts.map +1 -1
  124. package/dist/lib/http/request.d.ts +13 -9
  125. package/dist/lib/http/request.d.ts.map +1 -1
  126. package/dist/lib/http/request.js +27 -49
  127. package/dist/lib/http/request.js.map +1 -1
  128. package/dist/lib/http/response.d.ts +6 -2
  129. package/dist/lib/http/response.d.ts.map +1 -1
  130. package/dist/lib/http/response.js +31 -11
  131. package/dist/lib/http/response.js.map +1 -1
  132. package/dist/lib/http/route.d.ts +3 -3
  133. package/dist/lib/http/route.d.ts.map +1 -1
  134. package/dist/lib/http/route.js +1 -1
  135. package/dist/lib/http/route.js.map +1 -1
  136. package/dist/lib/http/router.d.ts +12 -11
  137. package/dist/lib/http/router.d.ts.map +1 -1
  138. package/dist/lib/http/router.js +26 -34
  139. package/dist/lib/http/router.js.map +1 -1
  140. package/dist/lib/http/security-headers.js +1 -1
  141. package/dist/lib/http/security-headers.js.map +1 -1
  142. package/dist/lib/http/stream.d.ts +3 -3
  143. package/dist/lib/http/stream.d.ts.map +1 -1
  144. package/dist/lib/http/types.d.ts +1 -1
  145. package/dist/lib/http/types.d.ts.map +1 -1
  146. package/dist/lib/send-web-page.d.ts +8 -0
  147. package/dist/lib/send-web-page.d.ts.map +1 -0
  148. package/dist/{output → lib}/send-web-page.js +9 -7
  149. package/dist/lib/send-web-page.js.map +1 -0
  150. package/dist/lib/util/authorization-header.d.ts.map +1 -1
  151. package/dist/lib/util/color.d.ts +32 -0
  152. package/dist/lib/util/color.d.ts.map +1 -0
  153. package/dist/lib/util/color.js +116 -0
  154. package/dist/lib/util/color.js.map +1 -0
  155. package/dist/lib/util/crypto.d.ts +1 -0
  156. package/dist/lib/util/crypto.d.ts.map +1 -1
  157. package/dist/lib/util/crypto.js +8 -3
  158. package/dist/lib/util/crypto.js.map +1 -1
  159. package/dist/lib/util/function.d.ts +1 -0
  160. package/dist/lib/util/function.d.ts.map +1 -1
  161. package/dist/lib/util/function.js +12 -0
  162. package/dist/lib/util/function.js.map +1 -1
  163. package/dist/lib/util/locale.d.ts +20 -0
  164. package/dist/lib/util/locale.d.ts.map +1 -0
  165. package/dist/lib/util/locale.js +14 -0
  166. package/dist/lib/util/locale.js.map +1 -0
  167. package/dist/lib/util/time.d.ts +1 -1
  168. package/dist/lib/util/time.d.ts.map +1 -1
  169. package/dist/lib/util/time.js +1 -1
  170. package/dist/lib/util/time.js.map +1 -1
  171. package/dist/lib/util/type.d.ts +22 -0
  172. package/dist/lib/util/type.d.ts.map +1 -1
  173. package/dist/lib/util/type.js.map +1 -1
  174. package/dist/lib/util/ui8.d.ts +4 -0
  175. package/dist/lib/util/ui8.d.ts.map +1 -0
  176. package/dist/lib/util/ui8.js +17 -0
  177. package/dist/lib/util/ui8.js.map +1 -0
  178. package/dist/lib/util/zod-error.d.ts +2 -0
  179. package/dist/lib/util/zod-error.d.ts.map +1 -0
  180. package/dist/lib/util/zod-error.js +16 -0
  181. package/dist/lib/util/zod-error.js.map +1 -0
  182. package/dist/oauth-errors.d.ts +22 -22
  183. package/dist/oauth-errors.d.ts.map +1 -1
  184. package/dist/oauth-errors.js +37 -45
  185. package/dist/oauth-errors.js.map +1 -1
  186. package/dist/oauth-hooks.d.ts +11 -23
  187. package/dist/oauth-hooks.d.ts.map +1 -1
  188. package/dist/oauth-hooks.js.map +1 -1
  189. package/dist/oauth-middleware.d.ts +12 -0
  190. package/dist/oauth-middleware.d.ts.map +1 -0
  191. package/dist/oauth-middleware.js +32 -0
  192. package/dist/oauth-middleware.js.map +1 -0
  193. package/dist/oauth-provider.d.ts +109 -113
  194. package/dist/oauth-provider.d.ts.map +1 -1
  195. package/dist/oauth-provider.js +124 -542
  196. package/dist/oauth-provider.js.map +1 -1
  197. package/dist/oauth-verifier.d.ts +7 -26
  198. package/dist/oauth-verifier.d.ts.map +1 -1
  199. package/dist/oauth-verifier.js +6 -16
  200. package/dist/oauth-verifier.js.map +1 -1
  201. package/dist/request/code.d.ts.map +1 -1
  202. package/dist/request/request-data.d.ts +2 -4
  203. package/dist/request/request-data.d.ts.map +1 -1
  204. package/dist/request/request-data.js.map +1 -1
  205. package/dist/request/request-manager.d.ts +4 -2
  206. package/dist/request/request-manager.d.ts.map +1 -1
  207. package/dist/request/request-manager.js +9 -8
  208. package/dist/request/request-manager.js.map +1 -1
  209. package/dist/request/request-store.d.ts +6 -0
  210. package/dist/request/request-store.d.ts.map +1 -1
  211. package/dist/request/request-store.js +3 -1
  212. package/dist/request/request-store.js.map +1 -1
  213. package/dist/result/authorization-redirect-parameters.d.ts +18 -0
  214. package/dist/result/authorization-redirect-parameters.d.ts.map +1 -0
  215. package/dist/result/authorization-redirect-parameters.js +3 -0
  216. package/dist/result/authorization-redirect-parameters.js.map +1 -0
  217. package/dist/result/authorization-result-authorize-page.d.ts +13 -0
  218. package/dist/result/authorization-result-authorize-page.d.ts.map +1 -0
  219. package/dist/result/authorization-result-authorize-page.js +3 -0
  220. package/dist/result/authorization-result-authorize-page.js.map +1 -0
  221. package/dist/result/authorization-result-redirect.d.ts +8 -0
  222. package/dist/result/authorization-result-redirect.d.ts.map +1 -0
  223. package/dist/result/authorization-result-redirect.js +3 -0
  224. package/dist/result/authorization-result-redirect.js.map +1 -0
  225. package/dist/router/assets/assets-manifest.d.ts +10 -0
  226. package/dist/router/assets/assets-manifest.d.ts.map +1 -0
  227. package/dist/router/assets/assets-manifest.js +77 -0
  228. package/dist/router/assets/assets-manifest.js.map +1 -0
  229. package/dist/router/assets/assets.d.ts +16 -0
  230. package/dist/router/assets/assets.d.ts.map +1 -0
  231. package/dist/router/assets/assets.js +43 -0
  232. package/dist/router/assets/assets.js.map +1 -0
  233. package/dist/router/assets/csrf.d.ts +4 -0
  234. package/dist/router/assets/csrf.d.ts.map +1 -0
  235. package/dist/router/assets/csrf.js +51 -0
  236. package/dist/router/assets/csrf.js.map +1 -0
  237. package/dist/router/assets/send-account-page.d.ts +7 -0
  238. package/dist/router/assets/send-account-page.d.ts.map +1 -0
  239. package/dist/router/assets/send-account-page.js +34 -0
  240. package/dist/router/assets/send-account-page.js.map +1 -0
  241. package/dist/router/assets/send-authorization-page.d.ts +5 -0
  242. package/dist/router/assets/send-authorization-page.d.ts.map +1 -0
  243. package/dist/router/assets/send-authorization-page.js +49 -0
  244. package/dist/router/assets/send-authorization-page.js.map +1 -0
  245. package/dist/router/assets/send-error-page.d.ts +4 -0
  246. package/dist/router/assets/send-error-page.d.ts.map +1 -0
  247. package/dist/router/assets/send-error-page.js +34 -0
  248. package/dist/router/assets/send-error-page.js.map +1 -0
  249. package/dist/router/create-account-page-middleware.d.ts +6 -0
  250. package/dist/router/create-account-page-middleware.d.ts.map +1 -0
  251. package/dist/router/create-account-page-middleware.js +39 -0
  252. package/dist/router/create-account-page-middleware.js.map +1 -0
  253. package/dist/router/create-api-middleware.d.ts +8 -0
  254. package/dist/router/create-api-middleware.d.ts.map +1 -0
  255. package/dist/router/create-api-middleware.js +501 -0
  256. package/dist/router/create-api-middleware.js.map +1 -0
  257. package/dist/router/create-authorization-page-middleware.d.ts +6 -0
  258. package/dist/router/create-authorization-page-middleware.d.ts.map +1 -0
  259. package/dist/router/create-authorization-page-middleware.js +104 -0
  260. package/dist/router/create-authorization-page-middleware.js.map +1 -0
  261. package/dist/router/create-oauth-middleware.d.ts +6 -0
  262. package/dist/router/create-oauth-middleware.d.ts.map +1 -0
  263. package/dist/router/create-oauth-middleware.js +142 -0
  264. package/dist/router/create-oauth-middleware.js.map +1 -0
  265. package/dist/router/error-handler.d.ts +3 -0
  266. package/dist/router/error-handler.d.ts.map +1 -0
  267. package/dist/{account/account.js → router/error-handler.js} +1 -1
  268. package/dist/router/error-handler.js.map +1 -0
  269. package/dist/router/middleware-options.d.ts +6 -0
  270. package/dist/router/middleware-options.d.ts.map +1 -0
  271. package/dist/router/middleware-options.js +3 -0
  272. package/dist/router/middleware-options.js.map +1 -0
  273. package/dist/router/send-redirect.d.ts +16 -0
  274. package/dist/router/send-redirect.d.ts.map +1 -0
  275. package/dist/{output/send-authorize-redirect.js → router/send-redirect.js} +40 -24
  276. package/dist/router/send-redirect.js.map +1 -0
  277. package/dist/{token/token-claims.d.ts → signer/api-token-payload.d.ts} +237 -232
  278. package/dist/signer/api-token-payload.d.ts.map +1 -0
  279. package/dist/signer/api-token-payload.js +17 -0
  280. package/dist/signer/api-token-payload.js.map +1 -0
  281. package/dist/signer/signed-token-payload.d.ts +164 -159
  282. package/dist/signer/signed-token-payload.d.ts.map +1 -1
  283. package/dist/signer/signed-token-payload.js +10 -16
  284. package/dist/signer/signed-token-payload.js.map +1 -1
  285. package/dist/signer/signer.d.ts +42 -11246
  286. package/dist/signer/signer.d.ts.map +1 -1
  287. package/dist/signer/signer.js +30 -15
  288. package/dist/signer/signer.js.map +1 -1
  289. package/dist/token/refresh-token.d.ts.map +1 -1
  290. package/dist/token/token-data.d.ts +1 -1
  291. package/dist/token/token-data.d.ts.map +1 -1
  292. package/dist/token/token-id.d.ts.map +1 -1
  293. package/dist/token/token-manager.d.ts +28 -26
  294. package/dist/token/token-manager.d.ts.map +1 -1
  295. package/dist/token/token-manager.js +138 -196
  296. package/dist/token/token-manager.js.map +1 -1
  297. package/dist/token/token-store.d.ts +4 -4
  298. package/dist/token/token-store.d.ts.map +1 -1
  299. package/dist/token/token-store.js +1 -0
  300. package/dist/token/token-store.js.map +1 -1
  301. package/dist/token/verify-token-claims.d.ts +3 -3
  302. package/dist/token/verify-token-claims.d.ts.map +1 -1
  303. package/dist/token/verify-token-claims.js +1 -1
  304. package/dist/token/verify-token-claims.js.map +1 -1
  305. package/dist/types/email-otp.d.ts +3 -0
  306. package/dist/types/email-otp.d.ts.map +1 -0
  307. package/dist/types/email-otp.js +6 -0
  308. package/dist/types/email-otp.js.map +1 -0
  309. package/dist/types/email.d.ts +3 -0
  310. package/dist/types/email.d.ts.map +1 -0
  311. package/dist/types/email.js +29 -0
  312. package/dist/types/email.js.map +1 -0
  313. package/dist/types/handle.d.ts +3 -0
  314. package/dist/types/handle.d.ts.map +1 -0
  315. package/dist/types/handle.js +22 -0
  316. package/dist/types/handle.js.map +1 -0
  317. package/dist/types/invite-code.d.ts +4 -0
  318. package/dist/types/invite-code.d.ts.map +1 -0
  319. package/dist/types/invite-code.js +6 -0
  320. package/dist/types/invite-code.js.map +1 -0
  321. package/dist/types/password.d.ts +4 -0
  322. package/dist/types/password.d.ts.map +1 -0
  323. package/dist/types/password.js +7 -0
  324. package/dist/types/password.js.map +1 -0
  325. package/package.json +11 -14
  326. package/src/access-token/access-token-mode.ts +4 -0
  327. package/src/account/account-manager.ts +105 -75
  328. package/src/account/account-store.ts +118 -114
  329. package/src/account/sign-in-data.ts +10 -10
  330. package/src/account/sign-up-input.ts +13 -4
  331. package/src/client/client-manager.ts +34 -2
  332. package/src/client/client-store.ts +1 -1
  333. package/src/constants.ts +6 -1
  334. package/src/customization/branding.ts +12 -0
  335. package/src/customization/build-customization-css.ts +30 -0
  336. package/src/customization/build-customization-data.ts +22 -0
  337. package/src/customization/colors.ts +30 -0
  338. package/src/customization/customization.ts +25 -0
  339. package/src/customization/links.ts +10 -0
  340. package/src/device/device-id.ts +5 -0
  341. package/src/device/device-manager.ts +76 -66
  342. package/src/device/device-store.ts +2 -0
  343. package/src/errors/access-denied-error.ts +24 -17
  344. package/src/{output/build-error-payload.ts → errors/error-parser.ts} +1 -1
  345. package/src/errors/invalid-grant-error.ts +5 -0
  346. package/src/errors/login-required-error.ts +10 -0
  347. package/src/index.ts +1 -0
  348. package/src/lib/html/build-document.ts +6 -4
  349. package/src/{output/backend-data.ts → lib/html/hydration-data.ts} +7 -5
  350. package/src/lib/html/tags.ts +2 -2
  351. package/src/lib/http/accept.ts +3 -3
  352. package/src/lib/http/context.ts +41 -10
  353. package/src/lib/http/headers.ts +15 -0
  354. package/src/lib/http/index.ts +1 -0
  355. package/src/lib/http/middleware.ts +8 -23
  356. package/src/lib/http/request.ts +40 -75
  357. package/src/lib/http/response.ts +39 -15
  358. package/src/lib/http/route.ts +8 -5
  359. package/src/lib/http/router.ts +40 -46
  360. package/src/lib/http/security-headers.ts +1 -1
  361. package/src/lib/http/types.ts +1 -6
  362. package/src/{output → lib}/send-web-page.ts +10 -9
  363. package/src/lib/util/color.ts +132 -0
  364. package/src/lib/util/crypto.ts +9 -4
  365. package/src/lib/util/function.ts +14 -0
  366. package/src/lib/util/locale.ts +18 -0
  367. package/src/lib/util/time.ts +3 -4
  368. package/src/lib/util/type.ts +24 -0
  369. package/src/lib/util/ui8.ts +14 -0
  370. package/src/lib/util/zod-error.ts +14 -0
  371. package/src/oauth-errors.ts +22 -22
  372. package/src/oauth-hooks.ts +11 -24
  373. package/src/oauth-middleware.ts +53 -0
  374. package/src/oauth-provider.ts +290 -1061
  375. package/src/oauth-verifier.ts +9 -55
  376. package/src/request/request-data.ts +5 -4
  377. package/src/request/request-manager.ts +11 -11
  378. package/src/request/request-store.ts +7 -0
  379. package/src/result/authorization-redirect-parameters.ts +24 -0
  380. package/src/result/authorization-result-authorize-page.ts +14 -0
  381. package/src/result/authorization-result-redirect.ts +8 -0
  382. package/src/router/assets/assets-manifest.ts +115 -0
  383. package/src/router/assets/assets.ts +54 -0
  384. package/src/router/assets/csrf.ts +63 -0
  385. package/src/router/assets/send-account-page.ts +43 -0
  386. package/src/router/assets/send-authorization-page.ts +62 -0
  387. package/src/router/assets/send-error-page.ts +42 -0
  388. package/src/router/create-account-page-middleware.ts +69 -0
  389. package/src/router/create-api-middleware.ts +814 -0
  390. package/src/router/create-authorization-page-middleware.ts +173 -0
  391. package/src/router/create-oauth-middleware.ts +247 -0
  392. package/src/router/error-handler.ts +6 -0
  393. package/src/router/middleware-options.ts +9 -0
  394. package/src/router/send-redirect.ts +142 -0
  395. package/src/signer/api-token-payload.ts +18 -0
  396. package/src/signer/signed-token-payload.ts +18 -28
  397. package/src/signer/signer.ts +49 -34
  398. package/src/token/token-data.ts +1 -1
  399. package/src/token/token-manager.ts +190 -239
  400. package/src/token/token-store.ts +6 -4
  401. package/src/token/verify-token-claims.ts +4 -4
  402. package/src/types/email-otp.ts +3 -0
  403. package/src/types/email.ts +26 -0
  404. package/src/types/handle.ts +18 -0
  405. package/src/types/invite-code.ts +4 -0
  406. package/src/types/password.ts +4 -0
  407. package/tsconfig.build.tsbuildinfo +1 -0
  408. package/tsconfig.json +1 -1
  409. package/dist/access-token/access-token-type.d.ts +0 -6
  410. package/dist/access-token/access-token-type.d.ts.map +0 -1
  411. package/dist/access-token/access-token-type.js +0 -10
  412. package/dist/access-token/access-token-type.js.map +0 -1
  413. package/dist/account/account.d.ts +0 -2
  414. package/dist/account/account.d.ts.map +0 -1
  415. package/dist/account/account.js.map +0 -1
  416. package/dist/assets/assets-middleware.d.ts +0 -5
  417. package/dist/assets/assets-middleware.d.ts.map +0 -1
  418. package/dist/assets/assets-middleware.js +0 -41
  419. package/dist/assets/assets-middleware.js.map +0 -1
  420. package/dist/lib/locale.d.ts +0 -15
  421. package/dist/lib/locale.d.ts.map +0 -1
  422. package/dist/lib/locale.js +0 -17
  423. package/dist/lib/locale.js.map +0 -1
  424. package/dist/output/backend-data.d.ts +0 -4
  425. package/dist/output/backend-data.d.ts.map +0 -1
  426. package/dist/output/backend-data.js.map +0 -1
  427. package/dist/output/build-authorize-data.d.ts +0 -29
  428. package/dist/output/build-authorize-data.d.ts.map +0 -1
  429. package/dist/output/build-authorize-data.js +0 -21
  430. package/dist/output/build-authorize-data.js.map +0 -1
  431. package/dist/output/build-customization-data.d.ts +0 -234
  432. package/dist/output/build-customization-data.d.ts.map +0 -1
  433. package/dist/output/build-customization-data.js +0 -174
  434. package/dist/output/build-customization-data.js.map +0 -1
  435. package/dist/output/build-error-data.d.ts +0 -3
  436. package/dist/output/build-error-data.d.ts.map +0 -1
  437. package/dist/output/build-error-data.js +0 -10
  438. package/dist/output/build-error-data.js.map +0 -1
  439. package/dist/output/build-error-payload.d.ts.map +0 -1
  440. package/dist/output/build-error-payload.js.map +0 -1
  441. package/dist/output/output-manager.d.ts +0 -28
  442. package/dist/output/output-manager.d.ts.map +0 -1
  443. package/dist/output/output-manager.js +0 -134
  444. package/dist/output/output-manager.js.map +0 -1
  445. package/dist/output/send-authorize-redirect.d.ts +0 -25
  446. package/dist/output/send-authorize-redirect.d.ts.map +0 -1
  447. package/dist/output/send-authorize-redirect.js.map +0 -1
  448. package/dist/output/send-web-page.d.ts +0 -8
  449. package/dist/output/send-web-page.d.ts.map +0 -1
  450. package/dist/output/send-web-page.js.map +0 -1
  451. package/dist/token/token-claims.d.ts.map +0 -1
  452. package/dist/token/token-claims.js +0 -27
  453. package/dist/token/token-claims.js.map +0 -1
  454. package/src/access-token/access-token-type.ts +0 -5
  455. package/src/account/account.ts +0 -1
  456. package/src/assets/assets-middleware.ts +0 -44
  457. package/src/lib/locale.ts +0 -21
  458. package/src/output/build-authorize-data.ts +0 -53
  459. package/src/output/build-customization-data.ts +0 -217
  460. package/src/output/build-error-data.ts +0 -8
  461. package/src/output/output-manager.ts +0 -188
  462. package/src/output/send-authorize-redirect.ts +0 -137
  463. package/src/token/token-claims.ts +0 -30
  464. package/tsconfig.backend.tsbuildinfo +0 -1
  465. /package/{tsconfig.backend.json → tsconfig.build.json} +0 -0
@@ -1,5 +1,6 @@
1
1
  import { createHash } from 'node:crypto'
2
- import { isSignedJwt } from '@atproto/jwk'
2
+ import { SignedJwt, isSignedJwt } from '@atproto/jwk'
3
+ import type { Account } from '@atproto/oauth-provider-api'
3
4
  import {
4
5
  CLIENT_ASSERTION_TYPE_JWT_BEARER,
5
6
  OAuthAccessToken,
@@ -11,9 +12,7 @@ import {
11
12
  OAuthTokenResponse,
12
13
  OAuthTokenType,
13
14
  } from '@atproto/oauth-types'
14
- import { AccessTokenType } from '../access-token/access-token-type.js'
15
- import { DeviceAccountInfo } from '../account/account-store.js'
16
- import { Account } from '../account/account.js'
15
+ import { AccessTokenMode } from '../access-token/access-token-mode.js'
17
16
  import { ClientAuth } from '../client/client-auth.js'
18
17
  import { Client } from '../client/client.js'
19
18
  import {
@@ -33,21 +32,18 @@ import { RequestMetadata } from '../lib/http/request.js'
33
32
  import { dateToEpoch, dateToRelativeSeconds } from '../lib/util/date.js'
34
33
  import { callAsync } from '../lib/util/function.js'
35
34
  import { OAuthHooks } from '../oauth-hooks.js'
35
+ import { Sub } from '../oidc/sub.js'
36
36
  import { Code, isCode } from '../request/code.js'
37
+ import { SignedTokenPayload } from '../signer/signed-token-payload.js'
37
38
  import { Signer } from '../signer/signer.js'
38
39
  import {
40
+ RefreshToken,
39
41
  generateRefreshToken,
40
42
  isRefreshToken,
41
43
  refreshTokenSchema,
42
44
  } from './refresh-token.js'
43
- import { TokenClaims } from './token-claims.js'
44
45
  import { TokenData } from './token-data.js'
45
- import {
46
- TokenId,
47
- generateTokenId,
48
- isTokenId,
49
- tokenIdSchema,
50
- } from './token-id.js'
46
+ import { TokenId, generateTokenId, isTokenId } from './token-id.js'
51
47
  import { TokenInfo, TokenStore } from './token-store.js'
52
48
  import {
53
49
  VerifyTokenClaimsOptions,
@@ -55,16 +51,15 @@ import {
55
51
  verifyTokenClaims,
56
52
  } from './verify-token-claims.js'
57
53
 
58
- export type AuthenticateTokenIdResult = VerifyTokenClaimsResult & {
59
- tokenInfo: TokenInfo
60
- }
54
+ export { AccessTokenMode, Signer }
55
+ export type { OAuthHooks, TokenStore, VerifyTokenClaimsResult }
61
56
 
62
57
  export class TokenManager {
63
58
  constructor(
64
59
  protected readonly store: TokenStore,
65
60
  protected readonly signer: Signer,
66
61
  protected readonly hooks: OAuthHooks,
67
- protected readonly accessTokenType: AccessTokenType,
62
+ protected readonly accessTokenMode: AccessTokenMode,
68
63
  protected readonly tokenMaxAge = TOKEN_MAX_AGE,
69
64
  ) {}
70
65
 
@@ -72,12 +67,30 @@ export class TokenManager {
72
67
  return new Date(now.getTime() + this.tokenMaxAge)
73
68
  }
74
69
 
75
- protected useJwtAccessToken(account: Account) {
76
- if (this.accessTokenType === AccessTokenType.auto) {
77
- return this.signer.issuer !== account.aud
78
- }
70
+ protected async buildAccessToken(
71
+ tokenId: TokenId,
72
+ account: Account,
73
+ client: Client,
74
+ parameters: OAuthAuthorizationRequestParameters,
75
+ options: {
76
+ now: Date
77
+ expiresAt: Date
78
+ },
79
+ ): Promise<OAuthAccessToken> {
80
+ return this.signer.createAccessToken({
81
+ jti: tokenId,
82
+ sub: account.sub,
83
+ exp: dateToEpoch(options.expiresAt),
84
+ iat: dateToEpoch(options.now),
85
+ cnf: parameters.dpop_jkt ? { jkt: parameters.dpop_jkt } : undefined,
79
86
 
80
- return this.accessTokenType === AccessTokenType.jwt
87
+ ...(this.accessTokenMode === AccessTokenMode.stateless && {
88
+ aud: account.aud,
89
+ scope: parameters.scope,
90
+ // https://datatracker.ietf.org/doc/html/rfc8693#section-4.3
91
+ client_id: client.id,
92
+ }),
93
+ })
81
94
  }
82
95
 
83
96
  async create(
@@ -85,7 +98,7 @@ export class TokenManager {
85
98
  clientAuth: ClientAuth,
86
99
  clientMetadata: RequestMetadata,
87
100
  account: Account,
88
- device: null | { id: DeviceId; info: DeviceAccountInfo },
101
+ deviceId: null | DeviceId,
89
102
  parameters: OAuthAuthorizationRequestParameters,
90
103
  input:
91
104
  | OAuthAuthorizationCodeGrantTokenRequest
@@ -132,9 +145,11 @@ export class TokenManager {
132
145
  throw new InvalidGrantError('Invalid code')
133
146
  }
134
147
 
148
+ // @NOTE not using `this.findByCode` because we want to delete the token
149
+ // if it still exists (rather than throwing if the code is invalid).
135
150
  const tokenInfo = await this.store.findTokenByCode(input.code)
136
151
  if (tokenInfo) {
137
- await this.store.deleteToken(tokenInfo.id)
152
+ await this.deleteToken(tokenInfo.id)
138
153
  throw new InvalidGrantError(`Code replayed`)
139
154
  }
140
155
 
@@ -184,11 +199,6 @@ export class TokenManager {
184
199
  )
185
200
  }
186
201
 
187
- if (!device) {
188
- // Fool-proofing (authorization_code grant should always have a device)
189
- throw new InvalidRequestError('consent was not given for this device')
190
- }
191
-
192
202
  break
193
203
  }
194
204
 
@@ -209,47 +219,29 @@ export class TokenManager {
209
219
  const now = new Date()
210
220
  const expiresAt = this.createTokenExpiry(now)
211
221
 
212
- const authorizationDetails = await callAsync(
213
- this.hooks.getAuthorizationDetails,
214
- {
215
- client,
216
- clientAuth,
217
- clientMetadata,
218
- parameters,
219
- account,
220
- },
221
- )
222
-
223
222
  const tokenData: TokenData = {
224
223
  createdAt: now,
225
224
  updatedAt: now,
226
225
  expiresAt,
227
226
  clientId: client.id,
228
227
  clientAuth,
229
- deviceId: device?.id ?? null,
228
+ deviceId,
230
229
  sub: account.sub,
231
230
  parameters,
232
- details: authorizationDetails ?? null,
231
+ details: null,
233
232
  code,
234
233
  }
235
234
 
236
235
  await this.store.createToken(tokenId, tokenData, refreshToken)
237
236
 
238
237
  try {
239
- const accessToken: OAuthAccessToken = !this.useJwtAccessToken(account)
240
- ? tokenId
241
- : await this.signer.accessToken(client, parameters, {
242
- // We don't specify the alg here. We suppose the Resource server will be
243
- // able to verify the token using any alg.
244
- aud: account.aud,
245
- sub: account.sub,
246
- alg: undefined,
247
- exp: expiresAt,
248
- iat: now,
249
- jti: tokenId,
250
- cnf: parameters.dpop_jkt ? { jkt: parameters.dpop_jkt } : undefined,
251
- authorization_details: authorizationDetails,
252
- })
238
+ const accessToken = await this.buildAccessToken(
239
+ tokenId,
240
+ account,
241
+ client,
242
+ parameters,
243
+ { now, expiresAt },
244
+ )
253
245
 
254
246
  const response = await this.buildTokenResponse(
255
247
  client,
@@ -257,8 +249,7 @@ export class TokenManager {
257
249
  refreshToken,
258
250
  expiresAt,
259
251
  parameters,
260
- account,
261
- authorizationDetails,
252
+ account.sub,
262
253
  )
263
254
 
264
255
  await callAsync(this.hooks.onTokenCreated, {
@@ -267,33 +258,33 @@ export class TokenManager {
267
258
  clientMetadata,
268
259
  account,
269
260
  parameters,
270
- deviceId: device ? device.id : null,
271
261
  })
272
262
 
273
263
  return response
274
264
  } catch (err) {
275
265
  // Just in case the token could not be issued, we delete it from the store
276
- await this.store.deleteToken(tokenId)
266
+ await this.deleteToken(tokenId)
277
267
 
278
268
  throw err
279
269
  }
280
270
  }
281
271
 
282
- protected async buildTokenResponse(
272
+ protected buildTokenResponse(
283
273
  client: Client,
284
274
  accessToken: OAuthAccessToken,
285
275
  refreshToken: string | undefined,
286
276
  expiresAt: Date,
287
277
  parameters: OAuthAuthorizationRequestParameters,
288
- account: Account,
289
- authorizationDetails: null | any,
290
- ): Promise<OAuthTokenResponse> {
291
- const tokenResponse: OAuthTokenResponse = {
278
+ sub: Sub,
279
+ ): OAuthTokenResponse {
280
+ return {
292
281
  access_token: accessToken,
293
282
  token_type: parameters.dpop_jkt ? 'DPoP' : 'Bearer',
294
283
  refresh_token: refreshToken,
295
284
  scope: parameters.scope,
296
- authorization_details: authorizationDetails,
285
+
286
+ // @NOTE using a getter so that the value gets computed when the JSON
287
+ // response is generated, allowing to value to be as accurate as possible.
297
288
  get expires_in() {
298
289
  return dateToRelativeSeconds(expiresAt)
299
290
  },
@@ -301,13 +292,11 @@ export class TokenManager {
301
292
  // ATPROTO extension: add the sub claim to the token response to allow
302
293
  // clients to resolve the PDS url (audience) using the did resolution
303
294
  // mechanism.
304
- sub: account.sub,
295
+ sub,
305
296
  }
306
-
307
- return tokenResponse
308
297
  }
309
298
 
310
- protected async validateAccess(
299
+ public async validateAccess(
311
300
  client: Client,
312
301
  clientAuth: ClientAuth,
313
302
  tokenInfo: TokenInfo,
@@ -316,10 +305,6 @@ export class TokenManager {
316
305
  throw new InvalidGrantError(`Token was not issued to this client`)
317
306
  }
318
307
 
319
- if (tokenInfo.info?.authorizedClients.includes(client.id) === false) {
320
- throw new InvalidGrantError(`Client no longer trusted by user`)
321
- }
322
-
323
308
  if (tokenInfo.data.clientAuth.method !== clientAuth.method) {
324
309
  throw new InvalidGrantError(`Client authentication method mismatch`)
325
310
  }
@@ -329,6 +314,34 @@ export class TokenManager {
329
314
  }
330
315
  }
331
316
 
317
+ public async validateRefresh(
318
+ client: Client,
319
+ clientAuth: ClientAuth,
320
+ { data }: TokenInfo,
321
+ ): Promise<void> {
322
+ // @TODO This value should be computable even if we don't have the "client"
323
+ // (because fetching client info could be flaky). Instead, all the info
324
+ // needed should be stored in the token info.
325
+ const allowLongerLifespan =
326
+ client.info.isFirstParty || data.clientAuth.method !== 'none'
327
+
328
+ const lifetime = allowLongerLifespan
329
+ ? AUTHENTICATED_REFRESH_LIFETIME
330
+ : UNAUTHENTICATED_REFRESH_LIFETIME
331
+
332
+ if (data.createdAt.getTime() + lifetime < Date.now()) {
333
+ throw new InvalidGrantError(`Refresh token expired`)
334
+ }
335
+
336
+ const inactivityTimeout = allowLongerLifespan
337
+ ? AUTHENTICATED_REFRESH_INACTIVITY_TIMEOUT
338
+ : UNAUTHENTICATED_REFRESH_INACTIVITY_TIMEOUT
339
+
340
+ if (data.updatedAt.getTime() + inactivityTimeout < Date.now()) {
341
+ throw new InvalidGrantError(`Refresh token exceeded inactivity timeout`)
342
+ }
343
+ }
344
+
332
345
  async refresh(
333
346
  client: Client,
334
347
  clientAuth: ClientAuth,
@@ -342,25 +355,23 @@ export class TokenManager {
342
355
  }
343
356
  const refreshToken = refreshTokenParsed.data
344
357
 
345
- const tokenInfo = await this.store.findTokenByRefreshToken(refreshToken)
346
- if (!tokenInfo?.currentRefreshToken) {
347
- throw new InvalidGrantError(`Invalid refresh token`)
348
- }
358
+ const tokenInfo = await this.findByRefreshToken(refreshToken).catch(
359
+ (err) => {
360
+ throw InvalidGrantError.from(
361
+ err,
362
+ err instanceof InvalidRequestError
363
+ ? err.error_description
364
+ : 'Invalid refresh token',
365
+ )
366
+ },
367
+ )
349
368
 
350
369
  const { account, data } = tokenInfo
351
370
  const { parameters } = data
352
371
 
353
372
  try {
354
- if (tokenInfo.currentRefreshToken !== refreshToken) {
355
- throw new InvalidGrantError(`refresh token replayed`)
356
- }
357
-
358
373
  await this.validateAccess(client, clientAuth, tokenInfo)
359
-
360
- if (input.grant_type !== 'refresh_token') {
361
- // Fool-proofing (should never happen)
362
- throw new InvalidGrantError(`Invalid grant type`)
363
- }
374
+ await this.validateRefresh(client, clientAuth, tokenInfo)
364
375
 
365
376
  if (!client.metadata.grant_types.includes(input.grant_type)) {
366
377
  // In case the client metadata was updated after the token was issued
@@ -377,34 +388,6 @@ export class TokenManager {
377
388
  }
378
389
  }
379
390
 
380
- const lastActivity = data.updatedAt
381
- const inactivityTimeout =
382
- clientAuth.method === 'none' && !client.info.isFirstParty
383
- ? UNAUTHENTICATED_REFRESH_INACTIVITY_TIMEOUT
384
- : AUTHENTICATED_REFRESH_INACTIVITY_TIMEOUT
385
- if (lastActivity.getTime() + inactivityTimeout < Date.now()) {
386
- throw new InvalidGrantError(`Refresh token exceeded inactivity timeout`)
387
- }
388
-
389
- const lifetime =
390
- clientAuth.method === 'none' && !client.info.isFirstParty
391
- ? UNAUTHENTICATED_REFRESH_LIFETIME
392
- : AUTHENTICATED_REFRESH_LIFETIME
393
- if (data.createdAt.getTime() + lifetime < Date.now()) {
394
- throw new InvalidGrantError(`Refresh token expired`)
395
- }
396
-
397
- const authorizationDetails = await callAsync(
398
- this.hooks.getAuthorizationDetails,
399
- {
400
- client,
401
- clientAuth,
402
- clientMetadata,
403
- parameters,
404
- account,
405
- },
406
- )
407
-
408
391
  const nextTokenId = await generateTokenId()
409
392
  const nextRefreshToken = await generateRefreshToken()
410
393
 
@@ -434,20 +417,13 @@ export class TokenManager {
434
417
  },
435
418
  )
436
419
 
437
- const accessToken: OAuthAccessToken = !this.useJwtAccessToken(account)
438
- ? nextTokenId
439
- : await this.signer.accessToken(client, parameters, {
440
- // We don't specify the alg here. We suppose the Resource server will be
441
- // able to verify the token using any alg.
442
- aud: account.aud,
443
- sub: account.sub,
444
- alg: undefined,
445
- exp: expiresAt,
446
- iat: now,
447
- jti: nextTokenId,
448
- cnf: parameters.dpop_jkt ? { jkt: parameters.dpop_jkt } : undefined,
449
- authorization_details: authorizationDetails,
450
- })
420
+ const accessToken = await this.buildAccessToken(
421
+ nextTokenId,
422
+ account,
423
+ client,
424
+ parameters,
425
+ { now, expiresAt },
426
+ )
451
427
 
452
428
  const response = await this.buildTokenResponse(
453
429
  client,
@@ -455,8 +431,7 @@ export class TokenManager {
455
431
  nextRefreshToken,
456
432
  expiresAt,
457
433
  parameters,
458
- account,
459
- authorizationDetails,
434
+ account.sub,
460
435
  )
461
436
 
462
437
  await callAsync(this.hooks.onTokenRefreshed, {
@@ -465,170 +440,146 @@ export class TokenManager {
465
440
  clientMetadata,
466
441
  account,
467
442
  parameters,
468
- deviceId: tokenInfo.data.deviceId,
469
443
  })
470
444
 
471
445
  return response
472
446
  } catch (err) {
473
447
  // Just in case the token could not be refreshed, we delete it from the store
474
- await this.store.deleteToken(tokenInfo.id)
448
+ await this.deleteToken(tokenInfo.id)
475
449
 
476
450
  throw err
477
451
  }
478
452
  }
479
453
 
480
454
  /**
481
- * @see {@link https://datatracker.ietf.org/doc/html/rfc7009#section-2.2 | RFC7009 Section 2.2}
455
+ * @note The token validity is not guaranteed. The caller must ensure that the
456
+ * token is valid before using the returned token info.
482
457
  */
483
- async revoke(token: string): Promise<void> {
484
- switch (true) {
485
- case isTokenId(token): {
486
- await this.store.deleteToken(token)
487
- return
488
- }
489
-
490
- case isSignedJwt(token): {
491
- const { payload } = await this.signer.verify(token, {
492
- clockTolerance: Infinity,
493
- requiredClaims: ['jti'],
494
- })
495
- const tokenId = tokenIdSchema.parse(payload.jti)
496
- await this.store.deleteToken(tokenId)
497
- return
498
- }
458
+ public async findToken(token: string): Promise<TokenInfo> {
459
+ if (isTokenId(token)) {
460
+ return this.getTokenInfo(token)
461
+ } else if (isCode(token)) {
462
+ return this.findByCode(token)
463
+ } else if (isRefreshToken(token)) {
464
+ return this.findByRefreshToken(token)
465
+ } else if (isSignedJwt(token)) {
466
+ return this.findBySignedJwt(token)
467
+ } else {
468
+ throw new InvalidRequestError(`Invalid token`)
469
+ }
470
+ }
499
471
 
500
- case isRefreshToken(token): {
501
- const tokenInfo = await this.store.findTokenByRefreshToken(token)
502
- if (tokenInfo) await this.store.deleteToken(tokenInfo.id)
503
- return
504
- }
472
+ public async findBySignedJwt(token: SignedJwt): Promise<TokenInfo> {
473
+ const { payload } = await this.signer.verifyAccessToken(token, {
474
+ clockTolerance: Infinity,
475
+ })
505
476
 
506
- case isCode(token): {
507
- const tokenInfo = await this.store.findTokenByCode(token)
508
- if (tokenInfo) await this.store.deleteToken(tokenInfo.id)
509
- return
510
- }
477
+ const tokenInfo = await this.getTokenInfo(payload.jti)
511
478
 
512
- default:
513
- // No error should be returned if the token is not valid
514
- return
479
+ // Fool-proof: Invalid store implementation ?
480
+ if (payload.sub !== tokenInfo.account.sub) {
481
+ await this.deleteToken(tokenInfo.id)
482
+ throw new Error(
483
+ `Account sub (${tokenInfo.account.sub}) does not match token sub (${payload.sub})`,
484
+ )
515
485
  }
486
+
487
+ return tokenInfo
516
488
  }
517
489
 
518
- /**
519
- * Allows an (authenticated) client to obtain information about a token.
520
- *
521
- * @see {@link https://datatracker.ietf.org/doc/html/rfc7662 RFC7662}
522
- */
523
- async clientTokenInfo(
524
- client: Client,
525
- clientAuth: ClientAuth,
526
- token: string,
527
- ): Promise<TokenInfo> {
528
- const tokenInfo = await this.findTokenInfo(token)
490
+ public async findByRefreshToken(token: RefreshToken): Promise<TokenInfo> {
491
+ const tokenInfo = await this.store.findTokenByRefreshToken(token)
492
+
529
493
  if (!tokenInfo) {
530
- throw new InvalidGrantError(`Invalid token`)
494
+ throw new InvalidRequestError(`Invalid refresh token`)
531
495
  }
532
496
 
533
- try {
534
- await this.validateAccess(client, clientAuth, tokenInfo)
535
- } catch (err) {
536
- await this.store.deleteToken(tokenInfo.id)
537
- throw err
538
- }
497
+ if (tokenInfo.currentRefreshToken !== token) {
498
+ await this.deleteToken(tokenInfo.id)
539
499
 
540
- if (tokenInfo.data.expiresAt.getTime() < Date.now()) {
541
- throw new InvalidGrantError(`Token expired`)
500
+ throw new InvalidRequestError(`Refresh token replayed`)
542
501
  }
543
502
 
544
503
  return tokenInfo
545
504
  }
546
505
 
547
- protected async findTokenInfo(token: string): Promise<TokenInfo | null> {
548
- switch (true) {
549
- case isTokenId(token):
550
- return this.store.readToken(token)
506
+ public async findByCode(code: Code): Promise<TokenInfo> {
507
+ const tokenInfo = await this.store.findTokenByCode(code)
551
508
 
552
- case isSignedJwt(token): {
553
- const { payload } = await this.signer
554
- .verifyAccessToken(token)
555
- .catch((_) => ({ payload: null }))
556
- if (!payload) return null
557
-
558
- const tokenInfo = await this.store.readToken(payload.jti)
559
- if (!tokenInfo) return null
560
-
561
- // Audience changed (e.g. user was moved to another resource server)
562
- if (payload.aud !== tokenInfo.account.aud) {
563
- return null
564
- }
565
-
566
- // Invalid store implementation ?
567
- if (payload.sub !== tokenInfo.account.sub) {
568
- throw new Error(
569
- `Account sub (${tokenInfo.account.sub}) does not match token sub (${payload.sub})`,
570
- )
571
- }
572
-
573
- return tokenInfo
574
- }
509
+ if (!tokenInfo) {
510
+ throw new InvalidRequestError(`Invalid code`)
511
+ }
575
512
 
576
- case isRefreshToken(token): {
577
- const tokenInfo = await this.store.findTokenByRefreshToken(token)
578
- if (!tokenInfo?.currentRefreshToken) return null
579
- if (tokenInfo.currentRefreshToken !== token) return null
580
- return tokenInfo
581
- }
513
+ return tokenInfo
514
+ }
582
515
 
583
- default:
584
- // Should never happen
585
- return null
586
- }
516
+ public async deleteToken(tokenId: TokenId): Promise<void> {
517
+ return this.store.deleteToken(tokenId)
587
518
  }
588
519
 
589
- async getTokenInfo(tokenType: OAuthTokenType, tokenId: TokenId) {
520
+ async getTokenInfo(tokenId: TokenId): Promise<TokenInfo> {
590
521
  const tokenInfo = await this.store.readToken(tokenId)
591
522
 
592
523
  if (!tokenInfo) {
593
- throw new InvalidTokenError(tokenType, `Invalid token`)
594
- }
595
-
596
- if (!(tokenInfo.data.expiresAt.getTime() > Date.now())) {
597
- throw new InvalidTokenError(tokenType, `Token expired`)
524
+ throw new InvalidRequestError(`Invalid token`)
598
525
  }
599
526
 
600
527
  return tokenInfo
601
528
  }
602
529
 
603
- async authenticateTokenId(
530
+ async verifyToken(
531
+ token: OAuthAccessToken,
604
532
  tokenType: OAuthTokenType,
605
- token: TokenId,
533
+ tokenId: TokenId,
606
534
  dpopJkt: string | null,
607
535
  verifyOptions?: VerifyTokenClaimsOptions,
608
- ): Promise<AuthenticateTokenIdResult> {
609
- const tokenInfo = await this.getTokenInfo(tokenType, token)
610
- const { parameters } = tokenInfo.data
536
+ ): Promise<VerifyTokenClaimsResult> {
537
+ const tokenInfo = await this.getTokenInfo(tokenId).catch((err) => {
538
+ throw InvalidTokenError.from(err, tokenType)
539
+ })
540
+
541
+ if (isCurrentTokenExpired(tokenInfo)) {
542
+ await this.deleteToken(tokenId)
543
+ throw new InvalidTokenError(tokenType, `Token expired`)
544
+ }
545
+
546
+ const { account, data } = tokenInfo
547
+ const { parameters } = data
611
548
 
612
549
  // Construct a list of claim, as if the token was a JWT.
613
- const claims: TokenClaims = {
614
- aud: tokenInfo.account.aud,
615
- sub: tokenInfo.account.sub,
616
- exp: dateToEpoch(tokenInfo.data.expiresAt),
617
- iat: dateToEpoch(tokenInfo.data.updatedAt),
618
- scope: tokenInfo.data.parameters.scope,
619
- client_id: tokenInfo.data.clientId,
550
+ const claims: SignedTokenPayload = {
551
+ iss: this.signer.issuer,
552
+ jti: tokenId,
553
+ sub: account.sub,
554
+ exp: dateToEpoch(data.expiresAt),
555
+ iat: dateToEpoch(data.updatedAt),
620
556
  cnf: parameters.dpop_jkt ? { jkt: parameters.dpop_jkt } : undefined,
557
+
558
+ // These are not stored in the JWT access token in "light" access token
559
+ // mode. See `buildAccessToken`.
560
+ aud: account.aud,
561
+ scope: parameters.scope,
562
+ client_id: data.clientId,
621
563
  }
622
564
 
623
- const result = verifyTokenClaims(
624
- token,
565
+ return verifyTokenClaims(
625
566
  token,
567
+ tokenId,
626
568
  tokenType,
627
569
  dpopJkt,
628
570
  claims,
629
571
  verifyOptions,
630
572
  )
573
+ }
631
574
 
632
- return { ...result, tokenInfo }
575
+ async listAccountTokens(sub: Sub): Promise<TokenInfo[]> {
576
+ const results = await this.store.listAccountTokens(sub)
577
+ return results
578
+ .filter((tokenInfo) => tokenInfo.account.sub === sub) // Fool proof
579
+ .filter((tokenInfo) => !isCurrentTokenExpired(tokenInfo))
633
580
  }
634
581
  }
582
+
583
+ function isCurrentTokenExpired(tokenInfo: TokenInfo): boolean {
584
+ return tokenInfo.data.expiresAt.getTime() < Date.now()
585
+ }