@atproto/oauth-provider 0.16.5 → 0.17.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 (321) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/dist/access-token/access-token-mode.js +2 -5
  3. package/dist/access-token/access-token-mode.js.map +1 -1
  4. package/dist/account/account-manager.js +25 -33
  5. package/dist/account/account-manager.js.map +1 -1
  6. package/dist/account/account-store.js +11 -32
  7. package/dist/account/account-store.js.map +1 -1
  8. package/dist/account/sign-in-data.js +9 -12
  9. package/dist/account/sign-in-data.js.map +1 -1
  10. package/dist/account/sign-up-input.js +14 -17
  11. package/dist/account/sign-up-input.js.map +1 -1
  12. package/dist/client/client-auth.js +1 -2
  13. package/dist/client/client-data.js +1 -2
  14. package/dist/client/client-id.js +2 -5
  15. package/dist/client/client-id.js.map +1 -1
  16. package/dist/client/client-info.js +1 -2
  17. package/dist/client/client-manager.js +86 -97
  18. package/dist/client/client-manager.js.map +1 -1
  19. package/dist/client/client-store.js +7 -26
  20. package/dist/client/client-store.js.map +1 -1
  21. package/dist/client/client-utils.js +10 -14
  22. package/dist/client/client-utils.js.map +1 -1
  23. package/dist/client/client.js +43 -53
  24. package/dist/client/client.js.map +1 -1
  25. package/dist/constants.js +28 -31
  26. package/dist/constants.js.map +1 -1
  27. package/dist/customization/branding.js +8 -11
  28. package/dist/customization/branding.js.map +1 -1
  29. package/dist/customization/build-customization-css.js +8 -11
  30. package/dist/customization/build-customization-css.js.map +1 -1
  31. package/dist/customization/build-customization-data.js +1 -4
  32. package/dist/customization/build-customization-data.js.map +1 -1
  33. package/dist/customization/colors.js +11 -14
  34. package/dist/customization/colors.js.map +1 -1
  35. package/dist/customization/customization.js +8 -11
  36. package/dist/customization/customization.js.map +1 -1
  37. package/dist/customization/links.js +7 -10
  38. package/dist/customization/links.js.map +1 -1
  39. package/dist/device/device-data.js +7 -10
  40. package/dist/device/device-data.js.map +1 -1
  41. package/dist/device/device-id.js +11 -16
  42. package/dist/device/device-id.js.map +1 -1
  43. package/dist/device/device-manager.js +32 -38
  44. package/dist/device/device-manager.js.map +1 -1
  45. package/dist/device/device-store.js +7 -25
  46. package/dist/device/device-store.js.map +1 -1
  47. package/dist/device/session-id.js +9 -13
  48. package/dist/device/session-id.js.map +1 -1
  49. package/dist/dpop/dpop-manager.d.ts +3 -3
  50. package/dist/dpop/dpop-manager.js +38 -43
  51. package/dist/dpop/dpop-manager.js.map +1 -1
  52. package/dist/dpop/dpop-nonce.d.ts +2 -2
  53. package/dist/dpop/dpop-nonce.d.ts.map +1 -1
  54. package/dist/dpop/dpop-nonce.js +14 -18
  55. package/dist/dpop/dpop-nonce.js.map +1 -1
  56. package/dist/dpop/dpop-proof.js +1 -2
  57. package/dist/errors/access-denied-error.js +2 -6
  58. package/dist/errors/access-denied-error.js.map +1 -1
  59. package/dist/errors/account-selection-required-error.js +2 -6
  60. package/dist/errors/account-selection-required-error.js.map +1 -1
  61. package/dist/errors/authorization-error.js +7 -12
  62. package/dist/errors/authorization-error.js.map +1 -1
  63. package/dist/errors/consent-required-error.js +2 -6
  64. package/dist/errors/consent-required-error.js.map +1 -1
  65. package/dist/errors/error-parser.js +14 -18
  66. package/dist/errors/error-parser.js.map +1 -1
  67. package/dist/errors/handle-unavailable-error.js +2 -7
  68. package/dist/errors/handle-unavailable-error.js.map +1 -1
  69. package/dist/errors/invalid-authorization-details-error.js +2 -6
  70. package/dist/errors/invalid-authorization-details-error.js.map +1 -1
  71. package/dist/errors/invalid-client-error.js +2 -6
  72. package/dist/errors/invalid-client-error.js.map +1 -1
  73. package/dist/errors/invalid-client-id-error.js +2 -6
  74. package/dist/errors/invalid-client-id-error.js.map +1 -1
  75. package/dist/errors/invalid-client-metadata-error.js +7 -11
  76. package/dist/errors/invalid-client-metadata-error.js.map +1 -1
  77. package/dist/errors/invalid-credentials-error.js +2 -7
  78. package/dist/errors/invalid-credentials-error.js.map +1 -1
  79. package/dist/errors/invalid-dpop-key-binding-error.js +2 -6
  80. package/dist/errors/invalid-dpop-key-binding-error.js.map +1 -1
  81. package/dist/errors/invalid-dpop-proof-error.js +2 -6
  82. package/dist/errors/invalid-dpop-proof-error.js.map +1 -1
  83. package/dist/errors/invalid-grant-error.js +2 -6
  84. package/dist/errors/invalid-grant-error.js.map +1 -1
  85. package/dist/errors/invalid-invite-code-error.d.ts +1 -1
  86. package/dist/errors/invalid-invite-code-error.d.ts.map +1 -1
  87. package/dist/errors/invalid-invite-code-error.js +2 -6
  88. package/dist/errors/invalid-invite-code-error.js.map +1 -1
  89. package/dist/errors/invalid-redirect-uri-error.js +2 -6
  90. package/dist/errors/invalid-redirect-uri-error.js.map +1 -1
  91. package/dist/errors/invalid-request-error.js +3 -7
  92. package/dist/errors/invalid-request-error.js.map +1 -1
  93. package/dist/errors/invalid-scope-error.js +2 -6
  94. package/dist/errors/invalid-scope-error.js.map +1 -1
  95. package/dist/errors/invalid-token-error.js +10 -15
  96. package/dist/errors/invalid-token-error.js.map +1 -1
  97. package/dist/errors/login-required-error.js +2 -6
  98. package/dist/errors/login-required-error.js.map +1 -1
  99. package/dist/errors/oauth-error.js +1 -9
  100. package/dist/errors/oauth-error.js.map +1 -1
  101. package/dist/errors/second-authentication-factor-required-error.js +2 -8
  102. package/dist/errors/second-authentication-factor-required-error.js.map +1 -1
  103. package/dist/errors/unauthorized-client-error.js +2 -6
  104. package/dist/errors/unauthorized-client-error.js.map +1 -1
  105. package/dist/errors/use-dpop-nonce-error.js +4 -8
  106. package/dist/errors/use-dpop-nonce-error.js.map +1 -1
  107. package/dist/errors/www-authenticate-error.js +4 -9
  108. package/dist/errors/www-authenticate-error.js.map +1 -1
  109. package/dist/index.js +14 -30
  110. package/dist/index.js.map +1 -1
  111. package/dist/lexicon/lexicon-data.js +1 -2
  112. package/dist/lexicon/lexicon-getter.js +6 -10
  113. package/dist/lexicon/lexicon-getter.js.map +1 -1
  114. package/dist/lexicon/lexicon-manager.js +10 -30
  115. package/dist/lexicon/lexicon-manager.js.map +1 -1
  116. package/dist/lexicon/lexicon-store.js +5 -10
  117. package/dist/lexicon/lexicon-store.js.map +1 -1
  118. package/dist/lib/csp/index.js +3 -8
  119. package/dist/lib/csp/index.js.map +1 -1
  120. package/dist/lib/hcaptcha.js +33 -43
  121. package/dist/lib/hcaptcha.js.map +1 -1
  122. package/dist/lib/html/build-document.js +19 -24
  123. package/dist/lib/html/build-document.js.map +1 -1
  124. package/dist/lib/html/escapers.js +10 -16
  125. package/dist/lib/html/escapers.js.map +1 -1
  126. package/dist/lib/html/html.js +1 -5
  127. package/dist/lib/html/html.js.map +1 -1
  128. package/dist/lib/html/hydration-data.js +6 -10
  129. package/dist/lib/html/hydration-data.js.map +1 -1
  130. package/dist/lib/html/index.js +3 -19
  131. package/dist/lib/html/index.js.map +1 -1
  132. package/dist/lib/html/tags.js +14 -23
  133. package/dist/lib/html/tags.js.map +1 -1
  134. package/dist/lib/html/util.js +1 -4
  135. package/dist/lib/html/util.js.map +1 -1
  136. package/dist/lib/http/accept.d.ts.map +1 -1
  137. package/dist/lib/http/accept.js +8 -8
  138. package/dist/lib/http/accept.js.map +1 -1
  139. package/dist/lib/http/context.js +1 -4
  140. package/dist/lib/http/context.js.map +1 -1
  141. package/dist/lib/http/headers.js +1 -4
  142. package/dist/lib/http/headers.js.map +1 -1
  143. package/dist/lib/http/index.js +10 -26
  144. package/dist/lib/http/index.js.map +1 -1
  145. package/dist/lib/http/method.js +1 -4
  146. package/dist/lib/http/method.js.map +1 -1
  147. package/dist/lib/http/middleware.js +11 -17
  148. package/dist/lib/http/middleware.js.map +1 -1
  149. package/dist/lib/http/parser.js +13 -20
  150. package/dist/lib/http/parser.js.map +1 -1
  151. package/dist/lib/http/path.js +1 -4
  152. package/dist/lib/http/path.js.map +1 -1
  153. package/dist/lib/http/request.d.ts.map +1 -1
  154. package/dist/lib/http/request.js +32 -47
  155. package/dist/lib/http/request.js.map +1 -1
  156. package/dist/lib/http/response.js +14 -27
  157. package/dist/lib/http/response.js.map +1 -1
  158. package/dist/lib/http/route.js +9 -12
  159. package/dist/lib/http/route.js.map +1 -1
  160. package/dist/lib/http/router.js +8 -13
  161. package/dist/lib/http/router.js.map +1 -1
  162. package/dist/lib/http/security-headers.js +10 -15
  163. package/dist/lib/http/security-headers.js.map +1 -1
  164. package/dist/lib/http/stream.js +12 -20
  165. package/dist/lib/http/stream.js.map +1 -1
  166. package/dist/lib/http/types.js +1 -2
  167. package/dist/lib/http/url.js +1 -4
  168. package/dist/lib/http/url.js.map +1 -1
  169. package/dist/lib/nsid.js +4 -8
  170. package/dist/lib/nsid.js.map +1 -1
  171. package/dist/lib/redis.js +4 -7
  172. package/dist/lib/redis.js.map +1 -1
  173. package/dist/lib/util/authorization-header.js +11 -15
  174. package/dist/lib/util/authorization-header.js.map +1 -1
  175. package/dist/lib/util/cast.js +3 -8
  176. package/dist/lib/util/cast.js.map +1 -1
  177. package/dist/lib/util/color.js +23 -32
  178. package/dist/lib/util/color.js.map +1 -1
  179. package/dist/lib/util/crypto.js +5 -10
  180. package/dist/lib/util/crypto.js.map +1 -1
  181. package/dist/lib/util/date.js +2 -6
  182. package/dist/lib/util/date.js.map +1 -1
  183. package/dist/lib/util/error.js +5 -8
  184. package/dist/lib/util/error.js.map +1 -1
  185. package/dist/lib/util/function.js +3 -8
  186. package/dist/lib/util/function.js.map +1 -1
  187. package/dist/lib/util/locale.js +3 -6
  188. package/dist/lib/util/locale.js.map +1 -1
  189. package/dist/lib/util/object.js +1 -4
  190. package/dist/lib/util/object.js.map +1 -1
  191. package/dist/lib/util/redirect-uri.js +3 -6
  192. package/dist/lib/util/redirect-uri.js.map +1 -1
  193. package/dist/lib/util/time.js +5 -9
  194. package/dist/lib/util/time.js.map +1 -1
  195. package/dist/lib/util/type.d.ts.map +1 -1
  196. package/dist/lib/util/type.js +1 -5
  197. package/dist/lib/util/type.js.map +1 -1
  198. package/dist/lib/util/ui8.js +3 -8
  199. package/dist/lib/util/ui8.js.map +1 -1
  200. package/dist/lib/util/well-known.js +1 -4
  201. package/dist/lib/util/well-known.js.map +1 -1
  202. package/dist/lib/util/zod-error.js +4 -8
  203. package/dist/lib/util/zod-error.js.map +1 -1
  204. package/dist/lib/write-form-redirect.js +9 -12
  205. package/dist/lib/write-form-redirect.js.map +1 -1
  206. package/dist/lib/write-html.js +12 -15
  207. package/dist/lib/write-html.js.map +1 -1
  208. package/dist/metadata/build-metadata.js +9 -12
  209. package/dist/metadata/build-metadata.js.map +1 -1
  210. package/dist/oauth-client.js +2 -18
  211. package/dist/oauth-client.js.map +1 -1
  212. package/dist/oauth-dpop.js +2 -18
  213. package/dist/oauth-dpop.js.map +1 -1
  214. package/dist/oauth-errors.js +24 -42
  215. package/dist/oauth-errors.js.map +1 -1
  216. package/dist/oauth-hooks.js +8 -15
  217. package/dist/oauth-hooks.js.map +1 -1
  218. package/dist/oauth-middleware.js +13 -16
  219. package/dist/oauth-middleware.js.map +1 -1
  220. package/dist/oauth-provider.js +108 -125
  221. package/dist/oauth-provider.js.map +1 -1
  222. package/dist/oauth-store.js +7 -23
  223. package/dist/oauth-store.js.map +1 -1
  224. package/dist/oauth-verifier.js +41 -53
  225. package/dist/oauth-verifier.js.map +1 -1
  226. package/dist/oidc/sub.js +2 -5
  227. package/dist/oidc/sub.js.map +1 -1
  228. package/dist/replay/replay-manager.js +6 -11
  229. package/dist/replay/replay-manager.js.map +1 -1
  230. package/dist/replay/replay-store-memory.js +5 -7
  231. package/dist/replay/replay-store-memory.js.map +1 -1
  232. package/dist/replay/replay-store-redis.js +3 -8
  233. package/dist/replay/replay-store-redis.js.map +1 -1
  234. package/dist/replay/replay-store.js +3 -8
  235. package/dist/replay/replay-store.js.map +1 -1
  236. package/dist/request/code.js +10 -15
  237. package/dist/request/code.js.map +1 -1
  238. package/dist/request/request-data.js +1 -5
  239. package/dist/request/request-data.js.map +1 -1
  240. package/dist/request/request-id.js +9 -13
  241. package/dist/request/request-id.js.map +1 -1
  242. package/dist/request/request-manager.js +61 -71
  243. package/dist/request/request-manager.js.map +1 -1
  244. package/dist/request/request-store.js +9 -27
  245. package/dist/request/request-store.js.map +1 -1
  246. package/dist/request/request-uri.js +17 -23
  247. package/dist/request/request-uri.js.map +1 -1
  248. package/dist/result/authorization-redirect-parameters.js +1 -2
  249. package/dist/result/authorization-result-authorize-page.js +1 -2
  250. package/dist/result/authorization-result-redirect.js +1 -2
  251. package/dist/router/assets/assets-manifest.d.ts.map +1 -1
  252. package/dist/router/assets/assets-manifest.js +14 -15
  253. package/dist/router/assets/assets-manifest.js.map +1 -1
  254. package/dist/router/assets/assets.d.ts.map +1 -1
  255. package/dist/router/assets/assets.js +25 -27
  256. package/dist/router/assets/assets.js.map +1 -1
  257. package/dist/router/assets/csrf.js +16 -25
  258. package/dist/router/assets/csrf.js.map +1 -1
  259. package/dist/router/assets/send-account-page.js +3 -6
  260. package/dist/router/assets/send-account-page.js.map +1 -1
  261. package/dist/router/assets/send-authorization-page.js +3 -6
  262. package/dist/router/assets/send-authorization-page.js.map +1 -1
  263. package/dist/router/assets/send-cookie-error-page.js +3 -6
  264. package/dist/router/assets/send-cookie-error-page.js.map +1 -1
  265. package/dist/router/assets/send-error-page.js +6 -9
  266. package/dist/router/assets/send-error-page.js.map +1 -1
  267. package/dist/router/assets/send-redirect.js +12 -20
  268. package/dist/router/assets/send-redirect.js.map +1 -1
  269. package/dist/router/create-account-page-middleware.js +11 -14
  270. package/dist/router/create-account-page-middleware.js.map +1 -1
  271. package/dist/router/create-api-middleware.js +83 -90
  272. package/dist/router/create-api-middleware.js.map +1 -1
  273. package/dist/router/create-authorization-page-middleware.js +43 -46
  274. package/dist/router/create-authorization-page-middleware.js.map +1 -1
  275. package/dist/router/create-oauth-middleware.js +31 -34
  276. package/dist/router/create-oauth-middleware.js.map +1 -1
  277. package/dist/router/error-handler.js +1 -2
  278. package/dist/router/middleware-options.js +1 -2
  279. package/dist/signer/access-token-payload.js +12 -15
  280. package/dist/signer/access-token-payload.js.map +1 -1
  281. package/dist/signer/api-token-payload.js +8 -11
  282. package/dist/signer/api-token-payload.js.map +1 -1
  283. package/dist/signer/signer.js +11 -17
  284. package/dist/signer/signer.js.map +1 -1
  285. package/dist/token/refresh-token.js +10 -15
  286. package/dist/token/refresh-token.js.map +1 -1
  287. package/dist/token/token-claims.js +1 -2
  288. package/dist/token/token-data.js +1 -2
  289. package/dist/token/token-id.js +10 -15
  290. package/dist/token/token-id.js.map +1 -1
  291. package/dist/token/token-manager.js +40 -51
  292. package/dist/token/token-manager.js.map +1 -1
  293. package/dist/token/token-store.js +7 -25
  294. package/dist/token/token-store.js.map +1 -1
  295. package/dist/types/authorization-response-error.js +8 -12
  296. package/dist/types/authorization-response-error.js.map +1 -1
  297. package/dist/types/color-hue.js +2 -5
  298. package/dist/types/color-hue.js.map +1 -1
  299. package/dist/types/email-otp.js +2 -5
  300. package/dist/types/email-otp.js.map +1 -1
  301. package/dist/types/email.js +6 -9
  302. package/dist/types/email.js.map +1 -1
  303. package/dist/types/handle.js +6 -9
  304. package/dist/types/handle.js.map +1 -1
  305. package/dist/types/invite-code.js +2 -5
  306. package/dist/types/invite-code.js.map +1 -1
  307. package/dist/types/par-response-error.js +5 -9
  308. package/dist/types/par-response-error.js.map +1 -1
  309. package/dist/types/password.js +3 -6
  310. package/dist/types/password.js.map +1 -1
  311. package/dist/types/rgb-color.js +7 -10
  312. package/dist/types/rgb-color.js.map +1 -1
  313. package/package.json +20 -22
  314. package/src/dpop/dpop-nonce.ts +1 -1
  315. package/src/errors/invalid-invite-code-error.ts +1 -1
  316. package/src/lib/http/accept.ts +4 -1
  317. package/src/lib/http/request.ts +4 -1
  318. package/src/lib/util/type.ts +0 -1
  319. package/src/router/assets/assets-manifest.ts +3 -1
  320. package/src/router/assets/assets.ts +2 -0
  321. package/tsconfig.build.tsbuildinfo +1 -1
@@ -1,15 +1,10 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Signer = exports.Keyset = void 0;
4
- const jwk_1 = require("@atproto/jwk");
5
- Object.defineProperty(exports, "Keyset", { enumerable: true, get: function () { return jwk_1.Keyset; } });
6
- const constants_js_1 = require("../constants.js");
7
- const date_js_1 = require("../lib/util/date.js");
8
- const access_token_payload_js_1 = require("./access-token-payload.js");
9
- const api_token_payload_js_1 = require("./api-token-payload.js");
10
- class Signer {
11
- issuer;
12
- keyset;
1
+ import { Keyset, } from '@atproto/jwk';
2
+ import { EPHEMERAL_SESSION_MAX_AGE } from '../constants.js';
3
+ import { dateToEpoch } from '../lib/util/date.js';
4
+ import { accessTokenPayloadSchema, } from './access-token-payload.js';
5
+ import { apiTokenPayloadSchema } from './api-token-payload.js';
6
+ export { Keyset };
7
+ export class Signer {
13
8
  constructor(issuer, keyset) {
14
9
  this.issuer = issuer;
15
10
  this.keyset = keyset;
@@ -39,7 +34,7 @@ class Signer {
39
34
  const result = await this.verify(token, { ...options, typ: 'at+jwt' });
40
35
  return {
41
36
  protectedHeader: result.protectedHeader,
42
- payload: access_token_payload_js_1.accessTokenPayloadSchema.parse(result.payload),
37
+ payload: accessTokenPayloadSchema.parse(result.payload),
43
38
  };
44
39
  }
45
40
  async createEphemeralToken(payload) {
@@ -49,21 +44,20 @@ class Signer {
49
44
  }, {
50
45
  ...payload,
51
46
  aud: `oauth-provider-api@${this.issuer}`,
52
- iat: (0, date_js_1.dateToEpoch)(),
47
+ iat: dateToEpoch(),
53
48
  });
54
49
  }
55
50
  async verifyEphemeralToken(token, options) {
56
51
  const result = await this.verify(token, {
57
52
  ...options,
58
- maxTokenAge: options?.maxTokenAge ?? constants_js_1.EPHEMERAL_SESSION_MAX_AGE / 1e3,
53
+ maxTokenAge: options?.maxTokenAge ?? EPHEMERAL_SESSION_MAX_AGE / 1e3,
59
54
  audience: `oauth-provider-api@${this.issuer}`,
60
55
  typ: 'at+jwt',
61
56
  });
62
57
  return {
63
58
  protectedHeader: result.protectedHeader,
64
- payload: api_token_payload_js_1.apiTokenPayloadSchema.parse(result.payload),
59
+ payload: apiTokenPayloadSchema.parse(result.payload),
65
60
  };
66
61
  }
67
62
  }
68
- exports.Signer = Signer;
69
63
  //# sourceMappingURL=signer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"signer.js","sourceRoot":"","sources":["../../src/signer/signer.ts"],"names":[],"mappings":";;;AAAA,sCAOqB;AAYZ,uFAfP,YAAM,OAeO;AAXf,kDAA2D;AAC3D,iDAAiD;AAEjD,uEAGkC;AAClC,iEAA+E;AAO/E,MAAa,MAAM;IAEC;IACA;IAFlB,YACkB,MAAc,EACd,MAAc;QADd,WAAM,GAAN,MAAM,CAAQ;QACd,WAAM,GAAN,MAAM,CAAQ;IAC7B,CAAC;IAEJ,KAAK,CAAC,MAAM,CACV,KAAgB,EAChB,OAA0C;QAE1C,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,CAAI,KAAK,EAAE;YACrC,GAAG,OAAO;YACV,MAAM,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;SACtB,CAAC,CAAA;IACJ,CAAC;IAEM,KAAK,CAAC,IAAI,CACf,UAAyB,EACzB,OAAoD;QAEpD,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,EAAE,KAAK,EAAE,eAAe,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;YACxE,GAAG,CAAC,OAAO,OAAO,KAAK,UAAU;gBAC/B,CAAC,CAAC,MAAM,OAAO,CAAC,eAAe,EAAE,GAAG,CAAC;gBACrC,CAAC,CAAC,OAAO,CAAC;YACZ,GAAG,EAAE,IAAI,CAAC,MAAM;SACjB,CAAC,CAAC,CAAA;IACL,CAAC;IAED,KAAK,CAAC,iBAAiB,CACrB,OAA2C;QAE3C,OAAO,IAAI,CAAC,IAAI,CACd;YACE,4DAA4D;YAC5D,GAAG,EAAE,SAAS;YACd,GAAG,EAAE,QAAQ;SACd,EACD,OAAO,CACR,CAAA;IACH,CAAC;IAED,KAAK,CAAC,iBAAiB,CACrB,KAAgB,EAChB,OAAkD;QAElD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAI,KAAK,EAAE,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAA;QACzE,OAAO;YACL,eAAe,EAAE,MAAM,CAAC,eAAe;YACvC,OAAO,EAAE,kDAAwB,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAGrD;SACF,CAAA;IACH,CAAC;IAED,KAAK,CAAC,oBAAoB,CACxB,OAAwD;QAExD,OAAO,IAAI,CAAC,IAAI,CACd;YACE,GAAG,EAAE,SAAS;YACd,GAAG,EAAE,QAAQ;SACd,EACD;YACE,GAAG,OAAO;YACV,GAAG,EAAE,sBAAsB,IAAI,CAAC,MAAM,EAAE;YACxC,GAAG,EAAE,IAAA,qBAAW,GAAE;SACnB,CACF,CAAA;IACH,CAAC;IAED,KAAK,CAAC,oBAAoB,CACxB,KAAgB,EAChB,OAA+D;QAE/D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAI,KAAK,EAAE;YACzC,GAAG,OAAO;YACV,WAAW,EAAE,OAAO,EAAE,WAAW,IAAI,wCAAyB,GAAG,GAAG;YACpE,QAAQ,EAAE,sBAAsB,IAAI,CAAC,MAAM,EAAE;YAC7C,GAAG,EAAE,QAAQ;SACd,CAAC,CAAA;QACF,OAAO;YACL,eAAe,EAAE,MAAM,CAAC,eAAe;YACvC,OAAO,EAAE,4CAAqB,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAGlD;SACF,CAAA;IACH,CAAC;CACF;AAzFD,wBAyFC","sourcesContent":["import {\n JwtPayload,\n JwtPayloadGetter,\n JwtSignHeader,\n Keyset,\n SignedJwt,\n VerifyOptions,\n} from '@atproto/jwk'\nimport { EPHEMERAL_SESSION_MAX_AGE } from '../constants.js'\nimport { dateToEpoch } from '../lib/util/date.js'\nimport { OmitKey, RequiredKey } from '../lib/util/type.js'\nimport {\n AccessTokenPayload,\n accessTokenPayloadSchema,\n} from './access-token-payload.js'\nimport { ApiTokenPayload, apiTokenPayloadSchema } from './api-token-payload.js'\n\nexport type SignPayload = JwtPayload & { iss?: never }\n\nexport { Keyset }\nexport type { JwtPayloadGetter, JwtSignHeader, SignedJwt, VerifyOptions }\n\nexport class Signer {\n constructor(\n public readonly issuer: string,\n public readonly keyset: Keyset,\n ) {}\n\n async verify<C extends string = never>(\n token: SignedJwt,\n options?: Omit<VerifyOptions<C>, 'issuer'>,\n ) {\n return this.keyset.verifyJwt<C>(token, {\n ...options,\n issuer: [this.issuer],\n })\n }\n\n public async sign(\n signHeader: JwtSignHeader,\n payload: SignPayload | JwtPayloadGetter<SignPayload>,\n ): Promise<SignedJwt> {\n return this.keyset.createJwt(signHeader, async (protectedHeader, key) => ({\n ...(typeof payload === 'function'\n ? await payload(protectedHeader, key)\n : payload),\n iss: this.issuer,\n }))\n }\n\n async createAccessToken(\n payload: OmitKey<AccessTokenPayload, 'iss'>,\n ): Promise<SignedJwt> {\n return this.sign(\n {\n // https://datatracker.ietf.org/doc/html/rfc9068#section-2.1\n alg: undefined,\n typ: 'at+jwt',\n },\n payload,\n )\n }\n\n async verifyAccessToken<C extends string = never>(\n token: SignedJwt,\n options?: Omit<VerifyOptions<C>, 'issuer' | 'typ'>,\n ) {\n const result = await this.verify<C>(token, { ...options, typ: 'at+jwt' })\n return {\n protectedHeader: result.protectedHeader,\n payload: accessTokenPayloadSchema.parse(result.payload) as RequiredKey<\n AccessTokenPayload,\n C\n >,\n }\n }\n\n async createEphemeralToken(\n payload: OmitKey<ApiTokenPayload, 'iss' | 'aud' | 'iat'>,\n ) {\n return this.sign(\n {\n alg: undefined,\n typ: 'at+jwt',\n },\n {\n ...payload,\n aud: `oauth-provider-api@${this.issuer}`,\n iat: dateToEpoch(),\n },\n )\n }\n\n async verifyEphemeralToken<C extends string = never>(\n token: SignedJwt,\n options?: Omit<VerifyOptions<C>, 'issuer' | 'audience' | 'typ'>,\n ) {\n const result = await this.verify<C>(token, {\n ...options,\n maxTokenAge: options?.maxTokenAge ?? EPHEMERAL_SESSION_MAX_AGE / 1e3,\n audience: `oauth-provider-api@${this.issuer}`,\n typ: 'at+jwt',\n })\n return {\n protectedHeader: result.protectedHeader,\n payload: apiTokenPayloadSchema.parse(result.payload) as RequiredKey<\n ApiTokenPayload,\n C\n >,\n }\n }\n}\n"]}
1
+ {"version":3,"file":"signer.js","sourceRoot":"","sources":["../../src/signer/signer.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,MAAM,GAGP,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAA;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAEjD,OAAO,EAEL,wBAAwB,GACzB,MAAM,2BAA2B,CAAA;AAClC,OAAO,EAAmB,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AAI/E,OAAO,EAAE,MAAM,EAAE,CAAA;AAGjB,MAAM,OAAO,MAAM;IACjB,YACkB,MAAc,EACd,MAAc;QADd,WAAM,GAAN,MAAM,CAAQ;QACd,WAAM,GAAN,MAAM,CAAQ;IAC7B,CAAC;IAEJ,KAAK,CAAC,MAAM,CACV,KAAgB,EAChB,OAA0C;QAE1C,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,CAAI,KAAK,EAAE;YACrC,GAAG,OAAO;YACV,MAAM,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;SACtB,CAAC,CAAA;IACJ,CAAC;IAEM,KAAK,CAAC,IAAI,CACf,UAAyB,EACzB,OAAoD;QAEpD,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,EAAE,KAAK,EAAE,eAAe,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;YACxE,GAAG,CAAC,OAAO,OAAO,KAAK,UAAU;gBAC/B,CAAC,CAAC,MAAM,OAAO,CAAC,eAAe,EAAE,GAAG,CAAC;gBACrC,CAAC,CAAC,OAAO,CAAC;YACZ,GAAG,EAAE,IAAI,CAAC,MAAM;SACjB,CAAC,CAAC,CAAA;IACL,CAAC;IAED,KAAK,CAAC,iBAAiB,CACrB,OAA2C;QAE3C,OAAO,IAAI,CAAC,IAAI,CACd;YACE,4DAA4D;YAC5D,GAAG,EAAE,SAAS;YACd,GAAG,EAAE,QAAQ;SACd,EACD,OAAO,CACR,CAAA;IACH,CAAC;IAED,KAAK,CAAC,iBAAiB,CACrB,KAAgB,EAChB,OAAkD;QAElD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAI,KAAK,EAAE,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAA;QACzE,OAAO;YACL,eAAe,EAAE,MAAM,CAAC,eAAe;YACvC,OAAO,EAAE,wBAAwB,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAGrD;SACF,CAAA;IACH,CAAC;IAED,KAAK,CAAC,oBAAoB,CACxB,OAAwD;QAExD,OAAO,IAAI,CAAC,IAAI,CACd;YACE,GAAG,EAAE,SAAS;YACd,GAAG,EAAE,QAAQ;SACd,EACD;YACE,GAAG,OAAO;YACV,GAAG,EAAE,sBAAsB,IAAI,CAAC,MAAM,EAAE;YACxC,GAAG,EAAE,WAAW,EAAE;SACnB,CACF,CAAA;IACH,CAAC;IAED,KAAK,CAAC,oBAAoB,CACxB,KAAgB,EAChB,OAA+D;QAE/D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAI,KAAK,EAAE;YACzC,GAAG,OAAO;YACV,WAAW,EAAE,OAAO,EAAE,WAAW,IAAI,yBAAyB,GAAG,GAAG;YACpE,QAAQ,EAAE,sBAAsB,IAAI,CAAC,MAAM,EAAE;YAC7C,GAAG,EAAE,QAAQ;SACd,CAAC,CAAA;QACF,OAAO;YACL,eAAe,EAAE,MAAM,CAAC,eAAe;YACvC,OAAO,EAAE,qBAAqB,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAGlD;SACF,CAAA;IACH,CAAC;CACF","sourcesContent":["import {\n JwtPayload,\n JwtPayloadGetter,\n JwtSignHeader,\n Keyset,\n SignedJwt,\n VerifyOptions,\n} from '@atproto/jwk'\nimport { EPHEMERAL_SESSION_MAX_AGE } from '../constants.js'\nimport { dateToEpoch } from '../lib/util/date.js'\nimport { OmitKey, RequiredKey } from '../lib/util/type.js'\nimport {\n AccessTokenPayload,\n accessTokenPayloadSchema,\n} from './access-token-payload.js'\nimport { ApiTokenPayload, apiTokenPayloadSchema } from './api-token-payload.js'\n\nexport type SignPayload = JwtPayload & { iss?: never }\n\nexport { Keyset }\nexport type { JwtPayloadGetter, JwtSignHeader, SignedJwt, VerifyOptions }\n\nexport class Signer {\n constructor(\n public readonly issuer: string,\n public readonly keyset: Keyset,\n ) {}\n\n async verify<C extends string = never>(\n token: SignedJwt,\n options?: Omit<VerifyOptions<C>, 'issuer'>,\n ) {\n return this.keyset.verifyJwt<C>(token, {\n ...options,\n issuer: [this.issuer],\n })\n }\n\n public async sign(\n signHeader: JwtSignHeader,\n payload: SignPayload | JwtPayloadGetter<SignPayload>,\n ): Promise<SignedJwt> {\n return this.keyset.createJwt(signHeader, async (protectedHeader, key) => ({\n ...(typeof payload === 'function'\n ? await payload(protectedHeader, key)\n : payload),\n iss: this.issuer,\n }))\n }\n\n async createAccessToken(\n payload: OmitKey<AccessTokenPayload, 'iss'>,\n ): Promise<SignedJwt> {\n return this.sign(\n {\n // https://datatracker.ietf.org/doc/html/rfc9068#section-2.1\n alg: undefined,\n typ: 'at+jwt',\n },\n payload,\n )\n }\n\n async verifyAccessToken<C extends string = never>(\n token: SignedJwt,\n options?: Omit<VerifyOptions<C>, 'issuer' | 'typ'>,\n ) {\n const result = await this.verify<C>(token, { ...options, typ: 'at+jwt' })\n return {\n protectedHeader: result.protectedHeader,\n payload: accessTokenPayloadSchema.parse(result.payload) as RequiredKey<\n AccessTokenPayload,\n C\n >,\n }\n }\n\n async createEphemeralToken(\n payload: OmitKey<ApiTokenPayload, 'iss' | 'aud' | 'iat'>,\n ) {\n return this.sign(\n {\n alg: undefined,\n typ: 'at+jwt',\n },\n {\n ...payload,\n aud: `oauth-provider-api@${this.issuer}`,\n iat: dateToEpoch(),\n },\n )\n }\n\n async verifyEphemeralToken<C extends string = never>(\n token: SignedJwt,\n options?: Omit<VerifyOptions<C>, 'issuer' | 'audience' | 'typ'>,\n ) {\n const result = await this.verify<C>(token, {\n ...options,\n maxTokenAge: options?.maxTokenAge ?? EPHEMERAL_SESSION_MAX_AGE / 1e3,\n audience: `oauth-provider-api@${this.issuer}`,\n typ: 'at+jwt',\n })\n return {\n protectedHeader: result.protectedHeader,\n payload: apiTokenPayloadSchema.parse(result.payload) as RequiredKey<\n ApiTokenPayload,\n C\n >,\n }\n }\n}\n"]}
@@ -1,20 +1,15 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.generateRefreshToken = exports.isRefreshToken = exports.refreshTokenSchema = exports.REFRESH_TOKEN_LENGTH = void 0;
4
- const zod_1 = require("zod");
5
- const constants_js_1 = require("../constants.js");
6
- const crypto_js_1 = require("../lib/util/crypto.js");
7
- exports.REFRESH_TOKEN_LENGTH = constants_js_1.REFRESH_TOKEN_PREFIX.length + constants_js_1.REFRESH_TOKEN_BYTES_LENGTH * 2; // hex encoding
8
- exports.refreshTokenSchema = zod_1.z
1
+ import { z } from 'zod';
2
+ import { REFRESH_TOKEN_BYTES_LENGTH, REFRESH_TOKEN_PREFIX, } from '../constants.js';
3
+ import { randomHexId } from '../lib/util/crypto.js';
4
+ export const REFRESH_TOKEN_LENGTH = REFRESH_TOKEN_PREFIX.length + REFRESH_TOKEN_BYTES_LENGTH * 2; // hex encoding
5
+ export const refreshTokenSchema = z
9
6
  .string()
10
- .length(exports.REFRESH_TOKEN_LENGTH)
11
- .refine((v) => v.startsWith(constants_js_1.REFRESH_TOKEN_PREFIX), {
7
+ .length(REFRESH_TOKEN_LENGTH)
8
+ .refine((v) => v.startsWith(REFRESH_TOKEN_PREFIX), {
12
9
  message: `Invalid refresh token format`,
13
10
  });
14
- const isRefreshToken = (data) => exports.refreshTokenSchema.safeParse(data).success;
15
- exports.isRefreshToken = isRefreshToken;
16
- const generateRefreshToken = async () => {
17
- return `${constants_js_1.REFRESH_TOKEN_PREFIX}${await (0, crypto_js_1.randomHexId)(constants_js_1.REFRESH_TOKEN_BYTES_LENGTH)}`;
11
+ export const isRefreshToken = (data) => refreshTokenSchema.safeParse(data).success;
12
+ export const generateRefreshToken = async () => {
13
+ return `${REFRESH_TOKEN_PREFIX}${await randomHexId(REFRESH_TOKEN_BYTES_LENGTH)}`;
18
14
  };
19
- exports.generateRefreshToken = generateRefreshToken;
20
15
  //# sourceMappingURL=refresh-token.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"refresh-token.js","sourceRoot":"","sources":["../../src/token/refresh-token.ts"],"names":[],"mappings":";;;AAAA,6BAAuB;AACvB,kDAGwB;AACxB,qDAAmD;AAEtC,QAAA,oBAAoB,GAC/B,mCAAoB,CAAC,MAAM,GAAG,yCAA0B,GAAG,CAAC,CAAA,CAAC,eAAe;AAEjE,QAAA,kBAAkB,GAAG,OAAC;KAChC,MAAM,EAAE;KACR,MAAM,CAAC,4BAAoB,CAAC;KAC5B,MAAM,CACL,CAAC,CAAC,EAAkD,EAAE,CACpD,CAAC,CAAC,UAAU,CAAC,mCAAoB,CAAC,EACpC;IACE,OAAO,EAAE,8BAA8B;CACxC,CACF,CAAA;AAEI,MAAM,cAAc,GAAG,CAAC,IAAa,EAAwB,EAAE,CACpE,0BAAkB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,OAAO,CAAA;AAD/B,QAAA,cAAc,kBACiB;AAGrC,MAAM,oBAAoB,GAAG,KAAK,IAA2B,EAAE;IACpE,OAAO,GAAG,mCAAoB,GAAG,MAAM,IAAA,uBAAW,EAChD,yCAA0B,CAC3B,EAAE,CAAA;AACL,CAAC,CAAA;AAJY,QAAA,oBAAoB,wBAIhC","sourcesContent":["import { z } from 'zod'\nimport {\n REFRESH_TOKEN_BYTES_LENGTH,\n REFRESH_TOKEN_PREFIX,\n} from '../constants.js'\nimport { randomHexId } from '../lib/util/crypto.js'\n\nexport const REFRESH_TOKEN_LENGTH =\n REFRESH_TOKEN_PREFIX.length + REFRESH_TOKEN_BYTES_LENGTH * 2 // hex encoding\n\nexport const refreshTokenSchema = z\n .string()\n .length(REFRESH_TOKEN_LENGTH)\n .refine(\n (v): v is `${typeof REFRESH_TOKEN_PREFIX}${string}` =>\n v.startsWith(REFRESH_TOKEN_PREFIX),\n {\n message: `Invalid refresh token format`,\n },\n )\n\nexport const isRefreshToken = (data: unknown): data is RefreshToken =>\n refreshTokenSchema.safeParse(data).success\n\nexport type RefreshToken = z.infer<typeof refreshTokenSchema>\nexport const generateRefreshToken = async (): Promise<RefreshToken> => {\n return `${REFRESH_TOKEN_PREFIX}${await randomHexId(\n REFRESH_TOKEN_BYTES_LENGTH,\n )}`\n}\n"]}
1
+ {"version":3,"file":"refresh-token.js","sourceRoot":"","sources":["../../src/token/refresh-token.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EACL,0BAA0B,EAC1B,oBAAoB,GACrB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAEnD,MAAM,CAAC,MAAM,oBAAoB,GAC/B,oBAAoB,CAAC,MAAM,GAAG,0BAA0B,GAAG,CAAC,CAAA,CAAC,eAAe;AAE9E,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC;KAChC,MAAM,EAAE;KACR,MAAM,CAAC,oBAAoB,CAAC;KAC5B,MAAM,CACL,CAAC,CAAC,EAAkD,EAAE,CACpD,CAAC,CAAC,UAAU,CAAC,oBAAoB,CAAC,EACpC;IACE,OAAO,EAAE,8BAA8B;CACxC,CACF,CAAA;AAEH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,IAAa,EAAwB,EAAE,CACpE,kBAAkB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,OAAO,CAAA;AAG5C,MAAM,CAAC,MAAM,oBAAoB,GAAG,KAAK,IAA2B,EAAE;IACpE,OAAO,GAAG,oBAAoB,GAAG,MAAM,WAAW,CAChD,0BAA0B,CAC3B,EAAE,CAAA;AACL,CAAC,CAAA","sourcesContent":["import { z } from 'zod'\nimport {\n REFRESH_TOKEN_BYTES_LENGTH,\n REFRESH_TOKEN_PREFIX,\n} from '../constants.js'\nimport { randomHexId } from '../lib/util/crypto.js'\n\nexport const REFRESH_TOKEN_LENGTH =\n REFRESH_TOKEN_PREFIX.length + REFRESH_TOKEN_BYTES_LENGTH * 2 // hex encoding\n\nexport const refreshTokenSchema = z\n .string()\n .length(REFRESH_TOKEN_LENGTH)\n .refine(\n (v): v is `${typeof REFRESH_TOKEN_PREFIX}${string}` =>\n v.startsWith(REFRESH_TOKEN_PREFIX),\n {\n message: `Invalid refresh token format`,\n },\n )\n\nexport const isRefreshToken = (data: unknown): data is RefreshToken =>\n refreshTokenSchema.safeParse(data).success\n\nexport type RefreshToken = z.infer<typeof refreshTokenSchema>\nexport const generateRefreshToken = async (): Promise<RefreshToken> => {\n return `${REFRESH_TOKEN_PREFIX}${await randomHexId(\n REFRESH_TOKEN_BYTES_LENGTH,\n )}`\n}\n"]}
@@ -1,3 +1,2 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
1
+ export {};
3
2
  //# sourceMappingURL=token-claims.js.map
@@ -1,3 +1,2 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
1
+ export {};
3
2
  //# sourceMappingURL=token-data.js.map
@@ -1,20 +1,15 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isTokenId = exports.generateTokenId = exports.tokenIdSchema = exports.TOKEN_ID_LENGTH = void 0;
4
- const zod_1 = require("zod");
5
- const constants_js_1 = require("../constants.js");
6
- const crypto_js_1 = require("../lib/util/crypto.js");
7
- exports.TOKEN_ID_LENGTH = constants_js_1.TOKEN_ID_PREFIX.length + constants_js_1.TOKEN_ID_BYTES_LENGTH * 2; // hex encoding
8
- exports.tokenIdSchema = zod_1.z
1
+ import { z } from 'zod';
2
+ import { TOKEN_ID_BYTES_LENGTH, TOKEN_ID_PREFIX } from '../constants.js';
3
+ import { randomHexId } from '../lib/util/crypto.js';
4
+ export const TOKEN_ID_LENGTH = TOKEN_ID_PREFIX.length + TOKEN_ID_BYTES_LENGTH * 2; // hex encoding
5
+ export const tokenIdSchema = z
9
6
  .string()
10
- .length(exports.TOKEN_ID_LENGTH)
11
- .refine((v) => v.startsWith(constants_js_1.TOKEN_ID_PREFIX), {
7
+ .length(TOKEN_ID_LENGTH)
8
+ .refine((v) => v.startsWith(TOKEN_ID_PREFIX), {
12
9
  message: `Invalid token ID format`,
13
10
  });
14
- const generateTokenId = async () => {
15
- return `${constants_js_1.TOKEN_ID_PREFIX}${await (0, crypto_js_1.randomHexId)(constants_js_1.TOKEN_ID_BYTES_LENGTH)}`;
11
+ export const generateTokenId = async () => {
12
+ return `${TOKEN_ID_PREFIX}${await randomHexId(TOKEN_ID_BYTES_LENGTH)}`;
16
13
  };
17
- exports.generateTokenId = generateTokenId;
18
- const isTokenId = (data) => exports.tokenIdSchema.safeParse(data).success;
19
- exports.isTokenId = isTokenId;
14
+ export const isTokenId = (data) => tokenIdSchema.safeParse(data).success;
20
15
  //# sourceMappingURL=token-id.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"token-id.js","sourceRoot":"","sources":["../../src/token/token-id.ts"],"names":[],"mappings":";;;AAAA,6BAAuB;AACvB,kDAAwE;AACxE,qDAAmD;AAEtC,QAAA,eAAe,GAC1B,8BAAe,CAAC,MAAM,GAAG,oCAAqB,GAAG,CAAC,CAAA,CAAC,eAAe;AAEvD,QAAA,aAAa,GAAG,OAAC;KAC3B,MAAM,EAAE;KACR,MAAM,CAAC,uBAAe,CAAC;KACvB,MAAM,CACL,CAAC,CAAC,EAA6C,EAAE,CAC/C,CAAC,CAAC,UAAU,CAAC,8BAAe,CAAC,EAC/B;IACE,OAAO,EAAE,yBAAyB;CACnC,CACF,CAAA;AAGI,MAAM,eAAe,GAAG,KAAK,IAAsB,EAAE;IAC1D,OAAO,GAAG,8BAAe,GAAG,MAAM,IAAA,uBAAW,EAAC,oCAAqB,CAAC,EAAE,CAAA;AACxE,CAAC,CAAA;AAFY,QAAA,eAAe,mBAE3B;AAEM,MAAM,SAAS,GAAG,CAAC,IAAa,EAAmB,EAAE,CAC1D,qBAAa,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,OAAO,CAAA;AAD1B,QAAA,SAAS,aACiB","sourcesContent":["import { z } from 'zod'\nimport { TOKEN_ID_BYTES_LENGTH, TOKEN_ID_PREFIX } from '../constants.js'\nimport { randomHexId } from '../lib/util/crypto.js'\n\nexport const TOKEN_ID_LENGTH =\n TOKEN_ID_PREFIX.length + TOKEN_ID_BYTES_LENGTH * 2 // hex encoding\n\nexport const tokenIdSchema = z\n .string()\n .length(TOKEN_ID_LENGTH)\n .refine(\n (v): v is `${typeof TOKEN_ID_PREFIX}${string}` =>\n v.startsWith(TOKEN_ID_PREFIX),\n {\n message: `Invalid token ID format`,\n },\n )\n\nexport type TokenId = z.infer<typeof tokenIdSchema>\nexport const generateTokenId = async (): Promise<TokenId> => {\n return `${TOKEN_ID_PREFIX}${await randomHexId(TOKEN_ID_BYTES_LENGTH)}`\n}\n\nexport const isTokenId = (data: unknown): data is TokenId =>\n tokenIdSchema.safeParse(data).success\n"]}
1
+ {"version":3,"file":"token-id.js","sourceRoot":"","sources":["../../src/token/token-id.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACxE,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAEnD,MAAM,CAAC,MAAM,eAAe,GAC1B,eAAe,CAAC,MAAM,GAAG,qBAAqB,GAAG,CAAC,CAAA,CAAC,eAAe;AAEpE,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC;KAC3B,MAAM,EAAE;KACR,MAAM,CAAC,eAAe,CAAC;KACvB,MAAM,CACL,CAAC,CAAC,EAA6C,EAAE,CAC/C,CAAC,CAAC,UAAU,CAAC,eAAe,CAAC,EAC/B;IACE,OAAO,EAAE,yBAAyB;CACnC,CACF,CAAA;AAGH,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,IAAsB,EAAE;IAC1D,OAAO,GAAG,eAAe,GAAG,MAAM,WAAW,CAAC,qBAAqB,CAAC,EAAE,CAAA;AACxE,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,IAAa,EAAmB,EAAE,CAC1D,aAAa,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,OAAO,CAAA","sourcesContent":["import { z } from 'zod'\nimport { TOKEN_ID_BYTES_LENGTH, TOKEN_ID_PREFIX } from '../constants.js'\nimport { randomHexId } from '../lib/util/crypto.js'\n\nexport const TOKEN_ID_LENGTH =\n TOKEN_ID_PREFIX.length + TOKEN_ID_BYTES_LENGTH * 2 // hex encoding\n\nexport const tokenIdSchema = z\n .string()\n .length(TOKEN_ID_LENGTH)\n .refine(\n (v): v is `${typeof TOKEN_ID_PREFIX}${string}` =>\n v.startsWith(TOKEN_ID_PREFIX),\n {\n message: `Invalid token ID format`,\n },\n )\n\nexport type TokenId = z.infer<typeof tokenIdSchema>\nexport const generateTokenId = async (): Promise<TokenId> => {\n return `${TOKEN_ID_PREFIX}${await randomHexId(TOKEN_ID_BYTES_LENGTH)}`\n}\n\nexport const isTokenId = (data: unknown): data is TokenId =>\n tokenIdSchema.safeParse(data).success\n"]}
@@ -1,28 +1,18 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TokenManager = exports.Signer = exports.AccessTokenMode = void 0;
4
- const jwk_1 = require("@atproto/jwk");
5
- const lex_resolver_1 = require("@atproto/lex-resolver");
6
- const access_token_mode_js_1 = require("../access-token/access-token-mode.js");
7
- Object.defineProperty(exports, "AccessTokenMode", { enumerable: true, get: function () { return access_token_mode_js_1.AccessTokenMode; } });
8
- const constants_js_1 = require("../constants.js");
9
- const invalid_grant_error_js_1 = require("../errors/invalid-grant-error.js");
10
- const invalid_request_error_js_1 = require("../errors/invalid-request-error.js");
11
- const invalid_token_error_js_1 = require("../errors/invalid-token-error.js");
12
- const date_js_1 = require("../lib/util/date.js");
13
- const code_js_1 = require("../request/code.js");
14
- const signer_js_1 = require("../signer/signer.js");
15
- Object.defineProperty(exports, "Signer", { enumerable: true, get: function () { return signer_js_1.Signer; } });
16
- const refresh_token_js_1 = require("./refresh-token.js");
17
- const token_id_js_1 = require("./token-id.js");
18
- class TokenManager {
19
- store;
20
- lexiconManager;
21
- signer;
22
- hooks;
23
- accessTokenMode;
24
- tokenMaxAge;
25
- constructor(store, lexiconManager, signer, hooks, accessTokenMode, tokenMaxAge = constants_js_1.TOKEN_MAX_AGE) {
1
+ import { isSignedJwt } from '@atproto/jwk';
2
+ import { LexResolverError } from '@atproto/lex-resolver';
3
+ import { AccessTokenMode } from '../access-token/access-token-mode.js';
4
+ import { TOKEN_MAX_AGE } from '../constants.js';
5
+ import { InvalidGrantError } from '../errors/invalid-grant-error.js';
6
+ import { InvalidRequestError } from '../errors/invalid-request-error.js';
7
+ import { InvalidTokenError } from '../errors/invalid-token-error.js';
8
+ import { dateToEpoch, dateToRelativeSeconds } from '../lib/util/date.js';
9
+ import { isCode } from '../request/code.js';
10
+ import { Signer } from '../signer/signer.js';
11
+ import { generateRefreshToken, isRefreshToken, } from './refresh-token.js';
12
+ import { generateTokenId, isTokenId } from './token-id.js';
13
+ export { AccessTokenMode, Signer };
14
+ export class TokenManager {
15
+ constructor(store, lexiconManager, signer, hooks, accessTokenMode, tokenMaxAge = TOKEN_MAX_AGE) {
26
16
  this.store = store;
27
17
  this.lexiconManager = lexiconManager;
28
18
  this.signer = signer;
@@ -37,15 +27,15 @@ class TokenManager {
37
27
  const claims = {
38
28
  jti: tokenId,
39
29
  sub: account.sub,
40
- iat: (0, date_js_1.dateToEpoch)(issuedAt),
41
- exp: (0, date_js_1.dateToEpoch)(expiresAt),
30
+ iat: dateToEpoch(issuedAt),
31
+ exp: dateToEpoch(expiresAt),
42
32
  aud: account.aud,
43
33
  ...(parameters.dpop_jkt && {
44
34
  cnf: { jkt: parameters.dpop_jkt },
45
35
  }),
46
36
  // Because tokens can end-up being quite big, we only include the scope in
47
37
  // stateless mode.
48
- ...(this.accessTokenMode === access_token_mode_js_1.AccessTokenMode.stateless && {
38
+ ...(this.accessTokenMode === AccessTokenMode.stateless && {
49
39
  scope,
50
40
  }),
51
41
  // https://datatracker.ietf.org/doc/html/rfc8693#section-4.3
@@ -61,9 +51,9 @@ class TokenManager {
61
51
  }
62
52
  async createToken(client, clientAuth, clientMetadata, account, deviceId, parameters, code) {
63
53
  await this.validateTokenParams(client, clientAuth, parameters);
64
- const tokenId = await (0, token_id_js_1.generateTokenId)();
54
+ const tokenId = await generateTokenId();
65
55
  const refreshToken = client.metadata.grant_types.includes('refresh_token')
66
- ? await (0, refresh_token_js_1.generateRefreshToken)()
56
+ ? await generateRefreshToken()
67
57
  : undefined;
68
58
  const now = new Date();
69
59
  const expiresAt = this.createTokenExpiry(now);
@@ -71,8 +61,8 @@ class TokenManager {
71
61
  .buildTokenScope(parameters.scope)
72
62
  .catch((err) => {
73
63
  // Parse expected errors
74
- if (err instanceof lex_resolver_1.LexResolverError) {
75
- throw new invalid_request_error_js_1.InvalidRequestError(err.message, err);
64
+ if (err instanceof LexResolverError) {
65
+ throw new InvalidRequestError(err.message, err);
76
66
  }
77
67
  // Unexpected error
78
68
  throw err;
@@ -112,7 +102,7 @@ class TokenManager {
112
102
  }
113
103
  async validateTokenParams(client, clientAuth, parameters) {
114
104
  if (client.metadata.dpop_bound_access_tokens && !parameters.dpop_jkt) {
115
- throw new invalid_grant_error_js_1.InvalidGrantError(`DPoP JKT is required for DPoP bound access tokens`);
105
+ throw new InvalidGrantError(`DPoP JKT is required for DPoP bound access tokens`);
116
106
  }
117
107
  }
118
108
  buildTokenResponse(tokenType, accessToken, refreshToken, expiresAt, sub, scope) {
@@ -124,7 +114,7 @@ class TokenManager {
124
114
  // @NOTE using a getter so that the value gets computed when the JSON
125
115
  // response is generated, allowing to value to be as accurate as possible.
126
116
  get expires_in() {
127
- return (0, date_js_1.dateToRelativeSeconds)(expiresAt);
117
+ return dateToRelativeSeconds(expiresAt);
128
118
  },
129
119
  // ATPROTO extension: add the sub claim to the token response to allow
130
120
  // clients to resolve the PDS url (audience) using the did resolution
@@ -136,8 +126,8 @@ class TokenManager {
136
126
  const { account, data } = tokenInfo;
137
127
  const { parameters } = data;
138
128
  await this.validateTokenParams(client, clientAuth, parameters);
139
- const nextTokenId = await (0, token_id_js_1.generateTokenId)();
140
- const nextRefreshToken = await (0, refresh_token_js_1.generateRefreshToken)();
129
+ const nextTokenId = await generateTokenId();
130
+ const nextRefreshToken = await generateRefreshToken();
141
131
  const now = new Date();
142
132
  const expiresAt = this.createTokenExpiry(now);
143
133
  // @NOTE since the permission sets are stored in a persistent store,
@@ -172,20 +162,20 @@ class TokenManager {
172
162
  * token is valid before using the returned token info.
173
163
  */
174
164
  async findToken(token) {
175
- if ((0, token_id_js_1.isTokenId)(token)) {
165
+ if (isTokenId(token)) {
176
166
  return this.getTokenInfo(token);
177
167
  }
178
- else if ((0, code_js_1.isCode)(token)) {
168
+ else if (isCode(token)) {
179
169
  return this.findByCode(token);
180
170
  }
181
- else if ((0, refresh_token_js_1.isRefreshToken)(token)) {
171
+ else if (isRefreshToken(token)) {
182
172
  return this.findByRefreshToken(token);
183
173
  }
184
- else if ((0, jwk_1.isSignedJwt)(token)) {
174
+ else if (isSignedJwt(token)) {
185
175
  return this.findByAccessToken(token);
186
176
  }
187
177
  else {
188
- throw new invalid_request_error_js_1.InvalidRequestError(`Invalid token`);
178
+ throw new InvalidRequestError(`Invalid token`);
189
179
  }
190
180
  }
191
181
  async findByAccessToken(token) {
@@ -216,14 +206,14 @@ class TokenManager {
216
206
  // @TODO Add another store method that atomically consumes the refresh token
217
207
  // with a lock.
218
208
  const tokenInfo = await this.findByRefreshToken(token).catch((err) => {
219
- throw invalid_grant_error_js_1.InvalidGrantError.from(err, `Invalid refresh token`);
209
+ throw InvalidGrantError.from(err, `Invalid refresh token`);
220
210
  });
221
211
  if (!tokenInfo) {
222
- throw new invalid_grant_error_js_1.InvalidGrantError(`Invalid refresh token`);
212
+ throw new InvalidGrantError(`Invalid refresh token`);
223
213
  }
224
214
  if (tokenInfo.currentRefreshToken !== token) {
225
215
  await this.deleteToken(tokenInfo.id);
226
- throw new invalid_grant_error_js_1.InvalidGrantError(`Refresh token replayed`);
216
+ throw new InvalidGrantError(`Refresh token replayed`);
227
217
  }
228
218
  return tokenInfo;
229
219
  }
@@ -244,10 +234,10 @@ class TokenManager {
244
234
  async loadTokenClaims(tokenType, tokenPayload) {
245
235
  const tokenId = tokenPayload.jti;
246
236
  const tokenInfo = await this.getTokenInfo(tokenId).catch((err) => {
247
- throw invalid_token_error_js_1.InvalidTokenError.from(err, tokenType);
237
+ throw InvalidTokenError.from(err, tokenType);
248
238
  });
249
239
  if (!tokenInfo) {
250
- throw new invalid_token_error_js_1.InvalidTokenError(tokenType, `Invalid token`);
240
+ throw new InvalidTokenError(tokenType, `Invalid token`);
251
241
  }
252
242
  const { account, data } = tokenInfo;
253
243
  // Fool proof, make sure that the database & token payload are consistent.
@@ -255,17 +245,17 @@ class TokenManager {
255
245
  // the values directly.
256
246
  if (tokenPayload.cnf?.jkt !== data.parameters.dpop_jkt) {
257
247
  await this.deleteToken(tokenId);
258
- throw new invalid_token_error_js_1.InvalidTokenError(tokenType, `Invalid token`);
248
+ throw new InvalidTokenError(tokenType, `Invalid token`);
259
249
  }
260
250
  if (isCurrentTokenExpired(tokenInfo)) {
261
251
  await this.deleteToken(tokenId);
262
- throw new invalid_token_error_js_1.InvalidTokenError(tokenType, `Token expired`);
252
+ throw new InvalidTokenError(tokenType, `Token expired`);
263
253
  }
264
254
  return {
265
255
  jti: tokenId,
266
256
  sub: account.sub,
267
- iat: (0, date_js_1.dateToEpoch)(data.updatedAt),
268
- exp: (0, date_js_1.dateToEpoch)(data.expiresAt),
257
+ iat: dateToEpoch(data.updatedAt),
258
+ exp: dateToEpoch(data.expiresAt),
269
259
  aud: account.aud,
270
260
  scope: data.scope ?? data.parameters.scope,
271
261
  // https://datatracker.ietf.org/doc/html/rfc8693#section-4.3
@@ -279,7 +269,6 @@ class TokenManager {
279
269
  .filter((tokenInfo) => !isCurrentTokenExpired(tokenInfo));
280
270
  }
281
271
  }
282
- exports.TokenManager = TokenManager;
283
272
  function isCurrentTokenExpired(tokenInfo) {
284
273
  return tokenInfo.data.expiresAt.getTime() < Date.now();
285
274
  }
@@ -1 +1 @@
1
- {"version":3,"file":"token-manager.js","sourceRoot":"","sources":["../../src/token/token-manager.ts"],"names":[],"mappings":";;;AAAA,sCAAqD;AACrD,wDAAwD;AASxD,+EAAsE;AAyB7D,gGAzBA,sCAAe,OAyBA;AAtBxB,kDAA+C;AAE/C,6EAAoE;AACpE,iFAAwE;AACxE,6EAAoE;AAGpE,iDAAwE;AAGxE,gDAAiD;AAEjD,mDAA4C;AAUlB,uFAVjB,kBAAM,OAUiB;AAThC,yDAI2B;AAE3B,+CAAmE;AAMnE,MAAa,YAAY;IAEF;IACA;IACA;IACA;IACA;IACA;IANrB,YACqB,KAAiB,EACjB,cAA8B,EAC9B,MAAc,EACd,KAAiB,EACjB,eAAgC,EAChC,cAAc,4BAAa;QAL3B,UAAK,GAAL,KAAK,CAAY;QACjB,mBAAc,GAAd,cAAc,CAAgB;QAC9B,WAAM,GAAN,MAAM,CAAQ;QACd,UAAK,GAAL,KAAK,CAAY;QACjB,oBAAe,GAAf,eAAe,CAAiB;QAChC,gBAAW,GAAX,WAAW,CAAgB;IAC7C,CAAC;IAEM,iBAAiB,CAAC,GAAG,GAAG,IAAI,IAAI,EAAE;QAC1C,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,CAAA;IACnD,CAAC;IAES,KAAK,CAAC,iBAAiB,CAC/B,OAAgB,EAChB,MAAc,EACd,OAAgB,EAChB,UAA+C,EAC/C,QAAc,EACd,SAAe,EACf,KAAiB;QAEjB,MAAM,MAAM,GAAgB;YAC1B,GAAG,EAAE,OAAO;YACZ,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,GAAG,EAAE,IAAA,qBAAW,EAAC,QAAQ,CAAC;YAC1B,GAAG,EAAE,IAAA,qBAAW,EAAC,SAAS,CAAC;YAC3B,GAAG,EAAE,OAAO,CAAC,GAAG;YAEhB,GAAG,CAAC,UAAU,CAAC,QAAQ,IAAI;gBACzB,GAAG,EAAE,EAAE,GAAG,EAAE,UAAU,CAAC,QAAQ,EAAE;aAClC,CAAC;YAEF,0EAA0E;YAC1E,kBAAkB;YAClB,GAAG,CAAC,IAAI,CAAC,eAAe,KAAK,sCAAe,CAAC,SAAS,IAAI;gBACxD,KAAK;aACN,CAAC;YAEF,4DAA4D;YAC5D,SAAS,EAAE,MAAM,CAAC,EAAE;SACrB,CAAA;QAED,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,IAAI,CAAC,IAAI,EAAE;YAChE,MAAM;YACN,OAAO;YACP,UAAU;YACV,MAAM;SACP,CAAC,CAAA;QAEF,OAAO,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,cAAc,IAAI,MAAM,CAAC,CAAA;IAChE,CAAC;IAED,KAAK,CAAC,WAAW,CACf,MAAc,EACd,UAAsB,EACtB,cAA+B,EAC/B,OAAgB,EAChB,QAAyB,EACzB,UAA+C,EAC/C,IAAU;QAEV,MAAM,IAAI,CAAC,mBAAmB,CAAC,MAAM,EAAE,UAAU,EAAE,UAAU,CAAC,CAAA;QAE9D,MAAM,OAAO,GAAG,MAAM,IAAA,6BAAe,GAAE,CAAA;QACvC,MAAM,YAAY,GAAG,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,QAAQ,CAAC,eAAe,CAAC;YACxE,CAAC,CAAC,MAAM,IAAA,uCAAoB,GAAE;YAC9B,CAAC,CAAC,SAAS,CAAA;QAEb,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAA;QACtB,MAAM,SAAS,GAAG,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAA;QAE7C,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,cAAc;aACpC,eAAe,CAAC,UAAU,CAAC,KAAM,CAAC;aAClC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YACb,wBAAwB;YACxB,IAAI,GAAG,YAAY,+BAAgB,EAAE,CAAC;gBACpC,MAAM,IAAI,8CAAmB,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,CAAA;YACjD,CAAC;YAED,mBAAmB;YACnB,MAAM,GAAG,CAAA;QACX,CAAC,CAAC,CAAA;QAEJ,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAC9C,OAAO,EACP,MAAM,EACN,OAAO,EACP,UAAU,EACV,GAAG,EACH,SAAS,EACT,KAAK,CACN,CAAA;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,kBAAkB,CACtC,cAAc,CAAC,UAAU,CAAC,EAC1B,WAAW,EACX,YAAY,EACZ,SAAS,EACT,OAAO,CAAC,GAAG,EACX,KAAK,CACN,CAAA;QAED,MAAM,SAAS,GAAoB;YACjC,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,GAAG;YACd,SAAS;YACT,QAAQ,EAAE,MAAM,CAAC,EAAE;YACnB,UAAU;YACV,QAAQ;YACR,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,UAAU;YACV,OAAO,EAAE,IAAI;YACb,KAAK;YACL,IAAI;SACL,CAAA;QAED,MAAM,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,OAAO,EAAE,SAAS,EAAE,YAAY,CAAC,CAAA;QAE9D,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,IAAI,CAAC,IAAI,EAAE;gBAC1C,MAAM;gBACN,UAAU;gBACV,cAAc;gBACd,OAAO;gBACP,UAAU;aACX,CAAC,CAAA;YAEF,OAAO,QAAQ,CAAA;QACjB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,qEAAqE;YACrE,sBAAsB;YACtB,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAA;YAC/B,MAAM,GAAG,CAAA;QACX,CAAC;IACH,CAAC;IAES,KAAK,CAAC,mBAAmB,CACjC,MAAc,EACd,UAAsB,EACtB,UAA+C;QAE/C,IAAI,MAAM,CAAC,QAAQ,CAAC,wBAAwB,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAC;YACrE,MAAM,IAAI,0CAAiB,CACzB,mDAAmD,CACpD,CAAA;QACH,CAAC;IACH,CAAC;IAES,kBAAkB,CAC1B,SAAyB,EACzB,WAA6B,EAC7B,YAAgC,EAChC,SAAe,EACf,GAAQ,EACR,KAAa;QAEb,OAAO;YACL,YAAY,EAAE,WAAW;YACzB,UAAU,EAAE,SAAS;YACrB,aAAa,EAAE,YAAY;YAC3B,KAAK;YAEL,qEAAqE;YACrE,0EAA0E;YAC1E,IAAI,UAAU;gBACZ,OAAO,IAAA,+BAAqB,EAAC,SAAS,CAAC,CAAA;YACzC,CAAC;YAED,sEAAsE;YACtE,qEAAqE;YACrE,aAAa;YACb,GAAG;SACJ,CAAA;IACH,CAAC;IAED,KAAK,CAAC,WAAW,CACf,MAAc,EACd,UAAsB,EACtB,cAA+B,EAC/B,SAAoB;QAEpB,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,SAAS,CAAA;QACnC,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAA;QAE3B,MAAM,IAAI,CAAC,mBAAmB,CAAC,MAAM,EAAE,UAAU,EAAE,UAAU,CAAC,CAAA;QAE9D,MAAM,WAAW,GAAG,MAAM,IAAA,6BAAe,GAAE,CAAA;QAC3C,MAAM,gBAAgB,GAAG,MAAM,IAAA,uCAAoB,GAAE,CAAA;QAErD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAA;QACtB,MAAM,SAAS,GAAG,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAA;QAE7C,oEAAoE;QACpE,wEAAwE;QACxE,iCAAiC;QACjC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,eAAe,CAAC,UAAU,CAAC,KAAM,CAAC,CAAA;QAE1E,MAAM,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE,EAAE,WAAW,EAAE,gBAAgB,EAAE;YACxE,SAAS,EAAE,GAAG;YACd,SAAS;YACT,qEAAqE;YACrE,cAAc;YACd,qEAAqE;YACrE,kBAAkB;YAClB,mEAAmE;YACnE,aAAa;YACb,UAAU;YACV,KAAK;SACN,CAAC,CAAA;QAEF,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAC9C,WAAW,EACX,MAAM,EACN,OAAO,EACP,UAAU,EACV,GAAG,EACH,SAAS,EACT,KAAK,CACN,CAAA;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,kBAAkB,CACtC,cAAc,CAAC,UAAU,CAAC,EAC1B,WAAW,EACX,gBAAgB,EAChB,SAAS,EACT,OAAO,CAAC,GAAG,EACX,KAAK,CACN,CAAA;QAED,MAAM,IAAI,CAAC,KAAK,CAAC,gBAAgB,EAAE,IAAI,CAAC,IAAI,EAAE;YAC5C,MAAM;YACN,UAAU;YACV,cAAc;YACd,OAAO;YACP,UAAU;SACX,CAAC,CAAA;QAEF,OAAO,QAAQ,CAAA;IACjB,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,SAAS,CAAC,KAAa;QAClC,IAAI,IAAA,uBAAS,EAAC,KAAK,CAAC,EAAE,CAAC;YACrB,OAAO,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAA;QACjC,CAAC;aAAM,IAAI,IAAA,gBAAM,EAAC,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAA;QAC/B,CAAC;aAAM,IAAI,IAAA,iCAAc,EAAC,KAAK,CAAC,EAAE,CAAC;YACjC,OAAO,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAA;QACvC,CAAC;aAAM,IAAI,IAAA,iBAAW,EAAC,KAAK,CAAC,EAAE,CAAC;YAC9B,OAAO,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAA;QACtC,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,8CAAmB,CAAC,eAAe,CAAC,CAAA;QAChD,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,iBAAiB,CAAC,KAAgB;QAC7C,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,KAAK,EAAE;YAC7D,cAAc,EAAE,QAAQ;SACzB,CAAC,CAAA;QAEF,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QACtD,IAAI,CAAC,SAAS;YAAE,OAAO,IAAI,CAAA;QAE3B,6CAA6C;QAC7C,IAAI,OAAO,CAAC,GAAG,KAAK,SAAS,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;YAC1C,MAAM,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE,CAAC,CAAA;YACpC,MAAM,IAAI,KAAK,CACb,gBAAgB,SAAS,CAAC,OAAO,CAAC,GAAG,+BAA+B,OAAO,CAAC,GAAG,GAAG,CACnF,CAAA;QACH,CAAC;QAED,OAAO,SAAS,CAAA;IAClB,CAAC;IAES,KAAK,CAAC,kBAAkB,CAChC,KAAmB;QAEnB,OAAO,IAAI,CAAC,KAAK,CAAC,uBAAuB,CAAC,KAAK,CAAC,CAAA;IAClD,CAAC;IAEM,KAAK,CAAC,mBAAmB,CAAC,KAAmB;QAClD,2EAA2E;QAC3E,0EAA0E;QAC1E,4EAA4E;QAC5E,yEAAyE;QACzE,oEAAoE;QACpE,yEAAyE;QACzE,uEAAuE;QAEvE,4EAA4E;QAC5E,eAAe;QACf,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YACnE,MAAM,0CAAiB,CAAC,IAAI,CAAC,GAAG,EAAE,uBAAuB,CAAC,CAAA;QAC5D,CAAC,CAAC,CAAA;QAEF,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,0CAAiB,CAAC,uBAAuB,CAAC,CAAA;QACtD,CAAC;QAED,IAAI,SAAS,CAAC,mBAAmB,KAAK,KAAK,EAAE,CAAC;YAC5C,MAAM,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE,CAAC,CAAA;YACpC,MAAM,IAAI,0CAAiB,CAAC,wBAAwB,CAAC,CAAA;QACvD,CAAC;QAED,OAAO,SAAS,CAAA;IAClB,CAAC;IAEM,KAAK,CAAC,UAAU,CAAC,IAAU;QAChC,OAAO,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,IAAI,CAAC,CAAA;IACzC,CAAC;IAEM,KAAK,CAAC,WAAW,CAAC,OAAgB;QACvC,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,CAAA;IACxC,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,OAAgB;QACjC,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;IACtC,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,eAAe,CACnB,SAAyB,EACzB,YAAgC;QAEhC,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,CAAA;QAChC,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YAC/D,MAAM,0CAAiB,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAA;QAC9C,CAAC,CAAC,CAAA;QAEF,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,0CAAiB,CAAC,SAAS,EAAE,eAAe,CAAC,CAAA;QACzD,CAAC;QAED,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,SAAS,CAAA;QAEnC,0EAA0E;QAC1E,4EAA4E;QAC5E,uBAAuB;QACvB,IAAI,YAAY,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAC;YACvD,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAA;YAC/B,MAAM,IAAI,0CAAiB,CAAC,SAAS,EAAE,eAAe,CAAC,CAAA;QACzD,CAAC;QAED,IAAI,qBAAqB,CAAC,SAAS,CAAC,EAAE,CAAC;YACrC,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAA;YAC/B,MAAM,IAAI,0CAAiB,CAAC,SAAS,EAAE,eAAe,CAAC,CAAA;QACzD,CAAC;QAED,OAAO;YACL,GAAG,EAAE,OAAO;YACZ,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,GAAG,EAAE,IAAA,qBAAW,EAAC,IAAI,CAAC,SAAS,CAAC;YAChC,GAAG,EAAE,IAAA,qBAAW,EAAC,IAAI,CAAC,SAAS,CAAC;YAChC,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK;YAC1C,4DAA4D;YAC5D,SAAS,EAAE,IAAI,CAAC,QAAQ;SACzB,CAAA;IACH,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,GAAQ;QAC9B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAA;QACvD,OAAO,OAAO;aACX,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC,aAAa;aAClE,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC,CAAA;IAC7D,CAAC;CACF;AAvXD,oCAuXC;AAED,SAAS,qBAAqB,CAAC,SAAoB;IACjD,OAAO,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;AACxD,CAAC;AAED,SAAS,cAAc,CACrB,UAA+C;IAE/C,IAAI,UAAU,CAAC,QAAQ,EAAE,CAAC;QACxB,OAAO,MAAM,CAAA;IACf,CAAC;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC","sourcesContent":["import { SignedJwt, isSignedJwt } from '@atproto/jwk'\nimport { LexResolverError } from '@atproto/lex-resolver'\nimport type { Account } from '@atproto/oauth-provider-api'\nimport {\n OAuthAccessToken,\n OAuthAuthorizationRequestParameters,\n OAuthScope,\n OAuthTokenResponse,\n OAuthTokenType,\n} from '@atproto/oauth-types'\nimport { AccessTokenMode } from '../access-token/access-token-mode.js'\nimport { ClientAuth } from '../client/client-auth.js'\nimport { Client } from '../client/client.js'\nimport { TOKEN_MAX_AGE } from '../constants.js'\nimport { DeviceId } from '../device/device-id.js'\nimport { InvalidGrantError } from '../errors/invalid-grant-error.js'\nimport { InvalidRequestError } from '../errors/invalid-request-error.js'\nimport { InvalidTokenError } from '../errors/invalid-token-error.js'\nimport { LexiconManager } from '../lexicon/lexicon-manager.js'\nimport { RequestMetadata } from '../lib/http/request.js'\nimport { dateToEpoch, dateToRelativeSeconds } from '../lib/util/date.js'\nimport { OAuthHooks } from '../oauth-hooks.js'\nimport { Sub } from '../oidc/sub.js'\nimport { Code, isCode } from '../request/code.js'\nimport { AccessTokenPayload } from '../signer/access-token-payload.js'\nimport { Signer } from '../signer/signer.js'\nimport {\n RefreshToken,\n generateRefreshToken,\n isRefreshToken,\n} from './refresh-token.js'\nimport { TokenClaims } from './token-claims.js'\nimport { TokenId, generateTokenId, isTokenId } from './token-id.js'\nimport { CreateTokenData, TokenInfo, TokenStore } from './token-store.js'\n\nexport { AccessTokenMode, Signer }\nexport type { OAuthHooks, TokenStore }\n\nexport class TokenManager {\n constructor(\n protected readonly store: TokenStore,\n protected readonly lexiconManager: LexiconManager,\n protected readonly signer: Signer,\n protected readonly hooks: OAuthHooks,\n protected readonly accessTokenMode: AccessTokenMode,\n protected readonly tokenMaxAge = TOKEN_MAX_AGE,\n ) {}\n\n protected createTokenExpiry(now = new Date()) {\n return new Date(now.getTime() + this.tokenMaxAge)\n }\n\n protected async createAccessToken(\n tokenId: TokenId,\n client: Client,\n account: Account,\n parameters: OAuthAuthorizationRequestParameters,\n issuedAt: Date,\n expiresAt: Date,\n scope: OAuthScope,\n ): Promise<OAuthAccessToken> {\n const claims: TokenClaims = {\n jti: tokenId,\n sub: account.sub,\n iat: dateToEpoch(issuedAt),\n exp: dateToEpoch(expiresAt),\n aud: account.aud,\n\n ...(parameters.dpop_jkt && {\n cnf: { jkt: parameters.dpop_jkt },\n }),\n\n // Because tokens can end-up being quite big, we only include the scope in\n // stateless mode.\n ...(this.accessTokenMode === AccessTokenMode.stateless && {\n scope,\n }),\n\n // https://datatracker.ietf.org/doc/html/rfc8693#section-4.3\n client_id: client.id,\n }\n\n const claimsOverride = await this.hooks.onCreateToken?.call(null, {\n client,\n account,\n parameters,\n claims,\n })\n\n return this.signer.createAccessToken(claimsOverride ?? claims)\n }\n\n async createToken(\n client: Client,\n clientAuth: ClientAuth,\n clientMetadata: RequestMetadata,\n account: Account,\n deviceId: null | DeviceId,\n parameters: OAuthAuthorizationRequestParameters,\n code: Code,\n ): Promise<OAuthTokenResponse> {\n await this.validateTokenParams(client, clientAuth, parameters)\n\n const tokenId = await generateTokenId()\n const refreshToken = client.metadata.grant_types.includes('refresh_token')\n ? await generateRefreshToken()\n : undefined\n\n const now = new Date()\n const expiresAt = this.createTokenExpiry(now)\n\n const scope = await this.lexiconManager\n .buildTokenScope(parameters.scope!)\n .catch((err) => {\n // Parse expected errors\n if (err instanceof LexResolverError) {\n throw new InvalidRequestError(err.message, err)\n }\n\n // Unexpected error\n throw err\n })\n\n const accessToken = await this.createAccessToken(\n tokenId,\n client,\n account,\n parameters,\n now,\n expiresAt,\n scope,\n )\n\n const response = this.buildTokenResponse(\n inferTokenType(parameters),\n accessToken,\n refreshToken,\n expiresAt,\n account.sub,\n scope,\n )\n\n const tokenData: CreateTokenData = {\n createdAt: now,\n updatedAt: now,\n expiresAt,\n clientId: client.id,\n clientAuth,\n deviceId,\n sub: account.sub,\n parameters,\n details: null,\n scope,\n code,\n }\n\n await this.store.createToken(tokenId, tokenData, refreshToken)\n\n try {\n await this.hooks.onTokenCreated?.call(null, {\n client,\n clientAuth,\n clientMetadata,\n account,\n parameters,\n })\n\n return response\n } catch (err) {\n // If the hook fails, we delete the token to avoid leaving a dangling\n // token in the store.\n await this.deleteToken(tokenId)\n throw err\n }\n }\n\n protected async validateTokenParams(\n client: Client,\n clientAuth: ClientAuth,\n parameters: OAuthAuthorizationRequestParameters,\n ): Promise<void> {\n if (client.metadata.dpop_bound_access_tokens && !parameters.dpop_jkt) {\n throw new InvalidGrantError(\n `DPoP JKT is required for DPoP bound access tokens`,\n )\n }\n }\n\n protected buildTokenResponse(\n tokenType: OAuthTokenType,\n accessToken: OAuthAccessToken,\n refreshToken: string | undefined,\n expiresAt: Date,\n sub: Sub,\n scope: string,\n ): OAuthTokenResponse {\n return {\n access_token: accessToken,\n token_type: tokenType,\n refresh_token: refreshToken,\n scope,\n\n // @NOTE using a getter so that the value gets computed when the JSON\n // response is generated, allowing to value to be as accurate as possible.\n get expires_in() {\n return dateToRelativeSeconds(expiresAt)\n },\n\n // ATPROTO extension: add the sub claim to the token response to allow\n // clients to resolve the PDS url (audience) using the did resolution\n // mechanism.\n sub,\n }\n }\n\n async rotateToken(\n client: Client,\n clientAuth: ClientAuth,\n clientMetadata: RequestMetadata,\n tokenInfo: TokenInfo,\n ): Promise<OAuthTokenResponse> {\n const { account, data } = tokenInfo\n const { parameters } = data\n\n await this.validateTokenParams(client, clientAuth, parameters)\n\n const nextTokenId = await generateTokenId()\n const nextRefreshToken = await generateRefreshToken()\n\n const now = new Date()\n const expiresAt = this.createTokenExpiry(now)\n\n // @NOTE since the permission sets are stored in a persistent store,\n // it's fine to propagate a 500 (server_error) here as the values should\n // be retrievable from the store.\n const scope = await this.lexiconManager.buildTokenScope(parameters.scope!)\n\n await this.store.rotateToken(tokenInfo.id, nextTokenId, nextRefreshToken, {\n updatedAt: now,\n expiresAt,\n // @NOTE Normally, the clientAuth not change over time. There are two\n // exceptions:\n // - Upgrade from a legacy representation of client authentication to\n // a modern one.\n // - Allow clients to become \"confidential\" if they were previously\n // \"public\"\n clientAuth,\n scope,\n })\n\n const accessToken = await this.createAccessToken(\n nextTokenId,\n client,\n account,\n parameters,\n now,\n expiresAt,\n scope,\n )\n\n const response = this.buildTokenResponse(\n inferTokenType(parameters),\n accessToken,\n nextRefreshToken,\n expiresAt,\n account.sub,\n scope,\n )\n\n await this.hooks.onTokenRefreshed?.call(null, {\n client,\n clientAuth,\n clientMetadata,\n account,\n parameters,\n })\n\n return response\n }\n\n /**\n * @note The token validity is not guaranteed. The caller must ensure that the\n * token is valid before using the returned token info.\n */\n public async findToken(token: string): Promise<null | TokenInfo> {\n if (isTokenId(token)) {\n return this.getTokenInfo(token)\n } else if (isCode(token)) {\n return this.findByCode(token)\n } else if (isRefreshToken(token)) {\n return this.findByRefreshToken(token)\n } else if (isSignedJwt(token)) {\n return this.findByAccessToken(token)\n } else {\n throw new InvalidRequestError(`Invalid token`)\n }\n }\n\n public async findByAccessToken(token: SignedJwt): Promise<null | TokenInfo> {\n const { payload } = await this.signer.verifyAccessToken(token, {\n clockTolerance: Infinity,\n })\n\n const tokenInfo = await this.getTokenInfo(payload.jti)\n if (!tokenInfo) return null\n\n // Fool-proof: Invalid store implementation ?\n if (payload.sub !== tokenInfo.account.sub) {\n await this.deleteToken(tokenInfo.id)\n throw new Error(\n `Account sub (${tokenInfo.account.sub}) does not match token sub (${payload.sub})`,\n )\n }\n\n return tokenInfo\n }\n\n protected async findByRefreshToken(\n token: RefreshToken,\n ): Promise<null | TokenInfo> {\n return this.store.findTokenByRefreshToken(token)\n }\n\n public async consumeRefreshToken(token: RefreshToken): Promise<TokenInfo> {\n // @NOTE concurrent refreshes of the same refresh token could theoretically\n // lead to two new tokens (access & refresh) being created. This is deemed\n // acceptable for now (as the mechanism can only be used once since only one\n // of the two refresh token created will be valid, and any future refresh\n // attempts from outdated tokens will cause the entire session to be\n // invalidated). Ideally, the store should be able to handle this case by\n // atomically consuming the refresh token and returning the token info.\n\n // @TODO Add another store method that atomically consumes the refresh token\n // with a lock.\n const tokenInfo = await this.findByRefreshToken(token).catch((err) => {\n throw InvalidGrantError.from(err, `Invalid refresh token`)\n })\n\n if (!tokenInfo) {\n throw new InvalidGrantError(`Invalid refresh token`)\n }\n\n if (tokenInfo.currentRefreshToken !== token) {\n await this.deleteToken(tokenInfo.id)\n throw new InvalidGrantError(`Refresh token replayed`)\n }\n\n return tokenInfo\n }\n\n public async findByCode(code: Code): Promise<null | TokenInfo> {\n return this.store.findTokenByCode(code)\n }\n\n public async deleteToken(tokenId: TokenId): Promise<void> {\n return this.store.deleteToken(tokenId)\n }\n\n async getTokenInfo(tokenId: TokenId): Promise<null | TokenInfo> {\n return this.store.readToken(tokenId)\n }\n\n /**\n * This method is called to when decoding a token that was encoded in\n * {@link AccessTokenMode.light} mode, using data from the store to fill the\n * data that was omitted in the token itself.\n */\n async loadTokenClaims(\n tokenType: OAuthTokenType,\n tokenPayload: AccessTokenPayload,\n ): Promise<TokenClaims> {\n const tokenId = tokenPayload.jti\n const tokenInfo = await this.getTokenInfo(tokenId).catch((err) => {\n throw InvalidTokenError.from(err, tokenType)\n })\n\n if (!tokenInfo) {\n throw new InvalidTokenError(tokenType, `Invalid token`)\n }\n\n const { account, data } = tokenInfo\n\n // Fool proof, make sure that the database & token payload are consistent.\n // These should both be either undefined or a string so it's safe to compare\n // the values directly.\n if (tokenPayload.cnf?.jkt !== data.parameters.dpop_jkt) {\n await this.deleteToken(tokenId)\n throw new InvalidTokenError(tokenType, `Invalid token`)\n }\n\n if (isCurrentTokenExpired(tokenInfo)) {\n await this.deleteToken(tokenId)\n throw new InvalidTokenError(tokenType, `Token expired`)\n }\n\n return {\n jti: tokenId,\n sub: account.sub,\n iat: dateToEpoch(data.updatedAt),\n exp: dateToEpoch(data.expiresAt),\n aud: account.aud,\n scope: data.scope ?? data.parameters.scope,\n // https://datatracker.ietf.org/doc/html/rfc8693#section-4.3\n client_id: data.clientId,\n }\n }\n\n async listAccountTokens(sub: Sub): Promise<TokenInfo[]> {\n const results = await this.store.listAccountTokens(sub)\n return results\n .filter((tokenInfo) => tokenInfo.account.sub === sub) // Fool proof\n .filter((tokenInfo) => !isCurrentTokenExpired(tokenInfo))\n }\n}\n\nfunction isCurrentTokenExpired(tokenInfo: TokenInfo): boolean {\n return tokenInfo.data.expiresAt.getTime() < Date.now()\n}\n\nfunction inferTokenType(\n parameters: OAuthAuthorizationRequestParameters,\n): OAuthTokenType {\n if (parameters.dpop_jkt) {\n return 'DPoP'\n }\n return 'Bearer'\n}\n"]}
1
+ {"version":3,"file":"token-manager.js","sourceRoot":"","sources":["../../src/token/token-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import { SignedJwt, isSignedJwt } from '@atproto/jwk'\nimport { LexResolverError } from '@atproto/lex-resolver'\nimport type { Account } from '@atproto/oauth-provider-api'\nimport {\n OAuthAccessToken,\n OAuthAuthorizationRequestParameters,\n OAuthScope,\n OAuthTokenResponse,\n OAuthTokenType,\n} from '@atproto/oauth-types'\nimport { AccessTokenMode } from '../access-token/access-token-mode.js'\nimport { ClientAuth } from '../client/client-auth.js'\nimport { Client } from '../client/client.js'\nimport { TOKEN_MAX_AGE } from '../constants.js'\nimport { DeviceId } from '../device/device-id.js'\nimport { InvalidGrantError } from '../errors/invalid-grant-error.js'\nimport { InvalidRequestError } from '../errors/invalid-request-error.js'\nimport { InvalidTokenError } from '../errors/invalid-token-error.js'\nimport { LexiconManager } from '../lexicon/lexicon-manager.js'\nimport { RequestMetadata } from '../lib/http/request.js'\nimport { dateToEpoch, dateToRelativeSeconds } from '../lib/util/date.js'\nimport { OAuthHooks } from '../oauth-hooks.js'\nimport { Sub } from '../oidc/sub.js'\nimport { Code, isCode } from '../request/code.js'\nimport { AccessTokenPayload } from '../signer/access-token-payload.js'\nimport { Signer } from '../signer/signer.js'\nimport {\n RefreshToken,\n generateRefreshToken,\n isRefreshToken,\n} from './refresh-token.js'\nimport { TokenClaims } from './token-claims.js'\nimport { TokenId, generateTokenId, isTokenId } from './token-id.js'\nimport { CreateTokenData, TokenInfo, TokenStore } from './token-store.js'\n\nexport { AccessTokenMode, Signer }\nexport type { OAuthHooks, TokenStore }\n\nexport class TokenManager {\n constructor(\n protected readonly store: TokenStore,\n protected readonly lexiconManager: LexiconManager,\n protected readonly signer: Signer,\n protected readonly hooks: OAuthHooks,\n protected readonly accessTokenMode: AccessTokenMode,\n protected readonly tokenMaxAge = TOKEN_MAX_AGE,\n ) {}\n\n protected createTokenExpiry(now = new Date()) {\n return new Date(now.getTime() + this.tokenMaxAge)\n }\n\n protected async createAccessToken(\n tokenId: TokenId,\n client: Client,\n account: Account,\n parameters: OAuthAuthorizationRequestParameters,\n issuedAt: Date,\n expiresAt: Date,\n scope: OAuthScope,\n ): Promise<OAuthAccessToken> {\n const claims: TokenClaims = {\n jti: tokenId,\n sub: account.sub,\n iat: dateToEpoch(issuedAt),\n exp: dateToEpoch(expiresAt),\n aud: account.aud,\n\n ...(parameters.dpop_jkt && {\n cnf: { jkt: parameters.dpop_jkt },\n }),\n\n // Because tokens can end-up being quite big, we only include the scope in\n // stateless mode.\n ...(this.accessTokenMode === AccessTokenMode.stateless && {\n scope,\n }),\n\n // https://datatracker.ietf.org/doc/html/rfc8693#section-4.3\n client_id: client.id,\n }\n\n const claimsOverride = await this.hooks.onCreateToken?.call(null, {\n client,\n account,\n parameters,\n claims,\n })\n\n return this.signer.createAccessToken(claimsOverride ?? claims)\n }\n\n async createToken(\n client: Client,\n clientAuth: ClientAuth,\n clientMetadata: RequestMetadata,\n account: Account,\n deviceId: null | DeviceId,\n parameters: OAuthAuthorizationRequestParameters,\n code: Code,\n ): Promise<OAuthTokenResponse> {\n await this.validateTokenParams(client, clientAuth, parameters)\n\n const tokenId = await generateTokenId()\n const refreshToken = client.metadata.grant_types.includes('refresh_token')\n ? await generateRefreshToken()\n : undefined\n\n const now = new Date()\n const expiresAt = this.createTokenExpiry(now)\n\n const scope = await this.lexiconManager\n .buildTokenScope(parameters.scope!)\n .catch((err) => {\n // Parse expected errors\n if (err instanceof LexResolverError) {\n throw new InvalidRequestError(err.message, err)\n }\n\n // Unexpected error\n throw err\n })\n\n const accessToken = await this.createAccessToken(\n tokenId,\n client,\n account,\n parameters,\n now,\n expiresAt,\n scope,\n )\n\n const response = this.buildTokenResponse(\n inferTokenType(parameters),\n accessToken,\n refreshToken,\n expiresAt,\n account.sub,\n scope,\n )\n\n const tokenData: CreateTokenData = {\n createdAt: now,\n updatedAt: now,\n expiresAt,\n clientId: client.id,\n clientAuth,\n deviceId,\n sub: account.sub,\n parameters,\n details: null,\n scope,\n code,\n }\n\n await this.store.createToken(tokenId, tokenData, refreshToken)\n\n try {\n await this.hooks.onTokenCreated?.call(null, {\n client,\n clientAuth,\n clientMetadata,\n account,\n parameters,\n })\n\n return response\n } catch (err) {\n // If the hook fails, we delete the token to avoid leaving a dangling\n // token in the store.\n await this.deleteToken(tokenId)\n throw err\n }\n }\n\n protected async validateTokenParams(\n client: Client,\n clientAuth: ClientAuth,\n parameters: OAuthAuthorizationRequestParameters,\n ): Promise<void> {\n if (client.metadata.dpop_bound_access_tokens && !parameters.dpop_jkt) {\n throw new InvalidGrantError(\n `DPoP JKT is required for DPoP bound access tokens`,\n )\n }\n }\n\n protected buildTokenResponse(\n tokenType: OAuthTokenType,\n accessToken: OAuthAccessToken,\n refreshToken: string | undefined,\n expiresAt: Date,\n sub: Sub,\n scope: string,\n ): OAuthTokenResponse {\n return {\n access_token: accessToken,\n token_type: tokenType,\n refresh_token: refreshToken,\n scope,\n\n // @NOTE using a getter so that the value gets computed when the JSON\n // response is generated, allowing to value to be as accurate as possible.\n get expires_in() {\n return dateToRelativeSeconds(expiresAt)\n },\n\n // ATPROTO extension: add the sub claim to the token response to allow\n // clients to resolve the PDS url (audience) using the did resolution\n // mechanism.\n sub,\n }\n }\n\n async rotateToken(\n client: Client,\n clientAuth: ClientAuth,\n clientMetadata: RequestMetadata,\n tokenInfo: TokenInfo,\n ): Promise<OAuthTokenResponse> {\n const { account, data } = tokenInfo\n const { parameters } = data\n\n await this.validateTokenParams(client, clientAuth, parameters)\n\n const nextTokenId = await generateTokenId()\n const nextRefreshToken = await generateRefreshToken()\n\n const now = new Date()\n const expiresAt = this.createTokenExpiry(now)\n\n // @NOTE since the permission sets are stored in a persistent store,\n // it's fine to propagate a 500 (server_error) here as the values should\n // be retrievable from the store.\n const scope = await this.lexiconManager.buildTokenScope(parameters.scope!)\n\n await this.store.rotateToken(tokenInfo.id, nextTokenId, nextRefreshToken, {\n updatedAt: now,\n expiresAt,\n // @NOTE Normally, the clientAuth not change over time. There are two\n // exceptions:\n // - Upgrade from a legacy representation of client authentication to\n // a modern one.\n // - Allow clients to become \"confidential\" if they were previously\n // \"public\"\n clientAuth,\n scope,\n })\n\n const accessToken = await this.createAccessToken(\n nextTokenId,\n client,\n account,\n parameters,\n now,\n expiresAt,\n scope,\n )\n\n const response = this.buildTokenResponse(\n inferTokenType(parameters),\n accessToken,\n nextRefreshToken,\n expiresAt,\n account.sub,\n scope,\n )\n\n await this.hooks.onTokenRefreshed?.call(null, {\n client,\n clientAuth,\n clientMetadata,\n account,\n parameters,\n })\n\n return response\n }\n\n /**\n * @note The token validity is not guaranteed. The caller must ensure that the\n * token is valid before using the returned token info.\n */\n public async findToken(token: string): Promise<null | TokenInfo> {\n if (isTokenId(token)) {\n return this.getTokenInfo(token)\n } else if (isCode(token)) {\n return this.findByCode(token)\n } else if (isRefreshToken(token)) {\n return this.findByRefreshToken(token)\n } else if (isSignedJwt(token)) {\n return this.findByAccessToken(token)\n } else {\n throw new InvalidRequestError(`Invalid token`)\n }\n }\n\n public async findByAccessToken(token: SignedJwt): Promise<null | TokenInfo> {\n const { payload } = await this.signer.verifyAccessToken(token, {\n clockTolerance: Infinity,\n })\n\n const tokenInfo = await this.getTokenInfo(payload.jti)\n if (!tokenInfo) return null\n\n // Fool-proof: Invalid store implementation ?\n if (payload.sub !== tokenInfo.account.sub) {\n await this.deleteToken(tokenInfo.id)\n throw new Error(\n `Account sub (${tokenInfo.account.sub}) does not match token sub (${payload.sub})`,\n )\n }\n\n return tokenInfo\n }\n\n protected async findByRefreshToken(\n token: RefreshToken,\n ): Promise<null | TokenInfo> {\n return this.store.findTokenByRefreshToken(token)\n }\n\n public async consumeRefreshToken(token: RefreshToken): Promise<TokenInfo> {\n // @NOTE concurrent refreshes of the same refresh token could theoretically\n // lead to two new tokens (access & refresh) being created. This is deemed\n // acceptable for now (as the mechanism can only be used once since only one\n // of the two refresh token created will be valid, and any future refresh\n // attempts from outdated tokens will cause the entire session to be\n // invalidated). Ideally, the store should be able to handle this case by\n // atomically consuming the refresh token and returning the token info.\n\n // @TODO Add another store method that atomically consumes the refresh token\n // with a lock.\n const tokenInfo = await this.findByRefreshToken(token).catch((err) => {\n throw InvalidGrantError.from(err, `Invalid refresh token`)\n })\n\n if (!tokenInfo) {\n throw new InvalidGrantError(`Invalid refresh token`)\n }\n\n if (tokenInfo.currentRefreshToken !== token) {\n await this.deleteToken(tokenInfo.id)\n throw new InvalidGrantError(`Refresh token replayed`)\n }\n\n return tokenInfo\n }\n\n public async findByCode(code: Code): Promise<null | TokenInfo> {\n return this.store.findTokenByCode(code)\n }\n\n public async deleteToken(tokenId: TokenId): Promise<void> {\n return this.store.deleteToken(tokenId)\n }\n\n async getTokenInfo(tokenId: TokenId): Promise<null | TokenInfo> {\n return this.store.readToken(tokenId)\n }\n\n /**\n * This method is called to when decoding a token that was encoded in\n * {@link AccessTokenMode.light} mode, using data from the store to fill the\n * data that was omitted in the token itself.\n */\n async loadTokenClaims(\n tokenType: OAuthTokenType,\n tokenPayload: AccessTokenPayload,\n ): Promise<TokenClaims> {\n const tokenId = tokenPayload.jti\n const tokenInfo = await this.getTokenInfo(tokenId).catch((err) => {\n throw InvalidTokenError.from(err, tokenType)\n })\n\n if (!tokenInfo) {\n throw new InvalidTokenError(tokenType, `Invalid token`)\n }\n\n const { account, data } = tokenInfo\n\n // Fool proof, make sure that the database & token payload are consistent.\n // These should both be either undefined or a string so it's safe to compare\n // the values directly.\n if (tokenPayload.cnf?.jkt !== data.parameters.dpop_jkt) {\n await this.deleteToken(tokenId)\n throw new InvalidTokenError(tokenType, `Invalid token`)\n }\n\n if (isCurrentTokenExpired(tokenInfo)) {\n await this.deleteToken(tokenId)\n throw new InvalidTokenError(tokenType, `Token expired`)\n }\n\n return {\n jti: tokenId,\n sub: account.sub,\n iat: dateToEpoch(data.updatedAt),\n exp: dateToEpoch(data.expiresAt),\n aud: account.aud,\n scope: data.scope ?? data.parameters.scope,\n // https://datatracker.ietf.org/doc/html/rfc8693#section-4.3\n client_id: data.clientId,\n }\n }\n\n async listAccountTokens(sub: Sub): Promise<TokenInfo[]> {\n const results = await this.store.listAccountTokens(sub)\n return results\n .filter((tokenInfo) => tokenInfo.account.sub === sub) // Fool proof\n .filter((tokenInfo) => !isCurrentTokenExpired(tokenInfo))\n }\n}\n\nfunction isCurrentTokenExpired(tokenInfo: TokenInfo): boolean {\n return tokenInfo.data.expiresAt.getTime() < Date.now()\n}\n\nfunction inferTokenType(\n parameters: OAuthAuthorizationRequestParameters,\n): OAuthTokenType {\n if (parameters.dpop_jkt) {\n return 'DPoP'\n }\n return 'Bearer'\n}\n"]}
@@ -1,27 +1,9 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.isTokenStore = void 0;
18
- exports.asTokenStore = asTokenStore;
19
- const type_js_1 = require("../lib/util/type.js");
1
+ import { buildInterfaceChecker } from '../lib/util/type.js';
20
2
  // Export all types needed to implement the TokenStore interface
21
- __exportStar(require("./refresh-token.js"), exports);
22
- __exportStar(require("./token-data.js"), exports);
23
- __exportStar(require("./token-id.js"), exports);
24
- exports.isTokenStore = (0, type_js_1.buildInterfaceChecker)([
3
+ export * from './refresh-token.js';
4
+ export * from './token-data.js';
5
+ export * from './token-id.js';
6
+ export const isTokenStore = buildInterfaceChecker([
25
7
  'createToken',
26
8
  'readToken',
27
9
  'deleteToken',
@@ -30,8 +12,8 @@ exports.isTokenStore = (0, type_js_1.buildInterfaceChecker)([
30
12
  'findTokenByCode',
31
13
  'listAccountTokens',
32
14
  ]);
33
- function asTokenStore(implementation) {
34
- if (!implementation || !(0, exports.isTokenStore)(implementation)) {
15
+ export function asTokenStore(implementation) {
16
+ if (!implementation || !isTokenStore(implementation)) {
35
17
  throw new Error('Invalid TokenStore implementation');
36
18
  }
37
19
  return implementation;
@@ -1 +1 @@
1
- {"version":3,"file":"token-store.js","sourceRoot":"","sources":["../../src/token/token-store.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAgFA,oCAOC;AAtFD,iDAAsE;AAOtE,gEAAgE;AAChE,qDAAkC;AAClC,kDAA+B;AAC/B,gDAA6B;AA2DhB,QAAA,YAAY,GAAG,IAAA,+BAAqB,EAAa;IAC5D,aAAa;IACb,WAAW;IACX,aAAa;IACb,aAAa;IACb,yBAAyB;IACzB,iBAAiB;IACjB,mBAAmB;CACpB,CAAC,CAAA;AAEF,SAAgB,YAAY,CAC1B,cAAkB;IAElB,IAAI,CAAC,cAAc,IAAI,CAAC,IAAA,oBAAY,EAAC,cAAc,CAAC,EAAE,CAAC;QACrD,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAA;IACtD,CAAC;IACD,OAAO,cAAc,CAAA;AACvB,CAAC","sourcesContent":["import type { Account } from '@atproto/oauth-provider-api'\nimport { Awaitable, buildInterfaceChecker } from '../lib/util/type.js'\nimport { Sub } from '../oidc/sub.js'\nimport { Code } from '../request/code.js'\nimport { RefreshToken } from './refresh-token.js'\nimport { TokenData } from './token-data.js'\nimport { TokenId } from './token-id.js'\n\n// Export all types needed to implement the TokenStore interface\nexport * from './refresh-token.js'\nexport * from './token-data.js'\nexport * from './token-id.js'\nexport type { Account, Awaitable, Sub }\n\nexport type TokenInfo = {\n id: TokenId\n data: TokenData\n account: Account\n currentRefreshToken: null | RefreshToken\n}\n\nexport type NewTokenData = {\n clientAuth: TokenData['clientAuth']\n expiresAt: TokenData['expiresAt']\n updatedAt: TokenData['updatedAt']\n scope: NonNullable<TokenData['scope']>\n}\n\nexport type CreateTokenData = TokenData & {\n scope: NonNullable<TokenData['scope']>\n}\n\n/**\n * @param data historically, {@link TokenData.scope} was not present in\n * {@link TokenData}, causing it to be \"nullable\" when returned from\n * {@link TokenStore.readToken}. We use {@link CreateTokenData} here to allow\n * the store implementation to expect its presence.\n */\nexport interface TokenStore {\n createToken(\n tokenId: TokenId,\n data: CreateTokenData,\n refreshToken?: RefreshToken,\n ): Awaitable<void>\n\n readToken(tokenId: TokenId): Awaitable<null | TokenInfo>\n\n deleteToken(tokenId: TokenId): Awaitable<void>\n\n rotateToken(\n tokenId: TokenId,\n newTokenId: TokenId,\n newRefreshToken: RefreshToken,\n newData: NewTokenData,\n ): Awaitable<void>\n\n /**\n * Find a token by its refresh token. Note that previous refresh tokens\n * should also return the token. The data model is responsible for storing\n * old refresh tokens when a new one is issued.\n */\n findTokenByRefreshToken(\n refreshToken: RefreshToken,\n ): Awaitable<null | TokenInfo>\n\n findTokenByCode(code: Code): Awaitable<null | TokenInfo>\n\n listAccountTokens(sub: Sub): Awaitable<TokenInfo[]>\n}\n\nexport const isTokenStore = buildInterfaceChecker<TokenStore>([\n 'createToken',\n 'readToken',\n 'deleteToken',\n 'rotateToken',\n 'findTokenByRefreshToken',\n 'findTokenByCode',\n 'listAccountTokens',\n])\n\nexport function asTokenStore<V extends Partial<TokenStore>>(\n implementation?: V,\n): V & TokenStore {\n if (!implementation || !isTokenStore(implementation)) {\n throw new Error('Invalid TokenStore implementation')\n }\n return implementation\n}\n"]}
1
+ {"version":3,"file":"token-store.js","sourceRoot":"","sources":["../../src/token/token-store.ts"],"names":[],"mappings":"AACA,OAAO,EAAa,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAOtE,gEAAgE;AAChE,cAAc,oBAAoB,CAAA;AAClC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,eAAe,CAAA;AA2D7B,MAAM,CAAC,MAAM,YAAY,GAAG,qBAAqB,CAAa;IAC5D,aAAa;IACb,WAAW;IACX,aAAa;IACb,aAAa;IACb,yBAAyB;IACzB,iBAAiB;IACjB,mBAAmB;CACpB,CAAC,CAAA;AAEF,MAAM,UAAU,YAAY,CAC1B,cAAkB;IAElB,IAAI,CAAC,cAAc,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC;QACrD,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAA;IACtD,CAAC;IACD,OAAO,cAAc,CAAA;AACvB,CAAC","sourcesContent":["import type { Account } from '@atproto/oauth-provider-api'\nimport { Awaitable, buildInterfaceChecker } from '../lib/util/type.js'\nimport { Sub } from '../oidc/sub.js'\nimport { Code } from '../request/code.js'\nimport { RefreshToken } from './refresh-token.js'\nimport { TokenData } from './token-data.js'\nimport { TokenId } from './token-id.js'\n\n// Export all types needed to implement the TokenStore interface\nexport * from './refresh-token.js'\nexport * from './token-data.js'\nexport * from './token-id.js'\nexport type { Account, Awaitable, Sub }\n\nexport type TokenInfo = {\n id: TokenId\n data: TokenData\n account: Account\n currentRefreshToken: null | RefreshToken\n}\n\nexport type NewTokenData = {\n clientAuth: TokenData['clientAuth']\n expiresAt: TokenData['expiresAt']\n updatedAt: TokenData['updatedAt']\n scope: NonNullable<TokenData['scope']>\n}\n\nexport type CreateTokenData = TokenData & {\n scope: NonNullable<TokenData['scope']>\n}\n\n/**\n * @param data historically, {@link TokenData.scope} was not present in\n * {@link TokenData}, causing it to be \"nullable\" when returned from\n * {@link TokenStore.readToken}. We use {@link CreateTokenData} here to allow\n * the store implementation to expect its presence.\n */\nexport interface TokenStore {\n createToken(\n tokenId: TokenId,\n data: CreateTokenData,\n refreshToken?: RefreshToken,\n ): Awaitable<void>\n\n readToken(tokenId: TokenId): Awaitable<null | TokenInfo>\n\n deleteToken(tokenId: TokenId): Awaitable<void>\n\n rotateToken(\n tokenId: TokenId,\n newTokenId: TokenId,\n newRefreshToken: RefreshToken,\n newData: NewTokenData,\n ): Awaitable<void>\n\n /**\n * Find a token by its refresh token. Note that previous refresh tokens\n * should also return the token. The data model is responsible for storing\n * old refresh tokens when a new one is issued.\n */\n findTokenByRefreshToken(\n refreshToken: RefreshToken,\n ): Awaitable<null | TokenInfo>\n\n findTokenByCode(code: Code): Awaitable<null | TokenInfo>\n\n listAccountTokens(sub: Sub): Awaitable<TokenInfo[]>\n}\n\nexport const isTokenStore = buildInterfaceChecker<TokenStore>([\n 'createToken',\n 'readToken',\n 'deleteToken',\n 'rotateToken',\n 'findTokenByRefreshToken',\n 'findTokenByCode',\n 'listAccountTokens',\n])\n\nexport function asTokenStore<V extends Partial<TokenStore>>(\n implementation?: V,\n): V & TokenStore {\n if (!implementation || !isTokenStore(implementation)) {\n throw new Error('Invalid TokenStore implementation')\n }\n return implementation\n}\n"]}
@@ -1,21 +1,17 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.authorizationResponseErrorSchema = void 0;
4
- exports.isAuthorizationResponseError = isAuthorizationResponseError;
5
- const zod_1 = require("zod");
6
- const oauth_types_1 = require("@atproto/oauth-types");
7
- exports.authorizationResponseErrorSchema = zod_1.z.union([
8
- oauth_types_1.oauthAuthorizationResponseErrorSchema,
1
+ import { z } from 'zod';
2
+ import { oauthAuthorizationResponseErrorSchema, oidcAuthorizationResponseErrorSchema, } from '@atproto/oauth-types';
3
+ export const authorizationResponseErrorSchema = z.union([
4
+ oauthAuthorizationResponseErrorSchema,
9
5
  // OIDC authentication error response are not part of the ATproto flavoured
10
6
  // OAuth but we allow them because they provide better feedback to the client
11
7
  // (in particular when SSO is used).
12
- oauth_types_1.oidcAuthorizationResponseErrorSchema,
8
+ oidcAuthorizationResponseErrorSchema,
13
9
  // This error is defined by rfc9396 (not part of the OAuth 2.1 or OIDC). But
14
10
  // since, in ATproto flavoured OAuth, client registration is a dynamic part of
15
11
  // the authorization process, we allow it.
16
- zod_1.z.literal('invalid_authorization_details'),
12
+ z.literal('invalid_authorization_details'),
17
13
  ]);
18
- function isAuthorizationResponseError(value) {
19
- return exports.authorizationResponseErrorSchema.safeParse(value).success;
14
+ export function isAuthorizationResponseError(value) {
15
+ return authorizationResponseErrorSchema.safeParse(value).success;
20
16
  }
21
17
  //# sourceMappingURL=authorization-response-error.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"authorization-response-error.js","sourceRoot":"","sources":["../../src/types/authorization-response-error.ts"],"names":[],"mappings":";;;AAsBA,oEAIC;AA1BD,6BAAuB;AACvB,sDAG6B;AAEhB,QAAA,gCAAgC,GAAG,OAAC,CAAC,KAAK,CAAC;IACtD,mDAAqC;IACrC,2EAA2E;IAC3E,6EAA6E;IAC7E,oCAAoC;IACpC,kDAAoC;IACpC,4EAA4E;IAC5E,8EAA8E;IAC9E,0CAA0C;IAC1C,OAAC,CAAC,OAAO,CAAC,+BAA+B,CAAC;CAC3C,CAAC,CAAA;AAMF,SAAgB,4BAA4B,CAC1C,KAAQ;IAER,OAAO,wCAAgC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CAAA;AAClE,CAAC","sourcesContent":["import { z } from 'zod'\nimport {\n oauthAuthorizationResponseErrorSchema,\n oidcAuthorizationResponseErrorSchema,\n} from '@atproto/oauth-types'\n\nexport const authorizationResponseErrorSchema = z.union([\n oauthAuthorizationResponseErrorSchema,\n // OIDC authentication error response are not part of the ATproto flavoured\n // OAuth but we allow them because they provide better feedback to the client\n // (in particular when SSO is used).\n oidcAuthorizationResponseErrorSchema,\n // This error is defined by rfc9396 (not part of the OAuth 2.1 or OIDC). But\n // since, in ATproto flavoured OAuth, client registration is a dynamic part of\n // the authorization process, we allow it.\n z.literal('invalid_authorization_details'),\n])\n\nexport type AuthorizationResponseError = z.infer<\n typeof authorizationResponseErrorSchema\n>\n\nexport function isAuthorizationResponseError<T>(\n value: T,\n): value is T & AuthorizationResponseError {\n return authorizationResponseErrorSchema.safeParse(value).success\n}\n"]}
1
+ {"version":3,"file":"authorization-response-error.js","sourceRoot":"","sources":["../../src/types/authorization-response-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EACL,qCAAqC,EACrC,oCAAoC,GACrC,MAAM,sBAAsB,CAAA;AAE7B,MAAM,CAAC,MAAM,gCAAgC,GAAG,CAAC,CAAC,KAAK,CAAC;IACtD,qCAAqC;IACrC,2EAA2E;IAC3E,6EAA6E;IAC7E,oCAAoC;IACpC,oCAAoC;IACpC,4EAA4E;IAC5E,8EAA8E;IAC9E,0CAA0C;IAC1C,CAAC,CAAC,OAAO,CAAC,+BAA+B,CAAC;CAC3C,CAAC,CAAA;AAMF,MAAM,UAAU,4BAA4B,CAC1C,KAAQ;IAER,OAAO,gCAAgC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CAAA;AAClE,CAAC","sourcesContent":["import { z } from 'zod'\nimport {\n oauthAuthorizationResponseErrorSchema,\n oidcAuthorizationResponseErrorSchema,\n} from '@atproto/oauth-types'\n\nexport const authorizationResponseErrorSchema = z.union([\n oauthAuthorizationResponseErrorSchema,\n // OIDC authentication error response are not part of the ATproto flavoured\n // OAuth but we allow them because they provide better feedback to the client\n // (in particular when SSO is used).\n oidcAuthorizationResponseErrorSchema,\n // This error is defined by rfc9396 (not part of the OAuth 2.1 or OIDC). But\n // since, in ATproto flavoured OAuth, client registration is a dynamic part of\n // the authorization process, we allow it.\n z.literal('invalid_authorization_details'),\n])\n\nexport type AuthorizationResponseError = z.infer<\n typeof authorizationResponseErrorSchema\n>\n\nexport function isAuthorizationResponseError<T>(\n value: T,\n): value is T & AuthorizationResponseError {\n return authorizationResponseErrorSchema.safeParse(value).success\n}\n"]}
@@ -1,6 +1,3 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.colorHueSchema = void 0;
4
- const zod_1 = require("zod");
5
- exports.colorHueSchema = zod_1.z.number().min(0).max(360);
1
+ import { z } from 'zod';
2
+ export const colorHueSchema = z.number().min(0).max(360);
6
3
  //# sourceMappingURL=color-hue.js.map