@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,188 @@
1
+ import { APIError, BetterAuthError } from "../error/index.mjs";
2
+ import { logger } from "../env/logger.mjs";
3
+ import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
4
+ import { base64 } from "@better-auth/utils/base64";
5
+ import { betterFetch } from "@better-fetch/fetch";
6
+ import { decodeJwt, decodeProtectedHeader, importJWK, jwtVerify } from "jose";
7
+ //#region src/social-providers/paypal.ts
8
+ /**
9
+ * ID token signing algorithms advertised by PayPal's OpenID configuration.
10
+ * Anything outside this allowlist is rejected so each token is only ever
11
+ * verified with the algorithm it was issued for.
12
+ *
13
+ * @see https://www.paypal.com/.well-known/openid-configuration
14
+ */
15
+ const PAYPAL_ID_TOKEN_ALGORITHMS = ["RS256", "HS256"];
16
+ const paypal = (options) => {
17
+ const isSandbox = (options.environment || "sandbox") === "sandbox";
18
+ const authorizationEndpoint = isSandbox ? "https://www.sandbox.paypal.com/signin/authorize" : "https://www.paypal.com/signin/authorize";
19
+ const tokenEndpoint = isSandbox ? "https://api-m.sandbox.paypal.com/v1/oauth2/token" : "https://api-m.paypal.com/v1/oauth2/token";
20
+ const userInfoEndpoint = isSandbox ? "https://api-m.sandbox.paypal.com/v1/identity/oauth2/userinfo" : "https://api-m.paypal.com/v1/identity/oauth2/userinfo";
21
+ /**
22
+ * Issuer and JWKS endpoints used to cryptographically verify ID tokens.
23
+ *
24
+ * @see https://www.paypal.com/.well-known/openid-configuration
25
+ */
26
+ const issuer = isSandbox ? "https://www.sandbox.paypal.com" : "https://www.paypal.com";
27
+ const jwksEndpoint = isSandbox ? "https://api.sandbox.paypal.com/v1/oauth2/certs" : "https://api.paypal.com/v1/oauth2/certs";
28
+ return {
29
+ id: "paypal",
30
+ name: "PayPal",
31
+ async createAuthorizationURL({ state, codeVerifier, redirectURI }) {
32
+ if (!options.clientId || !options.clientSecret) {
33
+ logger.error("Client Id and Client Secret is required for PayPal. Make sure to provide them in the options.");
34
+ throw new BetterAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
35
+ }
36
+ return await createAuthorizationURL({
37
+ id: "paypal",
38
+ options,
39
+ authorizationEndpoint,
40
+ scopes: [],
41
+ state,
42
+ codeVerifier,
43
+ redirectURI,
44
+ prompt: options.prompt
45
+ });
46
+ },
47
+ validateAuthorizationCode: async ({ code, redirectURI }) => {
48
+ /**
49
+ * PayPal requires Basic Auth for token exchange
50
+ **/
51
+ const credentials = base64.encode(`${options.clientId}:${options.clientSecret}`);
52
+ try {
53
+ const response = await betterFetch(tokenEndpoint, {
54
+ method: "POST",
55
+ headers: {
56
+ Authorization: `Basic ${credentials}`,
57
+ Accept: "application/json",
58
+ "Accept-Language": "en_US",
59
+ "Content-Type": "application/x-www-form-urlencoded"
60
+ },
61
+ body: new URLSearchParams({
62
+ grant_type: "authorization_code",
63
+ code,
64
+ redirect_uri: redirectURI
65
+ }).toString()
66
+ });
67
+ if (!response.data) throw new BetterAuthError("FAILED_TO_GET_ACCESS_TOKEN");
68
+ const data = response.data;
69
+ return {
70
+ accessToken: data.access_token,
71
+ refreshToken: data.refresh_token,
72
+ accessTokenExpiresAt: data.expires_in ? new Date(Date.now() + data.expires_in * 1e3) : void 0,
73
+ idToken: data.id_token
74
+ };
75
+ } catch (error) {
76
+ logger.error("PayPal token exchange failed:", error);
77
+ throw new BetterAuthError("FAILED_TO_GET_ACCESS_TOKEN");
78
+ }
79
+ },
80
+ refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
81
+ const credentials = base64.encode(`${options.clientId}:${options.clientSecret}`);
82
+ try {
83
+ const response = await betterFetch(tokenEndpoint, {
84
+ method: "POST",
85
+ headers: {
86
+ Authorization: `Basic ${credentials}`,
87
+ Accept: "application/json",
88
+ "Accept-Language": "en_US",
89
+ "Content-Type": "application/x-www-form-urlencoded"
90
+ },
91
+ body: new URLSearchParams({
92
+ grant_type: "refresh_token",
93
+ refresh_token: refreshToken
94
+ }).toString()
95
+ });
96
+ if (!response.data) throw new BetterAuthError("FAILED_TO_REFRESH_ACCESS_TOKEN");
97
+ const data = response.data;
98
+ return {
99
+ accessToken: data.access_token,
100
+ refreshToken: data.refresh_token,
101
+ accessTokenExpiresAt: data.expires_in ? new Date(Date.now() + data.expires_in * 1e3) : void 0
102
+ };
103
+ } catch (error) {
104
+ logger.error("PayPal token refresh failed:", error);
105
+ throw new BetterAuthError("FAILED_TO_REFRESH_ACCESS_TOKEN");
106
+ }
107
+ },
108
+ async verifyIdToken(token, nonce) {
109
+ if (options.disableIdTokenSignIn) return false;
110
+ if (options.verifyIdToken) return options.verifyIdToken(token, nonce);
111
+ try {
112
+ const { kid, alg: jwtAlg } = decodeProtectedHeader(token);
113
+ if (!jwtAlg) return false;
114
+ if (!PAYPAL_ID_TOKEN_ALGORITHMS.includes(jwtAlg)) return false;
115
+ const key = jwtAlg === "HS256" ? new TextEncoder().encode(options.clientSecret) : kid ? await getPayPalPublicKey(kid, jwksEndpoint) : void 0;
116
+ if (!key) return false;
117
+ const { payload: jwtClaims } = await jwtVerify(token, key, {
118
+ algorithms: [jwtAlg],
119
+ issuer,
120
+ audience: options.clientId,
121
+ maxTokenAge: "1h"
122
+ });
123
+ if (nonce && jwtClaims.nonce !== nonce) return false;
124
+ return true;
125
+ } catch (error) {
126
+ logger.error("Failed to verify PayPal ID token:", error);
127
+ return false;
128
+ }
129
+ },
130
+ async getUserInfo(token) {
131
+ if (options.getUserInfo) return options.getUserInfo(token);
132
+ if (!token.accessToken) {
133
+ logger.error("Access token is required to fetch PayPal user info");
134
+ return null;
135
+ }
136
+ try {
137
+ const response = await betterFetch(`${userInfoEndpoint}?schema=paypalv1.1`, { headers: {
138
+ Authorization: `Bearer ${token.accessToken}`,
139
+ Accept: "application/json"
140
+ } });
141
+ if (!response.data) {
142
+ logger.error("Failed to fetch user info from PayPal");
143
+ return null;
144
+ }
145
+ const userInfo = response.data;
146
+ if (token.idToken) {
147
+ let idTokenSubject;
148
+ try {
149
+ idTokenSubject = decodeJwt(token.idToken).sub;
150
+ } catch (error) {
151
+ logger.error("Failed to decode PayPal ID token:", error);
152
+ return null;
153
+ }
154
+ const userInfoSubject = userInfo.sub ?? userInfo.user_id;
155
+ if (!idTokenSubject || userInfoSubject !== idTokenSubject) {
156
+ logger.error("PayPal user info subject does not match ID token subject");
157
+ return null;
158
+ }
159
+ }
160
+ const userMap = await options.mapProfileToUser?.(userInfo);
161
+ return {
162
+ user: {
163
+ id: userInfo.user_id,
164
+ name: userInfo.name,
165
+ email: userInfo.email,
166
+ image: userInfo.picture,
167
+ emailVerified: userInfo.email_verified,
168
+ ...userMap
169
+ },
170
+ data: userInfo
171
+ };
172
+ } catch (error) {
173
+ logger.error("Failed to fetch user info from PayPal:", error);
174
+ return null;
175
+ }
176
+ },
177
+ options
178
+ };
179
+ };
180
+ const getPayPalPublicKey = async (kid, jwksUri) => {
181
+ const { data } = await betterFetch(jwksUri);
182
+ if (!data?.keys) throw new APIError("BAD_REQUEST", { message: "Keys not found" });
183
+ const jwk = data.keys.find((key) => key.kid === kid);
184
+ if (!jwk) throw new Error(`JWK with kid ${kid} not found`);
185
+ return await importJWK(jwk, jwk.alg);
186
+ };
187
+ //#endregion
188
+ export { getPayPalPublicKey, paypal };
@@ -0,0 +1,74 @@
1
+ import { OAuth2Tokens, ProviderOptions } from "../oauth2/oauth-provider.mjs";
2
+ //#region src/social-providers/polar.d.ts
3
+ interface PolarProfile {
4
+ id: string;
5
+ email: string;
6
+ username: string;
7
+ avatar_url: string;
8
+ github_username?: string | undefined;
9
+ account_id?: string | undefined;
10
+ public_name?: string | undefined;
11
+ email_verified?: boolean | undefined;
12
+ profile_settings?: {
13
+ profile_settings_enabled?: boolean;
14
+ profile_settings_public_name?: string;
15
+ profile_settings_public_avatar?: string;
16
+ profile_settings_public_bio?: string;
17
+ profile_settings_public_location?: string;
18
+ profile_settings_public_website?: string;
19
+ profile_settings_public_twitter?: string;
20
+ profile_settings_public_github?: string;
21
+ profile_settings_public_email?: string;
22
+ } | undefined;
23
+ }
24
+ interface PolarOptions extends ProviderOptions<PolarProfile> {}
25
+ declare const polar: (options: PolarOptions) => {
26
+ id: "polar";
27
+ name: string;
28
+ createAuthorizationURL({
29
+ state,
30
+ scopes,
31
+ codeVerifier,
32
+ redirectURI
33
+ }: {
34
+ state: string;
35
+ codeVerifier: string;
36
+ scopes?: string[] | undefined;
37
+ redirectURI: string;
38
+ display?: string | undefined;
39
+ loginHint?: string | undefined;
40
+ }): Promise<URL>;
41
+ validateAuthorizationCode: ({
42
+ code,
43
+ codeVerifier,
44
+ redirectURI
45
+ }: {
46
+ code: string;
47
+ redirectURI: string;
48
+ codeVerifier?: string | undefined;
49
+ deviceId?: string | undefined;
50
+ }) => Promise<OAuth2Tokens>;
51
+ refreshAccessToken: (refreshToken: string) => Promise<OAuth2Tokens>;
52
+ getUserInfo(token: OAuth2Tokens & {
53
+ user?: {
54
+ name?: {
55
+ firstName?: string;
56
+ lastName?: string;
57
+ };
58
+ email?: string;
59
+ } | undefined;
60
+ }): Promise<{
61
+ user: {
62
+ id: string;
63
+ name?: string;
64
+ email?: string | null;
65
+ image?: string;
66
+ emailVerified: boolean;
67
+ [key: string]: any;
68
+ };
69
+ data: any;
70
+ } | null>;
71
+ options: PolarOptions;
72
+ };
73
+ //#endregion
74
+ export { PolarOptions, PolarProfile, polar };
@@ -0,0 +1,71 @@
1
+ import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
2
+ import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
3
+ import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
4
+ import { betterFetch } from "@better-fetch/fetch";
5
+ //#region src/social-providers/polar.ts
6
+ const polar = (options) => {
7
+ const tokenEndpoint = "https://api.polar.sh/v1/oauth2/token";
8
+ return {
9
+ id: "polar",
10
+ name: "Polar",
11
+ createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {
12
+ const _scopes = options.disableDefaultScope ? [] : [
13
+ "openid",
14
+ "profile",
15
+ "email"
16
+ ];
17
+ if (options.scope) _scopes.push(...options.scope);
18
+ if (scopes) _scopes.push(...scopes);
19
+ return createAuthorizationURL({
20
+ id: "polar",
21
+ options,
22
+ authorizationEndpoint: "https://polar.sh/oauth2/authorize",
23
+ scopes: _scopes,
24
+ state,
25
+ codeVerifier,
26
+ redirectURI,
27
+ prompt: options.prompt
28
+ });
29
+ },
30
+ validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
31
+ return validateAuthorizationCode({
32
+ code,
33
+ codeVerifier,
34
+ redirectURI,
35
+ options,
36
+ tokenEndpoint
37
+ });
38
+ },
39
+ refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
40
+ return refreshAccessToken({
41
+ refreshToken,
42
+ options: {
43
+ clientId: options.clientId,
44
+ clientKey: options.clientKey,
45
+ clientSecret: options.clientSecret
46
+ },
47
+ tokenEndpoint
48
+ });
49
+ },
50
+ async getUserInfo(token) {
51
+ if (options.getUserInfo) return options.getUserInfo(token);
52
+ const { data: profile, error } = await betterFetch("https://api.polar.sh/v1/oauth2/userinfo", { headers: { Authorization: `Bearer ${token.accessToken}` } });
53
+ if (error) return null;
54
+ const userMap = await options.mapProfileToUser?.(profile);
55
+ return {
56
+ user: {
57
+ id: profile.id,
58
+ name: profile.public_name || profile.username || "",
59
+ email: profile.email,
60
+ image: profile.avatar_url,
61
+ emailVerified: profile.email_verified ?? false,
62
+ ...userMap
63
+ },
64
+ data: profile
65
+ };
66
+ },
67
+ options
68
+ };
69
+ };
70
+ //#endregion
71
+ export { polar };
@@ -0,0 +1,65 @@
1
+ import { OAuth2Tokens, ProviderOptions } from "../oauth2/oauth-provider.mjs";
2
+ //#region src/social-providers/railway.d.ts
3
+ interface RailwayProfile {
4
+ /** The user's unique ID (OAuth `sub` claim). */
5
+ sub: string;
6
+ /** The user's email address. */
7
+ email: string;
8
+ /** The user's display name. */
9
+ name: string;
10
+ /** URL of the user's profile picture. */
11
+ picture: string;
12
+ }
13
+ interface RailwayOptions extends ProviderOptions<RailwayProfile> {
14
+ clientId: string;
15
+ }
16
+ declare const railway: (options: RailwayOptions) => {
17
+ id: "railway";
18
+ name: string;
19
+ createAuthorizationURL({
20
+ state,
21
+ scopes,
22
+ codeVerifier,
23
+ redirectURI
24
+ }: {
25
+ state: string;
26
+ codeVerifier: string;
27
+ scopes?: string[] | undefined;
28
+ redirectURI: string;
29
+ display?: string | undefined;
30
+ loginHint?: string | undefined;
31
+ }): Promise<URL>;
32
+ validateAuthorizationCode: ({
33
+ code,
34
+ codeVerifier,
35
+ redirectURI
36
+ }: {
37
+ code: string;
38
+ redirectURI: string;
39
+ codeVerifier?: string | undefined;
40
+ deviceId?: string | undefined;
41
+ }) => Promise<OAuth2Tokens>;
42
+ refreshAccessToken: (refreshToken: string) => Promise<OAuth2Tokens>;
43
+ getUserInfo(token: OAuth2Tokens & {
44
+ user?: {
45
+ name?: {
46
+ firstName?: string;
47
+ lastName?: string;
48
+ };
49
+ email?: string;
50
+ } | undefined;
51
+ }): Promise<{
52
+ user: {
53
+ id: string;
54
+ name?: string;
55
+ email?: string | null;
56
+ image?: string;
57
+ emailVerified: boolean;
58
+ [key: string]: any;
59
+ };
60
+ data: any;
61
+ } | null>;
62
+ options: RailwayOptions;
63
+ };
64
+ //#endregion
65
+ export { RailwayOptions, RailwayProfile, railway };
@@ -0,0 +1,74 @@
1
+ import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
2
+ import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
3
+ import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
4
+ import { betterFetch } from "@better-fetch/fetch";
5
+ //#region src/social-providers/railway.ts
6
+ const authorizationEndpoint = "https://backboard.railway.com/oauth/auth";
7
+ const tokenEndpoint = "https://backboard.railway.com/oauth/token";
8
+ const userinfoEndpoint = "https://backboard.railway.com/oauth/me";
9
+ const railway = (options) => {
10
+ return {
11
+ id: "railway",
12
+ name: "Railway",
13
+ createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {
14
+ const _scopes = options.disableDefaultScope ? [] : [
15
+ "openid",
16
+ "email",
17
+ "profile"
18
+ ];
19
+ if (options.scope) _scopes.push(...options.scope);
20
+ if (scopes) _scopes.push(...scopes);
21
+ return createAuthorizationURL({
22
+ id: "railway",
23
+ options,
24
+ authorizationEndpoint,
25
+ scopes: _scopes,
26
+ state,
27
+ codeVerifier,
28
+ redirectURI
29
+ });
30
+ },
31
+ validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
32
+ return validateAuthorizationCode({
33
+ code,
34
+ codeVerifier,
35
+ redirectURI,
36
+ options,
37
+ tokenEndpoint,
38
+ authentication: "basic"
39
+ });
40
+ },
41
+ refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
42
+ return refreshAccessToken({
43
+ refreshToken,
44
+ options: {
45
+ clientId: options.clientId,
46
+ clientKey: options.clientKey,
47
+ clientSecret: options.clientSecret
48
+ },
49
+ tokenEndpoint,
50
+ authentication: "basic"
51
+ });
52
+ },
53
+ async getUserInfo(token) {
54
+ if (options.getUserInfo) return options.getUserInfo(token);
55
+ const { data: profile, error } = await betterFetch(userinfoEndpoint, { headers: { authorization: `Bearer ${token.accessToken}` } });
56
+ if (error || !profile) return null;
57
+ const userMap = await options.mapProfileToUser?.(profile);
58
+ return {
59
+ user: {
60
+ id: profile.sub,
61
+ name: profile.name,
62
+ email: profile.email,
63
+ image: profile.picture,
64
+ emailVerified: false,
65
+ ...userMap
66
+ },
67
+ data: profile
68
+ };
69
+ },
70
+ options
71
+ };
72
+ };
73
+ //#endregion
74
+ export { railway };
@@ -0,0 +1,62 @@
1
+ import { OAuth2Tokens, ProviderOptions } from "../oauth2/oauth-provider.mjs";
2
+ //#region src/social-providers/reddit.d.ts
3
+ interface RedditProfile {
4
+ id: string;
5
+ name: string;
6
+ icon_img: string | null;
7
+ has_verified_email: boolean;
8
+ oauth_client_id: string;
9
+ verified: boolean;
10
+ }
11
+ interface RedditOptions extends ProviderOptions<RedditProfile> {
12
+ clientId: string;
13
+ duration?: string | undefined;
14
+ }
15
+ declare const reddit: (options: RedditOptions) => {
16
+ id: "reddit";
17
+ name: string;
18
+ createAuthorizationURL({
19
+ state,
20
+ scopes,
21
+ redirectURI
22
+ }: {
23
+ state: string;
24
+ codeVerifier: string;
25
+ scopes?: string[] | undefined;
26
+ redirectURI: string;
27
+ display?: string | undefined;
28
+ loginHint?: string | undefined;
29
+ }): Promise<URL>;
30
+ validateAuthorizationCode: ({
31
+ code,
32
+ redirectURI
33
+ }: {
34
+ code: string;
35
+ redirectURI: string;
36
+ codeVerifier?: string | undefined;
37
+ deviceId?: string | undefined;
38
+ }) => Promise<OAuth2Tokens>;
39
+ refreshAccessToken: (refreshToken: string) => Promise<OAuth2Tokens>;
40
+ getUserInfo(token: OAuth2Tokens & {
41
+ user?: {
42
+ name?: {
43
+ firstName?: string;
44
+ lastName?: string;
45
+ };
46
+ email?: string;
47
+ } | undefined;
48
+ }): Promise<{
49
+ user: {
50
+ id: string;
51
+ name?: string;
52
+ email?: string | null;
53
+ image?: string;
54
+ emailVerified: boolean;
55
+ [key: string]: any;
56
+ };
57
+ data: any;
58
+ } | null>;
59
+ options: RedditOptions;
60
+ };
61
+ //#endregion
62
+ export { RedditOptions, RedditProfile, reddit };
@@ -0,0 +1,81 @@
1
+ import { getOAuth2Tokens } from "../oauth2/utils.mjs";
2
+ import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
3
+ import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
4
+ import { base64 } from "@better-auth/utils/base64";
5
+ import { betterFetch } from "@better-fetch/fetch";
6
+ //#region src/social-providers/reddit.ts
7
+ const reddit = (options) => {
8
+ return {
9
+ id: "reddit",
10
+ name: "Reddit",
11
+ createAuthorizationURL({ state, scopes, redirectURI }) {
12
+ const _scopes = options.disableDefaultScope ? [] : ["identity"];
13
+ if (options.scope) _scopes.push(...options.scope);
14
+ if (scopes) _scopes.push(...scopes);
15
+ return createAuthorizationURL({
16
+ id: "reddit",
17
+ options,
18
+ authorizationEndpoint: "https://www.reddit.com/api/v1/authorize",
19
+ scopes: _scopes,
20
+ state,
21
+ redirectURI,
22
+ duration: options.duration
23
+ });
24
+ },
25
+ validateAuthorizationCode: async ({ code, redirectURI }) => {
26
+ const body = new URLSearchParams({
27
+ grant_type: "authorization_code",
28
+ code,
29
+ redirect_uri: options.redirectURI || redirectURI
30
+ });
31
+ const { data, error } = await betterFetch("https://www.reddit.com/api/v1/access_token", {
32
+ method: "POST",
33
+ headers: {
34
+ "content-type": "application/x-www-form-urlencoded",
35
+ accept: "text/plain",
36
+ "user-agent": "better-auth",
37
+ Authorization: `Basic ${base64.encode(`${options.clientId}:${options.clientSecret}`)}`
38
+ },
39
+ body: body.toString()
40
+ });
41
+ if (error) throw error;
42
+ return getOAuth2Tokens(data);
43
+ },
44
+ refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
45
+ return refreshAccessToken({
46
+ refreshToken,
47
+ options: {
48
+ clientId: options.clientId,
49
+ clientKey: options.clientKey,
50
+ clientSecret: options.clientSecret
51
+ },
52
+ authentication: "basic",
53
+ tokenEndpoint: "https://www.reddit.com/api/v1/access_token"
54
+ });
55
+ },
56
+ async getUserInfo(token) {
57
+ if (options.getUserInfo) return options.getUserInfo(token);
58
+ const { data: profile, error } = await betterFetch("https://oauth.reddit.com/api/v1/me", { headers: {
59
+ Authorization: `Bearer ${token.accessToken}`,
60
+ "User-Agent": "better-auth"
61
+ } });
62
+ if (error) return null;
63
+ const userMap = await options.mapProfileToUser?.(profile);
64
+ const email = userMap?.email || `${profile.id}@reddit.invalid`;
65
+ return {
66
+ user: {
67
+ id: profile.id,
68
+ name: profile.name,
69
+ image: profile.icon_img?.split("?")[0],
70
+ ...userMap,
71
+ email,
72
+ emailVerified: userMap?.emailVerified ?? false
73
+ },
74
+ data: profile
75
+ };
76
+ },
77
+ options
78
+ };
79
+ };
80
+ //#endregion
81
+ export { reddit };
@@ -0,0 +1,70 @@
1
+ import { OAuth2Tokens, ProviderOptions } from "../oauth2/oauth-provider.mjs";
2
+ //#region src/social-providers/roblox.d.ts
3
+ interface RobloxProfile extends Record<string, any> {
4
+ /** the user's id */
5
+ sub: string;
6
+ /** the user's username */
7
+ preferred_username: string;
8
+ /** the user's display name, will return the same value as the preferred_username if not set */
9
+ nickname: string;
10
+ /** the user's display name, again, will return the same value as the preferred_username if not set */
11
+ name: string;
12
+ /** the account creation date as a unix timestamp in seconds */
13
+ created_at: number;
14
+ /** the user's profile URL */
15
+ profile: string;
16
+ /** the user's avatar URL */
17
+ picture: string;
18
+ }
19
+ interface RobloxOptions extends ProviderOptions<RobloxProfile> {
20
+ clientId: string;
21
+ prompt?: ("none" | "consent" | "login" | "select_account" | "select_account consent") | undefined;
22
+ }
23
+ declare const roblox: (options: RobloxOptions) => {
24
+ id: "roblox";
25
+ name: string;
26
+ createAuthorizationURL({
27
+ state,
28
+ scopes,
29
+ redirectURI
30
+ }: {
31
+ state: string;
32
+ codeVerifier: string;
33
+ scopes?: string[] | undefined;
34
+ redirectURI: string;
35
+ display?: string | undefined;
36
+ loginHint?: string | undefined;
37
+ }): URL;
38
+ validateAuthorizationCode: ({
39
+ code,
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: RobloxOptions;
68
+ };
69
+ //#endregion
70
+ export { RobloxOptions, RobloxProfile, roblox };