@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,54 @@
1
+ import { AwaitableFunction } from "../types/helper.mjs";
2
+ import { OAuth2Tokens, ProviderOptions } from "./oauth-provider.mjs";
3
+
4
+ //#region src/oauth2/refresh-access-token.d.ts
5
+ declare function refreshAccessTokenRequest({
6
+ refreshToken,
7
+ options,
8
+ authentication,
9
+ extraParams,
10
+ resource
11
+ }: {
12
+ refreshToken: string;
13
+ options: AwaitableFunction<Partial<ProviderOptions>>;
14
+ authentication?: ("basic" | "post") | undefined;
15
+ extraParams?: Record<string, string> | undefined;
16
+ resource?: (string | string[]) | undefined;
17
+ }): Promise<{
18
+ body: URLSearchParams;
19
+ headers: Record<string, any>;
20
+ }>;
21
+ /**
22
+ * @deprecated use async'd refreshAccessTokenRequest instead
23
+ */
24
+ declare function createRefreshAccessTokenRequest({
25
+ refreshToken,
26
+ options,
27
+ authentication,
28
+ extraParams,
29
+ resource
30
+ }: {
31
+ refreshToken: string;
32
+ options: ProviderOptions;
33
+ authentication?: ("basic" | "post") | undefined;
34
+ extraParams?: Record<string, string> | undefined;
35
+ resource?: (string | string[]) | undefined;
36
+ }): {
37
+ body: URLSearchParams;
38
+ headers: Record<string, any>;
39
+ };
40
+ declare function refreshAccessToken({
41
+ refreshToken,
42
+ options,
43
+ tokenEndpoint,
44
+ authentication,
45
+ extraParams
46
+ }: {
47
+ refreshToken: string;
48
+ options: Partial<ProviderOptions>;
49
+ tokenEndpoint: string;
50
+ authentication?: ("basic" | "post") | undefined;
51
+ extraParams?: Record<string, string> | undefined;
52
+ }): Promise<OAuth2Tokens>;
53
+ //#endregion
54
+ export { createRefreshAccessTokenRequest, refreshAccessToken, refreshAccessTokenRequest };
@@ -0,0 +1,73 @@
1
+ import { fetchRefusingRedirects } from "./reject-redirects.mjs";
2
+ import { base64 } from "@better-auth/utils/base64";
3
+ //#region src/oauth2/refresh-access-token.ts
4
+ async function refreshAccessTokenRequest({ refreshToken, options, authentication, extraParams, resource }) {
5
+ options = typeof options === "function" ? await options() : options;
6
+ return createRefreshAccessTokenRequest({
7
+ refreshToken,
8
+ options,
9
+ authentication,
10
+ extraParams,
11
+ resource
12
+ });
13
+ }
14
+ /**
15
+ * @deprecated use async'd refreshAccessTokenRequest instead
16
+ */
17
+ function createRefreshAccessTokenRequest({ refreshToken, options, authentication, extraParams, resource }) {
18
+ const body = new URLSearchParams();
19
+ const headers = {
20
+ "content-type": "application/x-www-form-urlencoded",
21
+ accept: "application/json"
22
+ };
23
+ body.set("grant_type", "refresh_token");
24
+ body.set("refresh_token", refreshToken);
25
+ if (authentication === "basic") {
26
+ const primaryClientId = Array.isArray(options.clientId) ? options.clientId[0] : options.clientId;
27
+ if (primaryClientId) headers["authorization"] = "Basic " + base64.encode(`${primaryClientId}:${options.clientSecret ?? ""}`);
28
+ else headers["authorization"] = "Basic " + base64.encode(`:${options.clientSecret ?? ""}`);
29
+ } else {
30
+ const primaryClientId = Array.isArray(options.clientId) ? options.clientId[0] : options.clientId;
31
+ body.set("client_id", primaryClientId);
32
+ if (options.clientSecret) body.set("client_secret", options.clientSecret);
33
+ }
34
+ if (resource) if (typeof resource === "string") body.append("resource", resource);
35
+ else for (const _resource of resource) body.append("resource", _resource);
36
+ if (extraParams) for (const [key, value] of Object.entries(extraParams)) body.set(key, value);
37
+ return {
38
+ body,
39
+ headers
40
+ };
41
+ }
42
+ async function refreshAccessToken({ refreshToken, options, tokenEndpoint, authentication, extraParams }) {
43
+ const { body, headers } = await createRefreshAccessTokenRequest({
44
+ refreshToken,
45
+ options,
46
+ authentication,
47
+ extraParams
48
+ });
49
+ const { data, error } = await fetchRefusingRedirects(tokenEndpoint, {
50
+ method: "POST",
51
+ body,
52
+ headers
53
+ });
54
+ if (error) throw error;
55
+ const tokens = {
56
+ accessToken: data.access_token,
57
+ refreshToken: data.refresh_token,
58
+ tokenType: data.token_type,
59
+ scopes: data.scope?.split(" "),
60
+ idToken: data.id_token
61
+ };
62
+ if (data.expires_in) {
63
+ const now = /* @__PURE__ */ new Date();
64
+ tokens.accessTokenExpiresAt = new Date(now.getTime() + data.expires_in * 1e3);
65
+ }
66
+ if (data.refresh_token_expires_in) {
67
+ const now = /* @__PURE__ */ new Date();
68
+ tokens.refreshTokenExpiresAt = new Date(now.getTime() + data.refresh_token_expires_in * 1e3);
69
+ }
70
+ return tokens;
71
+ }
72
+ //#endregion
73
+ export { createRefreshAccessTokenRequest, refreshAccessToken, refreshAccessTokenRequest };
@@ -0,0 +1,60 @@
1
+ import { BetterAuthError } from "../error/index.mjs";
2
+ import { betterFetch } from "@better-fetch/fetch";
3
+ //#region src/oauth2/reject-redirects.ts
4
+ const HTTP_REDIRECT_STATUSES = new Set([
5
+ 301,
6
+ 302,
7
+ 303,
8
+ 307,
9
+ 308
10
+ ]);
11
+ /**
12
+ * Whether a response from a `redirect: "manual"` fetch is a redirect.
13
+ *
14
+ * Node/undici exposes the real 3xx status. Spec-compliant runtimes (Cloudflare
15
+ * Workers, Deno, browsers) return an opaque-redirect filtered response with
16
+ * status 0 and type `"opaqueredirect"`, so the status alone is not enough.
17
+ */
18
+ function isRedirectResponse(response) {
19
+ return response.type === "opaqueredirect" || HTTP_REDIRECT_STATUSES.has(response.status);
20
+ }
21
+ function redirectRefused(endpoint) {
22
+ return new BetterAuthError(`The OAuth endpoint "${endpoint}" returned an HTTP redirect. Server-side OAuth fetches refuse redirects to prevent SSRF; configure the final endpoint URL.`);
23
+ }
24
+ /**
25
+ * Fetch option that refuses HTTP redirects portably.
26
+ *
27
+ * Cloudflare Workers (workerd) rejects `redirect: "error"`, so manual mode is
28
+ * used and the resolved response is checked with {@link assertResponseNotRedirect}
29
+ * (or, for betterFetch, with {@link fetchRefusingRedirects}).
30
+ */
31
+ const NO_FOLLOW_REDIRECT = { redirect: "manual" };
32
+ /**
33
+ * Throw when a native-`fetch` response (e.g. jose's JWKS loader) resolved to a
34
+ * redirect, so an attacker-influenced endpoint cannot bounce a server-side
35
+ * request to an internal address.
36
+ */
37
+ function assertResponseNotRedirect(endpoint, response) {
38
+ if (isRedirectResponse(response)) throw redirectRefused(endpoint);
39
+ }
40
+ /**
41
+ * betterFetch that refuses HTTP redirects on a server-side OAuth fetch.
42
+ *
43
+ * Returns the betterFetch result and throws if the endpoint redirected, on both
44
+ * undici (real 3xx status) and spec-compliant runtimes (opaque redirect, where
45
+ * the error status is 0). The redirect is never followed on any runtime.
46
+ */
47
+ async function fetchRefusingRedirects(url, options) {
48
+ let redirected = false;
49
+ const result = await betterFetch(url, {
50
+ ...options,
51
+ ...NO_FOLLOW_REDIRECT,
52
+ onError(context) {
53
+ if (isRedirectResponse(context.response)) redirected = true;
54
+ }
55
+ });
56
+ if (redirected) throw redirectRefused(url);
57
+ return result;
58
+ }
59
+ //#endregion
60
+ export { NO_FOLLOW_REDIRECT, assertResponseNotRedirect, fetchRefusingRedirects };
@@ -0,0 +1,24 @@
1
+ import { OAuth2Tokens } from "./oauth-provider.mjs";
2
+
3
+ //#region src/oauth2/utils.d.ts
4
+ declare function getOAuth2Tokens(data: Record<string, any>): OAuth2Tokens;
5
+ /**
6
+ * Fill in `accessTokenExpiresAt` from the provider's configured
7
+ * `accessTokenExpiresIn` when the token response omitted `expires_in`. Without a
8
+ * known expiry, `getAccessToken` cannot tell the token is expired and never
9
+ * refreshes it. No-op when the provider already supplied an expiry or no
10
+ * fallback is configured.
11
+ */
12
+ declare function applyDefaultAccessTokenExpiry(tokens: OAuth2Tokens, accessTokenExpiresIn: number | undefined): OAuth2Tokens;
13
+ /**
14
+ * Return the provider's primary Client ID: the single string, or the entry at
15
+ * array index 0 for the cross-platform form used by ID token audience
16
+ * verification. Index 0 is the designated primary and pairs with
17
+ * `clientSecret` for the authorization code flow; later array entries are
18
+ * only used as additional accepted audiences. Returns `undefined` when the
19
+ * primary value is missing or an empty string.
20
+ */
21
+ declare function getPrimaryClientId(clientId: unknown): string | undefined;
22
+ declare function generateCodeChallenge(codeVerifier: string): Promise<string>;
23
+ //#endregion
24
+ export { applyDefaultAccessTokenExpiry, generateCodeChallenge, getOAuth2Tokens, getPrimaryClientId };
@@ -0,0 +1,48 @@
1
+ import { base64Url } from "@better-auth/utils/base64";
2
+ //#region src/oauth2/utils.ts
3
+ function getOAuth2Tokens(data) {
4
+ const getDate = (seconds) => {
5
+ const now = /* @__PURE__ */ new Date();
6
+ return new Date(now.getTime() + seconds * 1e3);
7
+ };
8
+ return {
9
+ tokenType: data.token_type,
10
+ accessToken: data.access_token,
11
+ refreshToken: data.refresh_token,
12
+ accessTokenExpiresAt: data.expires_in ? getDate(data.expires_in) : void 0,
13
+ refreshTokenExpiresAt: data.refresh_token_expires_in ? getDate(data.refresh_token_expires_in) : void 0,
14
+ scopes: data?.scope ? typeof data.scope === "string" ? data.scope.split(" ") : data.scope : [],
15
+ idToken: data.id_token,
16
+ raw: data
17
+ };
18
+ }
19
+ /**
20
+ * Fill in `accessTokenExpiresAt` from the provider's configured
21
+ * `accessTokenExpiresIn` when the token response omitted `expires_in`. Without a
22
+ * known expiry, `getAccessToken` cannot tell the token is expired and never
23
+ * refreshes it. No-op when the provider already supplied an expiry or no
24
+ * fallback is configured.
25
+ */
26
+ function applyDefaultAccessTokenExpiry(tokens, accessTokenExpiresIn) {
27
+ if (!tokens.accessTokenExpiresAt && accessTokenExpiresIn) tokens.accessTokenExpiresAt = new Date(Date.now() + accessTokenExpiresIn * 1e3);
28
+ return tokens;
29
+ }
30
+ /**
31
+ * Return the provider's primary Client ID: the single string, or the entry at
32
+ * array index 0 for the cross-platform form used by ID token audience
33
+ * verification. Index 0 is the designated primary and pairs with
34
+ * `clientSecret` for the authorization code flow; later array entries are
35
+ * only used as additional accepted audiences. Returns `undefined` when the
36
+ * primary value is missing or an empty string.
37
+ */
38
+ function getPrimaryClientId(clientId) {
39
+ const value = Array.isArray(clientId) ? clientId[0] : clientId;
40
+ return typeof value === "string" && value.length > 0 ? value : void 0;
41
+ }
42
+ async function generateCodeChallenge(codeVerifier) {
43
+ const data = new TextEncoder().encode(codeVerifier);
44
+ const hash = await crypto.subtle.digest("SHA-256", data);
45
+ return base64Url.encode(new Uint8Array(hash), { padding: false });
46
+ }
47
+ //#endregion
48
+ export { applyDefaultAccessTokenExpiry, generateCodeChallenge, getOAuth2Tokens, getPrimaryClientId };
@@ -0,0 +1,85 @@
1
+ import { AwaitableFunction } from "../types/helper.mjs";
2
+ import { OAuth2Tokens, ProviderOptions } from "./oauth-provider.mjs";
3
+ import * as jose from "jose";
4
+
5
+ //#region src/oauth2/validate-authorization-code.d.ts
6
+ declare function authorizationCodeRequest({
7
+ code,
8
+ codeVerifier,
9
+ redirectURI,
10
+ options,
11
+ authentication,
12
+ deviceId,
13
+ headers,
14
+ additionalParams,
15
+ resource
16
+ }: {
17
+ code: string;
18
+ redirectURI: string;
19
+ options: AwaitableFunction<Partial<ProviderOptions>>;
20
+ codeVerifier?: string | undefined;
21
+ deviceId?: string | undefined;
22
+ authentication?: ("basic" | "post") | undefined;
23
+ headers?: Record<string, string> | undefined;
24
+ additionalParams?: Record<string, string> | undefined;
25
+ resource?: (string | string[]) | undefined;
26
+ }): Promise<{
27
+ body: URLSearchParams;
28
+ headers: Record<string, any>;
29
+ }>;
30
+ /**
31
+ * @deprecated use async'd authorizationCodeRequest instead
32
+ */
33
+ declare function createAuthorizationCodeRequest({
34
+ code,
35
+ codeVerifier,
36
+ redirectURI,
37
+ options,
38
+ authentication,
39
+ deviceId,
40
+ headers,
41
+ additionalParams,
42
+ resource
43
+ }: {
44
+ code: string;
45
+ redirectURI: string;
46
+ options: Partial<ProviderOptions>;
47
+ codeVerifier?: string | undefined;
48
+ deviceId?: string | undefined;
49
+ authentication?: ("basic" | "post") | undefined;
50
+ headers?: Record<string, string> | undefined;
51
+ additionalParams?: Record<string, string> | undefined;
52
+ resource?: (string | string[]) | undefined;
53
+ }): {
54
+ body: URLSearchParams;
55
+ headers: Record<string, any>;
56
+ };
57
+ declare function validateAuthorizationCode({
58
+ code,
59
+ codeVerifier,
60
+ redirectURI,
61
+ options,
62
+ tokenEndpoint,
63
+ authentication,
64
+ deviceId,
65
+ headers,
66
+ additionalParams,
67
+ resource
68
+ }: {
69
+ code: string;
70
+ redirectURI: string;
71
+ options: AwaitableFunction<Partial<ProviderOptions>>;
72
+ codeVerifier?: string | undefined;
73
+ deviceId?: string | undefined;
74
+ tokenEndpoint: string;
75
+ authentication?: ("basic" | "post") | undefined;
76
+ headers?: Record<string, string> | undefined;
77
+ additionalParams?: Record<string, string> | undefined;
78
+ resource?: (string | string[]) | undefined;
79
+ }): Promise<OAuth2Tokens>;
80
+ declare function validateToken(token: string, jwksEndpoint: string, options?: {
81
+ audience?: string | string[];
82
+ issuer?: string | string[];
83
+ }): Promise<jose.JWTVerifyResult<jose.JWTPayload> & jose.ResolvedKey>;
84
+ //#endregion
85
+ export { authorizationCodeRequest, createAuthorizationCodeRequest, validateAuthorizationCode, validateToken };
@@ -0,0 +1,86 @@
1
+ import { NO_FOLLOW_REDIRECT, assertResponseNotRedirect, fetchRefusingRedirects } from "./reject-redirects.mjs";
2
+ import { getOAuth2Tokens } from "./utils.mjs";
3
+ import { base64 } from "@better-auth/utils/base64";
4
+ import { createRemoteJWKSet, customFetch, jwtVerify } from "jose";
5
+ //#region src/oauth2/validate-authorization-code.ts
6
+ async function authorizationCodeRequest({ code, codeVerifier, redirectURI, options, authentication, deviceId, headers, additionalParams = {}, resource }) {
7
+ options = typeof options === "function" ? await options() : options;
8
+ return createAuthorizationCodeRequest({
9
+ code,
10
+ codeVerifier,
11
+ redirectURI,
12
+ options,
13
+ authentication,
14
+ deviceId,
15
+ headers,
16
+ additionalParams,
17
+ resource
18
+ });
19
+ }
20
+ /**
21
+ * @deprecated use async'd authorizationCodeRequest instead
22
+ */
23
+ function createAuthorizationCodeRequest({ code, codeVerifier, redirectURI, options, authentication, deviceId, headers, additionalParams = {}, resource }) {
24
+ const body = new URLSearchParams();
25
+ const requestHeaders = {
26
+ "content-type": "application/x-www-form-urlencoded",
27
+ accept: "application/json",
28
+ ...headers
29
+ };
30
+ body.set("grant_type", "authorization_code");
31
+ body.set("code", code);
32
+ codeVerifier && body.set("code_verifier", codeVerifier);
33
+ options.clientKey && body.set("client_key", options.clientKey);
34
+ deviceId && body.set("device_id", deviceId);
35
+ body.set("redirect_uri", options.redirectURI || redirectURI);
36
+ if (resource) if (typeof resource === "string") body.append("resource", resource);
37
+ else for (const _resource of resource) body.append("resource", _resource);
38
+ if (authentication === "basic") {
39
+ const primaryClientId = Array.isArray(options.clientId) ? options.clientId[0] : options.clientId;
40
+ requestHeaders["authorization"] = `Basic ${base64.encode(`${primaryClientId}:${options.clientSecret ?? ""}`)}`;
41
+ } else {
42
+ const primaryClientId = Array.isArray(options.clientId) ? options.clientId[0] : options.clientId;
43
+ body.set("client_id", primaryClientId);
44
+ if (options.clientSecret) body.set("client_secret", options.clientSecret);
45
+ }
46
+ for (const [key, value] of Object.entries(additionalParams)) if (!body.has(key)) body.append(key, value);
47
+ return {
48
+ body,
49
+ headers: requestHeaders
50
+ };
51
+ }
52
+ async function validateAuthorizationCode({ code, codeVerifier, redirectURI, options, tokenEndpoint, authentication, deviceId, headers, additionalParams = {}, resource }) {
53
+ const { body, headers: requestHeaders } = await authorizationCodeRequest({
54
+ code,
55
+ codeVerifier,
56
+ redirectURI,
57
+ options,
58
+ authentication,
59
+ deviceId,
60
+ headers,
61
+ additionalParams,
62
+ resource
63
+ });
64
+ const { data, error } = await fetchRefusingRedirects(tokenEndpoint, {
65
+ method: "POST",
66
+ body,
67
+ headers: requestHeaders
68
+ });
69
+ if (error) throw error;
70
+ return getOAuth2Tokens(data);
71
+ }
72
+ async function validateToken(token, jwksEndpoint, options) {
73
+ return await jwtVerify(token, createRemoteJWKSet(new URL(jwksEndpoint), { [customFetch]: async (url, init) => {
74
+ const response = await fetch(url, {
75
+ ...init,
76
+ ...NO_FOLLOW_REDIRECT
77
+ });
78
+ assertResponseNotRedirect(String(url), response);
79
+ return response;
80
+ } }), {
81
+ audience: options?.audience,
82
+ issuer: options?.issuer
83
+ });
84
+ }
85
+ //#endregion
86
+ export { authorizationCodeRequest, createAuthorizationCodeRequest, validateAuthorizationCode, validateToken };
@@ -0,0 +1,65 @@
1
+ import { JSONWebKeySet, JWTPayload, JWTVerifyOptions } from "jose";
2
+
3
+ //#region src/oauth2/verify.d.ts
4
+ type JwksFetchOptions = {
5
+ /** Jwks url or promise of a Jwks */jwksFetch: string | (() => Promise<JSONWebKeySet | undefined>);
6
+ /**
7
+ * Stable object to cache the result of a function `jwksFetch` under,
8
+ * with the same TTL and kid-miss refetch rules as string sources.
9
+ * Without it, a function source is fetched on every verification.
10
+ */
11
+ jwksCacheKey?: object;
12
+ };
13
+ /**
14
+ * @internal
15
+ */
16
+ interface VerifyAccessTokenRemote {
17
+ /** Full url of the introspect endpoint. Should end with `/oauth2/introspect` */
18
+ introspectUrl: string;
19
+ /** Client Secret */
20
+ clientId: string;
21
+ /** Client Secret */
22
+ clientSecret: string;
23
+ /**
24
+ * Forces remote verification of a token.
25
+ * This ensures attached session (if applicable)
26
+ * is also still active.
27
+ */
28
+ force?: boolean;
29
+ /**
30
+ * Accept introspection responses that omit the `aud` claim even when a
31
+ * required `audience` is configured in `verifyOptions`.
32
+ *
33
+ * By default verification fails closed: if you configure an `audience` and
34
+ * the introspection response has no `aud` (or a mismatching one), the token
35
+ * is rejected. Some authorization servers legitimately omit `aud` from
36
+ * introspection responses (it is OPTIONAL per RFC 7662 §2.2); only enable
37
+ * this if you trust the issuer to bind the token to this resource through
38
+ * another mechanism, as it skips the audience check in that case.
39
+ *
40
+ * @default false
41
+ */
42
+ allowMissingAudience?: boolean;
43
+ }
44
+ /**
45
+ * Performs local verification of an access token for your APIs.
46
+ *
47
+ * Can also be configured for remote verification.
48
+ */
49
+ declare function verifyJwsAccessToken(token: string, opts: JwksFetchOptions & {
50
+ /** Verify options */verifyOptions: JWTVerifyOptions & Required<Pick<JWTVerifyOptions, "audience" | "issuer">>;
51
+ }): Promise<JWTPayload>;
52
+ declare function getJwks(token: string, opts: JwksFetchOptions): Promise<JSONWebKeySet>;
53
+ /**
54
+ * Performs local verification of an access token for your API.
55
+ *
56
+ * Can also be configured for remote verification.
57
+ */
58
+ declare function verifyAccessToken(token: string, opts: {
59
+ /** Verify options */verifyOptions: JWTVerifyOptions & Required<Pick<JWTVerifyOptions, "audience" | "issuer">>; /** Scopes to additionally verify. Token must include all but not exact. */
60
+ scopes?: string[]; /** Required to verify access token locally */
61
+ jwksUrl?: string; /** If provided, can verify a token remotely */
62
+ remoteVerify?: VerifyAccessTokenRemote;
63
+ }): Promise<JWTPayload>;
64
+ //#endregion
65
+ export { getJwks, verifyAccessToken, verifyJwsAccessToken };