@depup/better-auth__core 1.6.23-depup.2

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 (310) hide show
  1. package/LICENSE.md +20 -0
  2. package/README.md +32 -0
  3. package/changes.json +14 -0
  4. package/dist/api/index.d.mts +281 -0
  5. package/dist/api/index.mjs +92 -0
  6. package/dist/async_hooks/index.d.mts +6 -0
  7. package/dist/async_hooks/index.mjs +20 -0
  8. package/dist/async_hooks/pure.index.d.mts +6 -0
  9. package/dist/async_hooks/pure.index.mjs +33 -0
  10. package/dist/context/endpoint-context.d.mts +18 -0
  11. package/dist/context/endpoint-context.mjs +29 -0
  12. package/dist/context/global.d.mts +6 -0
  13. package/dist/context/global.mjs +36 -0
  14. package/dist/context/index.d.mts +5 -0
  15. package/dist/context/index.mjs +5 -0
  16. package/dist/context/request-state.d.mts +27 -0
  17. package/dist/context/request-state.mjs +47 -0
  18. package/dist/context/transaction.d.mts +27 -0
  19. package/dist/context/transaction.mjs +96 -0
  20. package/dist/db/adapter/factory.d.mts +17 -0
  21. package/dist/db/adapter/factory.mjs +905 -0
  22. package/dist/db/adapter/get-default-field-name.d.mts +18 -0
  23. package/dist/db/adapter/get-default-field-name.mjs +36 -0
  24. package/dist/db/adapter/get-default-model-name.d.mts +12 -0
  25. package/dist/db/adapter/get-default-model-name.mjs +30 -0
  26. package/dist/db/adapter/get-field-attributes.d.mts +26 -0
  27. package/dist/db/adapter/get-field-attributes.mjs +37 -0
  28. package/dist/db/adapter/get-field-name.d.mts +18 -0
  29. package/dist/db/adapter/get-field-name.mjs +31 -0
  30. package/dist/db/adapter/get-id-field.d.mts +36 -0
  31. package/dist/db/adapter/get-id-field.mjs +64 -0
  32. package/dist/db/adapter/get-model-name.d.mts +12 -0
  33. package/dist/db/adapter/get-model-name.mjs +21 -0
  34. package/dist/db/adapter/index.d.mts +615 -0
  35. package/dist/db/adapter/index.mjs +24 -0
  36. package/dist/db/adapter/types.d.mts +105 -0
  37. package/dist/db/adapter/utils.d.mts +7 -0
  38. package/dist/db/adapter/utils.mjs +37 -0
  39. package/dist/db/get-tables.d.mts +6 -0
  40. package/dist/db/get-tables.mjs +266 -0
  41. package/dist/db/index.d.mts +10 -0
  42. package/dist/db/index.mjs +8 -0
  43. package/dist/db/plugin.d.mts +12 -0
  44. package/dist/db/schema/account.d.mts +28 -0
  45. package/dist/db/schema/account.mjs +17 -0
  46. package/dist/db/schema/rate-limit.d.mts +18 -0
  47. package/dist/db/schema/rate-limit.mjs +9 -0
  48. package/dist/db/schema/session.d.mts +23 -0
  49. package/dist/db/schema/session.mjs +12 -0
  50. package/dist/db/schema/shared.d.mts +10 -0
  51. package/dist/db/schema/shared.mjs +9 -0
  52. package/dist/db/schema/user.d.mts +22 -0
  53. package/dist/db/schema/user.mjs +11 -0
  54. package/dist/db/schema/verification.d.mts +21 -0
  55. package/dist/db/schema/verification.mjs +10 -0
  56. package/dist/db/type.d.mts +194 -0
  57. package/dist/env/color-depth.d.mts +4 -0
  58. package/dist/env/color-depth.mjs +86 -0
  59. package/dist/env/env-impl.d.mts +32 -0
  60. package/dist/env/env-impl.mjs +81 -0
  61. package/dist/env/index.d.mts +4 -0
  62. package/dist/env/index.mjs +4 -0
  63. package/dist/env/logger.d.mts +48 -0
  64. package/dist/env/logger.mjs +79 -0
  65. package/dist/error/codes.d.mts +69 -0
  66. package/dist/error/codes.mjs +55 -0
  67. package/dist/error/index.d.mts +26 -0
  68. package/dist/error/index.mjs +27 -0
  69. package/dist/index.d.mts +9 -0
  70. package/dist/index.mjs +1 -0
  71. package/dist/instrumentation/api.mjs +12 -0
  72. package/dist/instrumentation/attributes.d.mts +11 -0
  73. package/dist/instrumentation/attributes.mjs +10 -0
  74. package/dist/instrumentation/index.d.mts +3 -0
  75. package/dist/instrumentation/index.mjs +3 -0
  76. package/dist/instrumentation/noop.mjs +42 -0
  77. package/dist/instrumentation/pure.index.d.mts +7 -0
  78. package/dist/instrumentation/pure.index.mjs +7 -0
  79. package/dist/instrumentation/tracer.d.mts +13 -0
  80. package/dist/instrumentation/tracer.mjs +53 -0
  81. package/dist/oauth2/client-credentials-token.d.mts +56 -0
  82. package/dist/oauth2/client-credentials-token.mjs +64 -0
  83. package/dist/oauth2/create-authorization-url.d.mts +44 -0
  84. package/dist/oauth2/create-authorization-url.mjs +41 -0
  85. package/dist/oauth2/index.d.mts +8 -0
  86. package/dist/oauth2/index.mjs +7 -0
  87. package/dist/oauth2/oauth-provider.d.mts +192 -0
  88. package/dist/oauth2/refresh-access-token.d.mts +54 -0
  89. package/dist/oauth2/refresh-access-token.mjs +73 -0
  90. package/dist/oauth2/reject-redirects.mjs +60 -0
  91. package/dist/oauth2/utils.d.mts +24 -0
  92. package/dist/oauth2/utils.mjs +48 -0
  93. package/dist/oauth2/validate-authorization-code.d.mts +85 -0
  94. package/dist/oauth2/validate-authorization-code.mjs +86 -0
  95. package/dist/oauth2/verify.d.mts +65 -0
  96. package/dist/oauth2/verify.mjs +202 -0
  97. package/dist/social-providers/apple.d.mts +133 -0
  98. package/dist/social-providers/apple.mjs +117 -0
  99. package/dist/social-providers/atlassian.d.mts +70 -0
  100. package/dist/social-providers/atlassian.mjs +80 -0
  101. package/dist/social-providers/cognito.d.mts +85 -0
  102. package/dist/social-providers/cognito.mjs +162 -0
  103. package/dist/social-providers/discord.d.mts +124 -0
  104. package/dist/social-providers/discord.mjs +62 -0
  105. package/dist/social-providers/dropbox.d.mts +69 -0
  106. package/dist/social-providers/dropbox.mjs +72 -0
  107. package/dist/social-providers/facebook.d.mts +79 -0
  108. package/dist/social-providers/facebook.mjs +157 -0
  109. package/dist/social-providers/figma.d.mts +61 -0
  110. package/dist/social-providers/figma.mjs +83 -0
  111. package/dist/social-providers/github.d.mts +102 -0
  112. package/dist/social-providers/github.mjs +92 -0
  113. package/dist/social-providers/gitlab.d.mts +123 -0
  114. package/dist/social-providers/gitlab.mjs +79 -0
  115. package/dist/social-providers/google.d.mts +123 -0
  116. package/dist/social-providers/google.mjs +137 -0
  117. package/dist/social-providers/huggingface.d.mts +83 -0
  118. package/dist/social-providers/huggingface.mjs +73 -0
  119. package/dist/social-providers/index.d.mts +1834 -0
  120. package/dist/social-providers/index.mjs +78 -0
  121. package/dist/social-providers/kakao.d.mts +161 -0
  122. package/dist/social-providers/kakao.mjs +70 -0
  123. package/dist/social-providers/kick.d.mts +73 -0
  124. package/dist/social-providers/kick.mjs +68 -0
  125. package/dist/social-providers/line.d.mts +105 -0
  126. package/dist/social-providers/line.mjs +110 -0
  127. package/dist/social-providers/linear.d.mts +68 -0
  128. package/dist/social-providers/linear.mjs +85 -0
  129. package/dist/social-providers/linkedin.d.mts +67 -0
  130. package/dist/social-providers/linkedin.mjs +73 -0
  131. package/dist/social-providers/microsoft-entra-id.d.mts +174 -0
  132. package/dist/social-providers/microsoft-entra-id.mjs +152 -0
  133. package/dist/social-providers/naver.d.mts +92 -0
  134. package/dist/social-providers/naver.mjs +65 -0
  135. package/dist/social-providers/notion.d.mts +64 -0
  136. package/dist/social-providers/notion.mjs +72 -0
  137. package/dist/social-providers/paybin.d.mts +71 -0
  138. package/dist/social-providers/paybin.mjs +81 -0
  139. package/dist/social-providers/paypal.d.mts +131 -0
  140. package/dist/social-providers/paypal.mjs +188 -0
  141. package/dist/social-providers/polar.d.mts +74 -0
  142. package/dist/social-providers/polar.mjs +71 -0
  143. package/dist/social-providers/railway.d.mts +65 -0
  144. package/dist/social-providers/railway.mjs +74 -0
  145. package/dist/social-providers/reddit.d.mts +62 -0
  146. package/dist/social-providers/reddit.mjs +81 -0
  147. package/dist/social-providers/roblox.d.mts +70 -0
  148. package/dist/social-providers/roblox.mjs +57 -0
  149. package/dist/social-providers/salesforce.d.mts +79 -0
  150. package/dist/social-providers/salesforce.mjs +87 -0
  151. package/dist/social-providers/slack.d.mts +83 -0
  152. package/dist/social-providers/slack.mjs +66 -0
  153. package/dist/social-providers/spotify.d.mts +63 -0
  154. package/dist/social-providers/spotify.mjs +69 -0
  155. package/dist/social-providers/tiktok.d.mts +168 -0
  156. package/dist/social-providers/tiktok.mjs +60 -0
  157. package/dist/social-providers/twitch.d.mts +79 -0
  158. package/dist/social-providers/twitch.mjs +75 -0
  159. package/dist/social-providers/twitter.d.mts +126 -0
  160. package/dist/social-providers/twitter.mjs +85 -0
  161. package/dist/social-providers/vercel.d.mts +62 -0
  162. package/dist/social-providers/vercel.mjs +58 -0
  163. package/dist/social-providers/vk.d.mts +70 -0
  164. package/dist/social-providers/vk.mjs +81 -0
  165. package/dist/social-providers/wechat.d.mts +113 -0
  166. package/dist/social-providers/wechat.mjs +81 -0
  167. package/dist/social-providers/zoom.d.mts +163 -0
  168. package/dist/social-providers/zoom.mjs +69 -0
  169. package/dist/types/context.d.mts +319 -0
  170. package/dist/types/cookie.d.mts +15 -0
  171. package/dist/types/helper.d.mts +10 -0
  172. package/dist/types/index.d.mts +9 -0
  173. package/dist/types/init-options.d.mts +1430 -0
  174. package/dist/types/plugin-client.d.mts +123 -0
  175. package/dist/types/plugin.d.mts +124 -0
  176. package/dist/types/secret.d.mts +11 -0
  177. package/dist/utils/async.d.mts +22 -0
  178. package/dist/utils/async.mjs +32 -0
  179. package/dist/utils/db.d.mts +9 -0
  180. package/dist/utils/db.mjs +15 -0
  181. package/dist/utils/deprecate.d.mts +9 -0
  182. package/dist/utils/deprecate.mjs +16 -0
  183. package/dist/utils/error-codes.d.mts +13 -0
  184. package/dist/utils/error-codes.mjs +10 -0
  185. package/dist/utils/fetch-metadata.d.mts +4 -0
  186. package/dist/utils/fetch-metadata.mjs +6 -0
  187. package/dist/utils/host.d.mts +147 -0
  188. package/dist/utils/host.mjs +295 -0
  189. package/dist/utils/id.d.mts +4 -0
  190. package/dist/utils/id.mjs +7 -0
  191. package/dist/utils/ip.d.mts +77 -0
  192. package/dist/utils/ip.mjs +230 -0
  193. package/dist/utils/is-api-error.d.mts +6 -0
  194. package/dist/utils/is-api-error.mjs +8 -0
  195. package/dist/utils/json.d.mts +4 -0
  196. package/dist/utils/json.mjs +41 -0
  197. package/dist/utils/redirect-uri.d.mts +20 -0
  198. package/dist/utils/redirect-uri.mjs +48 -0
  199. package/dist/utils/string.d.mts +8 -0
  200. package/dist/utils/string.mjs +25 -0
  201. package/dist/utils/url.d.mts +37 -0
  202. package/dist/utils/url.mjs +61 -0
  203. package/package.json +216 -0
  204. package/src/api/index.ts +185 -0
  205. package/src/async_hooks/index.ts +40 -0
  206. package/src/async_hooks/pure.index.ts +46 -0
  207. package/src/context/endpoint-context.ts +50 -0
  208. package/src/context/global.ts +57 -0
  209. package/src/context/index.ts +23 -0
  210. package/src/context/request-state.ts +91 -0
  211. package/src/context/transaction.ts +169 -0
  212. package/src/db/adapter/factory.ts +1740 -0
  213. package/src/db/adapter/get-default-field-name.ts +59 -0
  214. package/src/db/adapter/get-default-model-name.ts +51 -0
  215. package/src/db/adapter/get-field-attributes.ts +62 -0
  216. package/src/db/adapter/get-field-name.ts +43 -0
  217. package/src/db/adapter/get-id-field.ts +150 -0
  218. package/src/db/adapter/get-model-name.ts +36 -0
  219. package/src/db/adapter/index.ts +656 -0
  220. package/src/db/adapter/types.ts +134 -0
  221. package/src/db/adapter/utils.ts +61 -0
  222. package/src/db/get-tables.ts +304 -0
  223. package/src/db/index.ts +43 -0
  224. package/src/db/plugin.ts +11 -0
  225. package/src/db/schema/account.ts +47 -0
  226. package/src/db/schema/rate-limit.ts +36 -0
  227. package/src/db/schema/session.ts +29 -0
  228. package/src/db/schema/shared.ts +7 -0
  229. package/src/db/schema/user.ts +31 -0
  230. package/src/db/schema/verification.ts +28 -0
  231. package/src/db/type.ts +360 -0
  232. package/src/env/color-depth.ts +172 -0
  233. package/src/env/env-impl.ts +123 -0
  234. package/src/env/index.ts +23 -0
  235. package/src/env/logger.ts +145 -0
  236. package/src/error/codes.ts +72 -0
  237. package/src/error/index.ts +44 -0
  238. package/src/index.ts +1 -0
  239. package/src/instrumentation/api.ts +17 -0
  240. package/src/instrumentation/attributes.ts +22 -0
  241. package/src/instrumentation/index.ts +2 -0
  242. package/src/instrumentation/noop.ts +74 -0
  243. package/src/instrumentation/pure.index.ts +31 -0
  244. package/src/instrumentation/tracer.ts +95 -0
  245. package/src/oauth2/client-credentials-token.ts +126 -0
  246. package/src/oauth2/create-authorization-url.ts +89 -0
  247. package/src/oauth2/index.ts +34 -0
  248. package/src/oauth2/oauth-provider.ts +222 -0
  249. package/src/oauth2/refresh-access-token.ts +157 -0
  250. package/src/oauth2/reject-redirects.ts +70 -0
  251. package/src/oauth2/utils.ts +70 -0
  252. package/src/oauth2/validate-authorization-code.ts +190 -0
  253. package/src/oauth2/verify.ts +408 -0
  254. package/src/social-providers/apple.ts +249 -0
  255. package/src/social-providers/atlassian.ts +133 -0
  256. package/src/social-providers/cognito.ts +281 -0
  257. package/src/social-providers/discord.ts +170 -0
  258. package/src/social-providers/dropbox.ts +112 -0
  259. package/src/social-providers/facebook.ts +288 -0
  260. package/src/social-providers/figma.ts +118 -0
  261. package/src/social-providers/github.ts +184 -0
  262. package/src/social-providers/gitlab.ts +155 -0
  263. package/src/social-providers/google.ts +263 -0
  264. package/src/social-providers/huggingface.ts +119 -0
  265. package/src/social-providers/index.ts +132 -0
  266. package/src/social-providers/kakao.ts +179 -0
  267. package/src/social-providers/kick.ts +109 -0
  268. package/src/social-providers/line.ts +169 -0
  269. package/src/social-providers/linear.ts +121 -0
  270. package/src/social-providers/linkedin.ts +110 -0
  271. package/src/social-providers/microsoft-entra-id.ts +391 -0
  272. package/src/social-providers/naver.ts +113 -0
  273. package/src/social-providers/notion.ts +108 -0
  274. package/src/social-providers/paybin.ts +118 -0
  275. package/src/social-providers/paypal.ts +371 -0
  276. package/src/social-providers/polar.ts +111 -0
  277. package/src/social-providers/railway.ts +100 -0
  278. package/src/social-providers/reddit.ts +126 -0
  279. package/src/social-providers/roblox.ts +112 -0
  280. package/src/social-providers/salesforce.ts +159 -0
  281. package/src/social-providers/slack.ts +112 -0
  282. package/src/social-providers/spotify.ts +94 -0
  283. package/src/social-providers/tiktok.ts +211 -0
  284. package/src/social-providers/twitch.ts +112 -0
  285. package/src/social-providers/twitter.ts +199 -0
  286. package/src/social-providers/vercel.ts +87 -0
  287. package/src/social-providers/vk.ts +125 -0
  288. package/src/social-providers/wechat.ts +220 -0
  289. package/src/social-providers/zoom.ts +230 -0
  290. package/src/types/context.ts +460 -0
  291. package/src/types/cookie.ts +10 -0
  292. package/src/types/helper.ts +27 -0
  293. package/src/types/index.ts +40 -0
  294. package/src/types/init-options.ts +1679 -0
  295. package/src/types/plugin-client.ts +143 -0
  296. package/src/types/plugin.ts +163 -0
  297. package/src/types/secret.ts +8 -0
  298. package/src/utils/async.ts +53 -0
  299. package/src/utils/db.ts +20 -0
  300. package/src/utils/deprecate.ts +21 -0
  301. package/src/utils/error-codes.ts +68 -0
  302. package/src/utils/fetch-metadata.ts +3 -0
  303. package/src/utils/host.ts +416 -0
  304. package/src/utils/id.ts +5 -0
  305. package/src/utils/ip.ts +395 -0
  306. package/src/utils/is-api-error.ts +10 -0
  307. package/src/utils/json.ts +56 -0
  308. package/src/utils/redirect-uri.ts +54 -0
  309. package/src/utils/string.ts +40 -0
  310. package/src/utils/url.ts +77 -0
@@ -0,0 +1,202 @@
1
+ import { logger } from "../env/logger.mjs";
2
+ import { fetchRefusingRedirects } from "./reject-redirects.mjs";
3
+ import { APIError } from "better-call";
4
+ import { UnsecuredJWT, createLocalJWKSet, decodeProtectedHeader, errors, jwtVerify } from "jose";
5
+ //#region src/oauth2/verify.ts
6
+ const joseInfrastructureErrorCodes = new Set([
7
+ errors.JWKSTimeout.code,
8
+ errors.JWKSInvalid.code,
9
+ errors.JWKSMultipleMatchingKeys.code
10
+ ]);
11
+ function isJoseInfrastructureError(error) {
12
+ return joseInfrastructureErrorCodes.has(error.code);
13
+ }
14
+ /**
15
+ * @internal
16
+ */
17
+ const jwksCache = /* @__PURE__ */ new Map();
18
+ /**
19
+ * Cache for function jwks sources, keyed by a caller-provided stable object.
20
+ * Entries are released with their key, so per-request keys cannot accumulate.
21
+ */
22
+ const functionJwksCache = /* @__PURE__ */ new WeakMap();
23
+ /**
24
+ * How long a cached JWKS is trusted before it is refetched
25
+ *
26
+ * @internal
27
+ */
28
+ const JWKS_CACHE_TTL_MS = 300 * 1e3;
29
+ const JWKS_NO_KID_REFETCH_COOLDOWN_MS = 30 * 1e3;
30
+ /**
31
+ * Returns the cached key set when it is within the TTL. When the token carries
32
+ * `kid`, the cached set must contain that key id; without `kid`, key selection
33
+ * is deferred to JOSE because RFC 7515 makes the header parameter optional.
34
+ */
35
+ function getFreshJwksWithKid(cached, kid) {
36
+ if (!cached) return void 0;
37
+ if (Date.now() - cached.fetchedAt >= JWKS_CACHE_TTL_MS) return void 0;
38
+ if (kid && !cached.jwks.keys.some((jwk) => jwk.kid === kid)) return;
39
+ return cached.jwks;
40
+ }
41
+ function shouldRefetchCachedJwksWithoutKid(error, resolved) {
42
+ if (!(resolved.fromCache && !resolved.kid && (error instanceof errors.JWKSNoMatchingKey || error instanceof errors.JWSSignatureVerificationFailed))) return false;
43
+ if (!resolved.noKidRefetchedAt) return true;
44
+ return Date.now() - resolved.noKidRefetchedAt >= JWKS_NO_KID_REFETCH_COOLDOWN_MS;
45
+ }
46
+ async function fetchJwks(jwksFetch) {
47
+ const jwks = typeof jwksFetch === "string" ? await fetchRefusingRedirects(jwksFetch, { headers: { Accept: "application/json" } }).then(async (res) => {
48
+ if (res.error) throw new Error(`Jwks failed: ${res.error.message ?? res.error.statusText}`);
49
+ return res.data;
50
+ }) : await jwksFetch();
51
+ if (!jwks) throw new Error("No jwks found");
52
+ return jwks;
53
+ }
54
+ /**
55
+ * Performs local verification of an access token for your APIs.
56
+ *
57
+ * Can also be configured for remote verification.
58
+ */
59
+ async function verifyJwsAccessToken(token, opts) {
60
+ try {
61
+ const resolved = await getJwksForVerification(token, opts);
62
+ let jwt;
63
+ try {
64
+ jwt = await jwtVerify(token, createLocalJWKSet(resolved.jwks), opts.verifyOptions);
65
+ } catch (error) {
66
+ if (shouldRefetchCachedJwksWithoutKid(error, resolved)) jwt = await jwtVerify(token, createLocalJWKSet((await getJwksForVerification(token, {
67
+ ...opts,
68
+ forceRefresh: true
69
+ })).jwks), opts.verifyOptions);
70
+ else throw error;
71
+ }
72
+ if (jwt.payload.azp) jwt.payload.client_id = jwt.payload.azp;
73
+ return jwt.payload;
74
+ } catch (error) {
75
+ if (error instanceof Error) throw error;
76
+ throw new Error(error);
77
+ }
78
+ }
79
+ async function getJwks(token, opts) {
80
+ return (await getJwksForVerification(token, opts)).jwks;
81
+ }
82
+ async function getJwksForVerification(token, opts) {
83
+ let jwtHeaders;
84
+ try {
85
+ jwtHeaders = decodeProtectedHeader(token);
86
+ } catch (error) {
87
+ if (error instanceof Error) throw error;
88
+ throw new Error(error);
89
+ }
90
+ const kid = jwtHeaders.kid;
91
+ if (typeof opts.jwksFetch !== "string") {
92
+ const cacheKey = opts.jwksCacheKey;
93
+ if (!cacheKey) {
94
+ const jwks = await opts.jwksFetch();
95
+ if (!jwks) throw new Error("No jwks found");
96
+ return {
97
+ jwks,
98
+ fromCache: false,
99
+ kid
100
+ };
101
+ }
102
+ const cached = functionJwksCache.get(cacheKey);
103
+ const cachedJwks = opts.forceRefresh ? void 0 : getFreshJwksWithKid(cached, kid);
104
+ if (cachedJwks) return {
105
+ jwks: cachedJwks,
106
+ fromCache: true,
107
+ kid,
108
+ noKidRefetchedAt: cached?.noKidRefetchedAt
109
+ };
110
+ const jwks = await opts.jwksFetch();
111
+ if (!jwks) throw new Error("No jwks found");
112
+ const fetchedAt = Date.now();
113
+ functionJwksCache.set(cacheKey, {
114
+ jwks,
115
+ fetchedAt,
116
+ ...opts.forceRefresh && !kid ? { noKidRefetchedAt: fetchedAt } : {}
117
+ });
118
+ return {
119
+ jwks,
120
+ fromCache: false,
121
+ kid
122
+ };
123
+ }
124
+ const cacheKey = opts.jwksFetch;
125
+ const cached = jwksCache.get(cacheKey);
126
+ const cachedJwks = opts.forceRefresh ? void 0 : getFreshJwksWithKid(cached, kid);
127
+ if (!cachedJwks) {
128
+ const jwks = await fetchJwks(opts.jwksFetch);
129
+ const fetchedAt = Date.now();
130
+ jwksCache.set(cacheKey, {
131
+ jwks,
132
+ fetchedAt,
133
+ ...opts.forceRefresh && !kid ? { noKidRefetchedAt: fetchedAt } : {}
134
+ });
135
+ return {
136
+ jwks,
137
+ fromCache: false,
138
+ kid
139
+ };
140
+ }
141
+ return {
142
+ jwks: cachedJwks,
143
+ fromCache: true,
144
+ kid,
145
+ noKidRefetchedAt: cached?.noKidRefetchedAt
146
+ };
147
+ }
148
+ /**
149
+ * Performs local verification of an access token for your API.
150
+ *
151
+ * Can also be configured for remote verification.
152
+ */
153
+ async function verifyAccessToken(token, opts) {
154
+ let payload;
155
+ if (opts.jwksUrl && !opts?.remoteVerify?.force) try {
156
+ payload = await verifyJwsAccessToken(token, {
157
+ jwksFetch: opts.jwksUrl,
158
+ verifyOptions: opts.verifyOptions
159
+ });
160
+ } catch (error) {
161
+ if (error instanceof Error) if (error.name === "TypeError" || error.name === "JWSInvalid") {} else if (error instanceof errors.JWTExpired) throw new APIError("UNAUTHORIZED", { message: "token expired" });
162
+ else if (error instanceof errors.JOSEError) {
163
+ if (isJoseInfrastructureError(error)) throw error;
164
+ throw new APIError("UNAUTHORIZED", { message: "invalid access token" });
165
+ } else throw error;
166
+ else throw new Error(error);
167
+ }
168
+ if (opts?.remoteVerify) {
169
+ const { data: introspect, error: introspectError } = await fetchRefusingRedirects(opts.remoteVerify.introspectUrl, {
170
+ method: "POST",
171
+ headers: {
172
+ Accept: "application/json",
173
+ "Content-Type": "application/x-www-form-urlencoded"
174
+ },
175
+ body: new URLSearchParams({
176
+ client_id: opts.remoteVerify.clientId,
177
+ client_secret: opts.remoteVerify.clientSecret,
178
+ token,
179
+ token_type_hint: "access_token"
180
+ }).toString()
181
+ });
182
+ if (introspectError) logger.error(`Introspection failed: ${introspectError.message ?? introspectError.statusText}`);
183
+ if (!introspect) throw new APIError("INTERNAL_SERVER_ERROR", { message: "introspection failed" });
184
+ if (!introspect.active) throw new APIError("UNAUTHORIZED", { message: "token inactive" });
185
+ try {
186
+ const unsecuredJwt = new UnsecuredJWT(introspect).encode();
187
+ const { audience: _audience, ...verifyOptionsNoAudience } = opts.verifyOptions;
188
+ const skipAudience = !introspect.aud && opts.remoteVerify.allowMissingAudience === true;
189
+ payload = UnsecuredJWT.decode(unsecuredJwt, skipAudience ? verifyOptionsNoAudience : opts.verifyOptions).payload;
190
+ } catch (error) {
191
+ throw new Error(error);
192
+ }
193
+ }
194
+ if (!payload) throw new APIError("UNAUTHORIZED", { message: `no token payload` });
195
+ if (opts.scopes) {
196
+ const validScopes = new Set(payload.scope?.split(" "));
197
+ for (const sc of opts.scopes) if (!validScopes.has(sc)) throw new APIError("FORBIDDEN", { message: `invalid scope ${sc}` });
198
+ }
199
+ return payload;
200
+ }
201
+ //#endregion
202
+ export { getJwks, verifyAccessToken, verifyJwsAccessToken };
@@ -0,0 +1,133 @@
1
+ import { OAuth2Tokens, ProviderOptions } from "../oauth2/oauth-provider.mjs";
2
+ //#region src/social-providers/apple.d.ts
3
+ interface AppleProfile {
4
+ /**
5
+ * The subject registered claim identifies the principal that’s the subject
6
+ * of the identity token. Because this token is for your app, the value is
7
+ * the unique identifier for the user.
8
+ */
9
+ sub: string;
10
+ /**
11
+ * A String value representing the user's email address.
12
+ * The email address is either the user's real email address or the proxy
13
+ * address, depending on their status private email relay service.
14
+ */
15
+ email?: string;
16
+ /**
17
+ * A string or Boolean value that indicates whether the service verifies
18
+ * the email. The value can either be a string ("true" or "false") or a
19
+ * Boolean (true or false). The system may not verify email addresses for
20
+ * Sign in with Apple at Work & School users, and this claim is "false" or
21
+ * false for those users.
22
+ */
23
+ email_verified: true | "true";
24
+ /**
25
+ * A string or Boolean value that indicates whether the email that the user
26
+ * shares is the proxy address. The value can either be a string ("true" or
27
+ * "false") or a Boolean (true or false).
28
+ */
29
+ is_private_email: boolean;
30
+ /**
31
+ * An Integer value that indicates whether the user appears to be a real
32
+ * person. Use the value of this claim to mitigate fraud. The possible
33
+ * values are: 0 (or Unsupported), 1 (or Unknown), 2 (or LikelyReal). For
34
+ * more information, see ASUserDetectionStatus. This claim is present only
35
+ * in iOS 14 and later, macOS 11 and later, watchOS 7 and later, tvOS 14
36
+ * and later. The claim isn’t present or supported for web-based apps.
37
+ */
38
+ real_user_status: number;
39
+ /**
40
+ * The user’s full name in the format provided during the authorization
41
+ * process.
42
+ */
43
+ name: string;
44
+ /**
45
+ * The URL to the user's profile picture.
46
+ */
47
+ picture: string;
48
+ user?: AppleNonConformUser | undefined;
49
+ }
50
+ /**
51
+ * This is the shape of the `user` query parameter that Apple sends the first
52
+ * time the user consents to the app.
53
+ * @see https://developer.apple.com/documentation/signinwithapplerestapi/request-an-authorization-to-the-sign-in-with-apple-server./
54
+ */
55
+ interface AppleNonConformUser {
56
+ name: {
57
+ firstName: string;
58
+ lastName: string;
59
+ };
60
+ email: string;
61
+ }
62
+ interface AppleOptions extends ProviderOptions<AppleProfile> {
63
+ clientId: string | string[];
64
+ appBundleIdentifier?: string | undefined;
65
+ audience?: (string | string[]) | undefined;
66
+ }
67
+ declare const apple: (options: AppleOptions) => {
68
+ id: "apple";
69
+ name: string;
70
+ createAuthorizationURL({
71
+ state,
72
+ scopes,
73
+ redirectURI
74
+ }: {
75
+ state: string;
76
+ codeVerifier: string;
77
+ scopes?: string[] | undefined;
78
+ redirectURI: string;
79
+ display?: string | undefined;
80
+ loginHint?: string | undefined;
81
+ }): Promise<URL>;
82
+ validateAuthorizationCode: ({
83
+ code,
84
+ codeVerifier,
85
+ redirectURI
86
+ }: {
87
+ code: string;
88
+ redirectURI: string;
89
+ codeVerifier?: string | undefined;
90
+ deviceId?: string | undefined;
91
+ }) => Promise<OAuth2Tokens>;
92
+ verifyIdToken(token: string, nonce: string | undefined): Promise<boolean>;
93
+ refreshAccessToken: (refreshToken: string) => Promise<OAuth2Tokens>;
94
+ getUserInfo(token: OAuth2Tokens & {
95
+ user?: {
96
+ name /**
97
+ * An Integer value that indicates whether the user appears to be a real
98
+ * person. Use the value of this claim to mitigate fraud. The possible
99
+ * values are: 0 (or Unsupported), 1 (or Unknown), 2 (or LikelyReal). For
100
+ * more information, see ASUserDetectionStatus. This claim is present only
101
+ * in iOS 14 and later, macOS 11 and later, watchOS 7 and later, tvOS 14
102
+ * and later. The claim isn’t present or supported for web-based apps.
103
+ */?
104
+ /**
105
+ * An Integer value that indicates whether the user appears to be a real
106
+ * person. Use the value of this claim to mitigate fraud. The possible
107
+ * values are: 0 (or Unsupported), 1 (or Unknown), 2 (or LikelyReal). For
108
+ * more information, see ASUserDetectionStatus. This claim is present only
109
+ * in iOS 14 and later, macOS 11 and later, watchOS 7 and later, tvOS 14
110
+ * and later. The claim isn’t present or supported for web-based apps.
111
+ */
112
+ : {
113
+ firstName?: string;
114
+ lastName?: string;
115
+ };
116
+ email?: string;
117
+ } | undefined;
118
+ }): Promise<{
119
+ user: {
120
+ id: string;
121
+ name?: string;
122
+ email?: string | null;
123
+ image?: string;
124
+ emailVerified: boolean;
125
+ [key: string]: any;
126
+ };
127
+ data: any;
128
+ } | null>;
129
+ options: AppleOptions;
130
+ };
131
+ declare const getApplePublicKey: (kid: string) => Promise<Uint8Array<ArrayBufferLike> | CryptoKey>;
132
+ //#endregion
133
+ export { AppleNonConformUser, AppleOptions, AppleProfile, apple, getApplePublicKey };
@@ -0,0 +1,117 @@
1
+ import { APIError, BetterAuthError } from "../error/index.mjs";
2
+ import { logger } from "../env/logger.mjs";
3
+ import { getPrimaryClientId } from "../oauth2/utils.mjs";
4
+ import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
5
+ import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
6
+ import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
7
+ import { betterFetch } from "@better-fetch/fetch";
8
+ import { decodeJwt, decodeProtectedHeader, importJWK, jwtVerify } from "jose";
9
+ //#region src/social-providers/apple.ts
10
+ async function sha256Hex(value) {
11
+ const data = new TextEncoder().encode(value);
12
+ const digest = await crypto.subtle.digest("SHA-256", data);
13
+ return Array.from(new Uint8Array(digest)).map((byte) => byte.toString(16).padStart(2, "0")).join("");
14
+ }
15
+ async function nonceMatches(jwtNonce, nonce) {
16
+ if (typeof jwtNonce !== "string") return false;
17
+ if (jwtNonce === nonce) return true;
18
+ return jwtNonce === await sha256Hex(nonce);
19
+ }
20
+ const apple = (options) => {
21
+ const tokenEndpoint = "https://appleid.apple.com/auth/token";
22
+ return {
23
+ id: "apple",
24
+ name: "Apple",
25
+ async createAuthorizationURL({ state, scopes, redirectURI }) {
26
+ if (!getPrimaryClientId(options.clientId) || !options.clientSecret) {
27
+ logger.error("Client ID and client secret are required for Apple. Make sure to provide them in the options.");
28
+ throw new BetterAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
29
+ }
30
+ const _scope = options.disableDefaultScope ? [] : ["email", "name"];
31
+ if (options.scope) _scope.push(...options.scope);
32
+ if (scopes) _scope.push(...scopes);
33
+ return await createAuthorizationURL({
34
+ id: "apple",
35
+ options,
36
+ authorizationEndpoint: "https://appleid.apple.com/auth/authorize",
37
+ scopes: _scope,
38
+ state,
39
+ redirectURI,
40
+ responseMode: "form_post",
41
+ responseType: "code id_token"
42
+ });
43
+ },
44
+ validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
45
+ return validateAuthorizationCode({
46
+ code,
47
+ codeVerifier,
48
+ redirectURI,
49
+ options,
50
+ tokenEndpoint
51
+ });
52
+ },
53
+ async verifyIdToken(token, nonce) {
54
+ if (options.disableIdTokenSignIn) return false;
55
+ if (options.verifyIdToken) return options.verifyIdToken(token, nonce);
56
+ try {
57
+ const { kid, alg: jwtAlg } = decodeProtectedHeader(token);
58
+ if (!kid || !jwtAlg) return false;
59
+ const { payload: jwtClaims } = await jwtVerify(token, await getApplePublicKey(kid), {
60
+ algorithms: [jwtAlg],
61
+ issuer: "https://appleid.apple.com",
62
+ audience: options.audience && options.audience.length ? options.audience : options.appBundleIdentifier ? options.appBundleIdentifier : options.clientId,
63
+ maxTokenAge: "1h"
64
+ });
65
+ ["email_verified", "is_private_email"].forEach((field) => {
66
+ if (jwtClaims[field] !== void 0) jwtClaims[field] = Boolean(jwtClaims[field]);
67
+ });
68
+ if (nonce && !await nonceMatches(jwtClaims.nonce, nonce)) return false;
69
+ return !!jwtClaims;
70
+ } catch {
71
+ return false;
72
+ }
73
+ },
74
+ refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
75
+ return refreshAccessToken({
76
+ refreshToken,
77
+ options,
78
+ tokenEndpoint
79
+ });
80
+ },
81
+ async getUserInfo(token) {
82
+ if (options.getUserInfo) return options.getUserInfo(token);
83
+ if (!token.idToken) return null;
84
+ const profile = decodeJwt(token.idToken);
85
+ if (!profile) return null;
86
+ let name;
87
+ if (token.user?.name) name = `${token.user.name.firstName || ""} ${token.user.name.lastName || ""}`.trim();
88
+ else name = profile.name || "";
89
+ const emailVerified = typeof profile.email_verified === "boolean" ? profile.email_verified : profile.email_verified === "true";
90
+ const enrichedProfile = {
91
+ ...profile,
92
+ name
93
+ };
94
+ const userMap = await options.mapProfileToUser?.(enrichedProfile);
95
+ return {
96
+ user: {
97
+ id: profile.sub,
98
+ name: enrichedProfile.name,
99
+ emailVerified,
100
+ email: profile.email,
101
+ ...userMap
102
+ },
103
+ data: enrichedProfile
104
+ };
105
+ },
106
+ options
107
+ };
108
+ };
109
+ const getApplePublicKey = async (kid) => {
110
+ const { data } = await betterFetch(`https://appleid.apple.com/auth/keys`);
111
+ if (!data?.keys) throw new APIError("BAD_REQUEST", { message: "Keys not found" });
112
+ const jwk = data.keys.find((key) => key.kid === kid);
113
+ if (!jwk) throw new Error(`JWK with kid ${kid} not found`);
114
+ return await importJWK(jwk, jwk.alg);
115
+ };
116
+ //#endregion
117
+ export { apple, getApplePublicKey };
@@ -0,0 +1,70 @@
1
+ import { OAuth2Tokens, ProviderOptions } from "../oauth2/oauth-provider.mjs";
2
+ //#region src/social-providers/atlassian.d.ts
3
+ interface AtlassianProfile {
4
+ account_type?: string | undefined;
5
+ account_id: string;
6
+ email?: string | undefined;
7
+ name: string;
8
+ picture?: string | undefined;
9
+ nickname?: string | undefined;
10
+ locale?: string | undefined;
11
+ extended_profile?: {
12
+ job_title?: string;
13
+ organization?: string;
14
+ department?: string;
15
+ location?: string;
16
+ } | undefined;
17
+ }
18
+ interface AtlassianOptions extends ProviderOptions<AtlassianProfile> {
19
+ clientId: string;
20
+ }
21
+ declare const atlassian: (options: AtlassianOptions) => {
22
+ id: "atlassian";
23
+ name: string;
24
+ createAuthorizationURL({
25
+ state,
26
+ scopes,
27
+ codeVerifier,
28
+ redirectURI
29
+ }: {
30
+ state: string;
31
+ codeVerifier: string;
32
+ scopes?: string[] | undefined;
33
+ redirectURI: string;
34
+ display?: string | undefined;
35
+ loginHint?: string | undefined;
36
+ }): Promise<URL>;
37
+ validateAuthorizationCode: ({
38
+ code,
39
+ codeVerifier,
40
+ redirectURI
41
+ }: {
42
+ code: string;
43
+ redirectURI: string;
44
+ codeVerifier?: string | undefined;
45
+ deviceId?: string | undefined;
46
+ }) => Promise<OAuth2Tokens>;
47
+ refreshAccessToken: (refreshToken: string) => Promise<OAuth2Tokens>;
48
+ getUserInfo(token: OAuth2Tokens & {
49
+ user?: {
50
+ name?: {
51
+ firstName?: string;
52
+ lastName?: string;
53
+ };
54
+ email?: string;
55
+ } | undefined;
56
+ }): Promise<{
57
+ user: {
58
+ id: string;
59
+ name?: string;
60
+ email?: string | null;
61
+ image?: string;
62
+ emailVerified: boolean;
63
+ [key: string]: any;
64
+ };
65
+ data: any;
66
+ } | null>;
67
+ options: AtlassianOptions;
68
+ };
69
+ //#endregion
70
+ export { AtlassianOptions, AtlassianProfile, atlassian };
@@ -0,0 +1,80 @@
1
+ import { BetterAuthError } from "../error/index.mjs";
2
+ import { logger } from "../env/logger.mjs";
3
+ import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
4
+ import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
5
+ import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
6
+ import { betterFetch } from "@better-fetch/fetch";
7
+ //#region src/social-providers/atlassian.ts
8
+ const atlassian = (options) => {
9
+ const tokenEndpoint = "https://auth.atlassian.com/oauth/token";
10
+ return {
11
+ id: "atlassian",
12
+ name: "Atlassian",
13
+ async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {
14
+ if (!options.clientId || !options.clientSecret) {
15
+ logger.error("Client Id and Secret are required for Atlassian");
16
+ throw new BetterAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
17
+ }
18
+ if (!codeVerifier) throw new BetterAuthError("codeVerifier is required for Atlassian");
19
+ const _scopes = options.disableDefaultScope ? [] : ["read:jira-user", "offline_access"];
20
+ if (options.scope) _scopes.push(...options.scope);
21
+ if (scopes) _scopes.push(...scopes);
22
+ return createAuthorizationURL({
23
+ id: "atlassian",
24
+ options,
25
+ authorizationEndpoint: "https://auth.atlassian.com/authorize",
26
+ scopes: _scopes,
27
+ state,
28
+ codeVerifier,
29
+ redirectURI,
30
+ additionalParams: { audience: "api.atlassian.com" },
31
+ prompt: options.prompt
32
+ });
33
+ },
34
+ validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
35
+ return validateAuthorizationCode({
36
+ code,
37
+ codeVerifier,
38
+ redirectURI,
39
+ options,
40
+ tokenEndpoint
41
+ });
42
+ },
43
+ refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
44
+ return refreshAccessToken({
45
+ refreshToken,
46
+ options: {
47
+ clientId: options.clientId,
48
+ clientSecret: options.clientSecret
49
+ },
50
+ tokenEndpoint
51
+ });
52
+ },
53
+ async getUserInfo(token) {
54
+ if (options.getUserInfo) return options.getUserInfo(token);
55
+ if (!token.accessToken) return null;
56
+ try {
57
+ const { data: profile } = await betterFetch("https://api.atlassian.com/me", { headers: { Authorization: `Bearer ${token.accessToken}` } });
58
+ if (!profile) return null;
59
+ const userMap = await options.mapProfileToUser?.(profile);
60
+ return {
61
+ user: {
62
+ id: profile.account_id,
63
+ name: profile.name,
64
+ email: profile.email,
65
+ image: profile.picture,
66
+ emailVerified: false,
67
+ ...userMap
68
+ },
69
+ data: profile
70
+ };
71
+ } catch (error) {
72
+ logger.error("Failed to fetch user info from Figma:", error);
73
+ return null;
74
+ }
75
+ },
76
+ options
77
+ };
78
+ };
79
+ //#endregion
80
+ export { atlassian };
@@ -0,0 +1,85 @@
1
+ import { OAuth2Tokens, ProviderOptions } from "../oauth2/oauth-provider.mjs";
2
+ //#region src/social-providers/cognito.d.ts
3
+ interface CognitoProfile {
4
+ sub: string;
5
+ email: string;
6
+ email_verified: boolean;
7
+ name: string;
8
+ given_name?: string | undefined;
9
+ family_name?: string | undefined;
10
+ picture?: string | undefined;
11
+ username?: string | undefined;
12
+ locale?: string | undefined;
13
+ phone_number?: string | undefined;
14
+ phone_number_verified?: boolean | undefined;
15
+ aud: string;
16
+ iss: string;
17
+ exp: number;
18
+ iat: number;
19
+ [key: string]: any;
20
+ }
21
+ interface CognitoOptions extends ProviderOptions<CognitoProfile> {
22
+ clientId: string | string[];
23
+ /**
24
+ * The Cognito domain (e.g., "your-app.auth.us-east-1.amazoncognito.com")
25
+ */
26
+ domain: string;
27
+ /**
28
+ * AWS region where User Pool is hosted (e.g., "us-east-1")
29
+ */
30
+ region: string;
31
+ userPoolId: string;
32
+ requireClientSecret?: boolean | undefined;
33
+ }
34
+ declare const cognito: (options: CognitoOptions) => {
35
+ id: "cognito";
36
+ name: string;
37
+ createAuthorizationURL({
38
+ state,
39
+ scopes,
40
+ codeVerifier,
41
+ redirectURI
42
+ }: {
43
+ state: string;
44
+ codeVerifier: string;
45
+ scopes?: string[] | undefined;
46
+ redirectURI: string;
47
+ display?: string | undefined;
48
+ loginHint?: string | undefined;
49
+ }): Promise<URL>;
50
+ validateAuthorizationCode: ({
51
+ code,
52
+ codeVerifier,
53
+ redirectURI
54
+ }: {
55
+ code: string;
56
+ redirectURI: string;
57
+ codeVerifier?: string | undefined;
58
+ deviceId?: string | undefined;
59
+ }) => Promise<OAuth2Tokens>;
60
+ refreshAccessToken: (refreshToken: string) => Promise<OAuth2Tokens>;
61
+ verifyIdToken(token: string, nonce: string | undefined): Promise<boolean>;
62
+ getUserInfo(token: OAuth2Tokens & {
63
+ user?: {
64
+ name?: {
65
+ firstName?: string;
66
+ lastName?: string;
67
+ };
68
+ email?: string;
69
+ } | undefined;
70
+ }): Promise<{
71
+ user: {
72
+ id: string;
73
+ name?: string;
74
+ email?: string | null;
75
+ image?: string;
76
+ emailVerified: boolean;
77
+ [key: string]: any;
78
+ };
79
+ data: any;
80
+ } | null>;
81
+ options: CognitoOptions;
82
+ };
83
+ declare const getCognitoPublicKey: (kid: string, region: string, userPoolId: string) => Promise<Uint8Array<ArrayBufferLike> | CryptoKey>;
84
+ //#endregion
85
+ export { CognitoOptions, CognitoProfile, cognito, getCognitoPublicKey };