@better-auth/core 1.4.17 → 1.5.0-beta.10

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 (278) hide show
  1. package/.turbo/turbo-build.log +259 -178
  2. package/LICENSE.md +15 -12
  3. package/dist/api/index.d.mts +27 -28
  4. package/dist/api/index.mjs +2 -1
  5. package/dist/api/index.mjs.map +1 -0
  6. package/dist/async_hooks/index.d.mts +2 -1
  7. package/dist/async_hooks/index.mjs +2 -1
  8. package/dist/async_hooks/index.mjs.map +1 -0
  9. package/dist/async_hooks/pure.index.d.mts +2 -1
  10. package/dist/async_hooks/pure.index.mjs +2 -1
  11. package/dist/async_hooks/pure.index.mjs.map +1 -0
  12. package/dist/context/endpoint-context.d.mts +3 -2
  13. package/dist/context/endpoint-context.mjs +4 -3
  14. package/dist/context/endpoint-context.mjs.map +1 -0
  15. package/dist/context/global.d.mts +2 -2
  16. package/dist/context/global.mjs +3 -2
  17. package/dist/context/global.mjs.map +1 -0
  18. package/dist/context/index.d.mts +2 -2
  19. package/dist/context/index.mjs +2 -2
  20. package/dist/context/request-state.d.mts +2 -1
  21. package/dist/context/request-state.mjs +4 -3
  22. package/dist/context/request-state.mjs.map +1 -0
  23. package/dist/context/transaction.d.mts +12 -3
  24. package/dist/context/transaction.mjs +55 -11
  25. package/dist/context/transaction.mjs.map +1 -0
  26. package/dist/db/adapter/factory.d.mts +3 -10
  27. package/dist/db/adapter/factory.mjs +27 -54
  28. package/dist/db/adapter/factory.mjs.map +1 -0
  29. package/dist/db/adapter/get-default-field-name.d.mts +2 -1
  30. package/dist/db/adapter/get-default-field-name.mjs +3 -2
  31. package/dist/db/adapter/get-default-field-name.mjs.map +1 -0
  32. package/dist/db/adapter/get-default-model-name.d.mts +2 -1
  33. package/dist/db/adapter/get-default-model-name.mjs +5 -4
  34. package/dist/db/adapter/get-default-model-name.mjs.map +1 -0
  35. package/dist/db/adapter/get-field-attributes.d.mts +3 -2
  36. package/dist/db/adapter/get-field-attributes.mjs +2 -1
  37. package/dist/db/adapter/get-field-attributes.mjs.map +1 -0
  38. package/dist/db/adapter/get-field-name.d.mts +2 -1
  39. package/dist/db/adapter/get-field-name.mjs +2 -1
  40. package/dist/db/adapter/get-field-name.mjs.map +1 -0
  41. package/dist/db/adapter/get-id-field.d.mts +3 -2
  42. package/dist/db/adapter/get-id-field.mjs +3 -3
  43. package/dist/db/adapter/get-id-field.mjs.map +1 -0
  44. package/dist/db/adapter/get-model-name.d.mts +2 -1
  45. package/dist/db/adapter/get-model-name.mjs +2 -1
  46. package/dist/db/adapter/get-model-name.mjs.map +1 -0
  47. package/dist/db/adapter/index.d.mts +4 -3
  48. package/dist/db/adapter/index.mjs +2 -2
  49. package/dist/db/adapter/types.d.mts +4 -35
  50. package/dist/db/adapter/utils.d.mts +2 -1
  51. package/dist/db/adapter/utils.mjs +2 -1
  52. package/dist/db/adapter/utils.mjs.map +1 -0
  53. package/dist/db/get-tables.d.mts +2 -1
  54. package/dist/db/get-tables.mjs +46 -39
  55. package/dist/db/get-tables.mjs.map +1 -0
  56. package/dist/db/plugin.d.mts +2 -1
  57. package/dist/db/schema/account.d.mts +2 -1
  58. package/dist/db/schema/account.mjs +2 -1
  59. package/dist/db/schema/account.mjs.map +1 -0
  60. package/dist/db/schema/rate-limit.d.mts +2 -1
  61. package/dist/db/schema/rate-limit.mjs +2 -1
  62. package/dist/db/schema/rate-limit.mjs.map +1 -0
  63. package/dist/db/schema/session.d.mts +2 -1
  64. package/dist/db/schema/session.mjs +2 -1
  65. package/dist/db/schema/session.mjs.map +1 -0
  66. package/dist/db/schema/shared.d.mts +2 -1
  67. package/dist/db/schema/shared.mjs +2 -1
  68. package/dist/db/schema/shared.mjs.map +1 -0
  69. package/dist/db/schema/user.d.mts +2 -1
  70. package/dist/db/schema/user.mjs +2 -1
  71. package/dist/db/schema/user.mjs.map +1 -0
  72. package/dist/db/schema/verification.d.mts +2 -1
  73. package/dist/db/schema/verification.mjs +2 -1
  74. package/dist/db/schema/verification.mjs.map +1 -0
  75. package/dist/db/type.d.mts +5 -1
  76. package/dist/env/color-depth.d.mts +2 -1
  77. package/dist/env/color-depth.mjs +2 -1
  78. package/dist/env/color-depth.mjs.map +1 -0
  79. package/dist/env/env-impl.d.mts +3 -2
  80. package/dist/env/env-impl.mjs +9 -8
  81. package/dist/env/env-impl.mjs.map +1 -0
  82. package/dist/env/logger.d.mts +2 -1
  83. package/dist/env/logger.mjs +3 -2
  84. package/dist/env/logger.mjs.map +1 -0
  85. package/dist/error/codes.d.mts +65 -44
  86. package/dist/error/codes.mjs +8 -3
  87. package/dist/error/codes.mjs.map +1 -0
  88. package/dist/error/index.d.mts +12 -2
  89. package/dist/error/index.mjs +17 -1
  90. package/dist/error/index.mjs.map +1 -0
  91. package/dist/index.d.mts +5 -5
  92. package/dist/oauth2/client-credentials-token.d.mts +2 -1
  93. package/dist/oauth2/client-credentials-token.mjs +2 -1
  94. package/dist/oauth2/client-credentials-token.mjs.map +1 -0
  95. package/dist/oauth2/create-authorization-url.d.mts +2 -1
  96. package/dist/oauth2/create-authorization-url.mjs +2 -1
  97. package/dist/oauth2/create-authorization-url.mjs.map +1 -0
  98. package/dist/oauth2/oauth-provider.d.mts +3 -2
  99. package/dist/oauth2/refresh-access-token.d.mts +2 -3
  100. package/dist/oauth2/refresh-access-token.mjs +2 -1
  101. package/dist/oauth2/refresh-access-token.mjs.map +1 -0
  102. package/dist/oauth2/utils.d.mts +2 -1
  103. package/dist/oauth2/utils.mjs +2 -1
  104. package/dist/oauth2/utils.mjs.map +1 -0
  105. package/dist/oauth2/validate-authorization-code.d.mts +2 -1
  106. package/dist/oauth2/validate-authorization-code.mjs +6 -5
  107. package/dist/oauth2/validate-authorization-code.mjs.map +1 -0
  108. package/dist/oauth2/verify.d.mts +7 -13
  109. package/dist/oauth2/verify.mjs +3 -2
  110. package/dist/oauth2/verify.mjs.map +1 -0
  111. package/dist/social-providers/apple.d.mts +2 -1
  112. package/dist/social-providers/apple.mjs +6 -3
  113. package/dist/social-providers/apple.mjs.map +1 -0
  114. package/dist/social-providers/atlassian.d.mts +2 -1
  115. package/dist/social-providers/atlassian.mjs +2 -1
  116. package/dist/social-providers/atlassian.mjs.map +1 -0
  117. package/dist/social-providers/cognito.d.mts +2 -1
  118. package/dist/social-providers/cognito.mjs +3 -3
  119. package/dist/social-providers/cognito.mjs.map +1 -0
  120. package/dist/social-providers/discord.d.mts +2 -1
  121. package/dist/social-providers/discord.mjs +2 -1
  122. package/dist/social-providers/discord.mjs.map +1 -0
  123. package/dist/social-providers/dropbox.d.mts +2 -1
  124. package/dist/social-providers/dropbox.mjs +3 -2
  125. package/dist/social-providers/dropbox.mjs.map +1 -0
  126. package/dist/social-providers/facebook.d.mts +2 -1
  127. package/dist/social-providers/facebook.mjs +13 -12
  128. package/dist/social-providers/facebook.mjs.map +1 -0
  129. package/dist/social-providers/figma.d.mts +2 -1
  130. package/dist/social-providers/figma.mjs +2 -1
  131. package/dist/social-providers/figma.mjs.map +1 -0
  132. package/dist/social-providers/github.d.mts +3 -2
  133. package/dist/social-providers/github.mjs +22 -5
  134. package/dist/social-providers/github.mjs.map +1 -0
  135. package/dist/social-providers/gitlab.d.mts +2 -1
  136. package/dist/social-providers/gitlab.mjs +2 -1
  137. package/dist/social-providers/gitlab.mjs.map +1 -0
  138. package/dist/social-providers/google.d.mts +2 -1
  139. package/dist/social-providers/google.mjs +5 -5
  140. package/dist/social-providers/google.mjs.map +1 -0
  141. package/dist/social-providers/huggingface.d.mts +2 -1
  142. package/dist/social-providers/huggingface.mjs +2 -1
  143. package/dist/social-providers/huggingface.mjs.map +1 -0
  144. package/dist/social-providers/index.d.mts +3 -2
  145. package/dist/social-providers/index.mjs +2 -1
  146. package/dist/social-providers/index.mjs.map +1 -0
  147. package/dist/social-providers/kakao.d.mts +2 -1
  148. package/dist/social-providers/kakao.mjs +2 -1
  149. package/dist/social-providers/kakao.mjs.map +1 -0
  150. package/dist/social-providers/kick.d.mts +2 -1
  151. package/dist/social-providers/kick.mjs +2 -1
  152. package/dist/social-providers/kick.mjs.map +1 -0
  153. package/dist/social-providers/line.d.mts +2 -1
  154. package/dist/social-providers/line.mjs +2 -1
  155. package/dist/social-providers/line.mjs.map +1 -0
  156. package/dist/social-providers/linear.d.mts +2 -1
  157. package/dist/social-providers/linear.mjs +2 -1
  158. package/dist/social-providers/linear.mjs.map +1 -0
  159. package/dist/social-providers/linkedin.d.mts +2 -1
  160. package/dist/social-providers/linkedin.mjs +2 -1
  161. package/dist/social-providers/linkedin.mjs.map +1 -0
  162. package/dist/social-providers/microsoft-entra-id.d.mts +2 -1
  163. package/dist/social-providers/microsoft-entra-id.mjs +2 -1
  164. package/dist/social-providers/microsoft-entra-id.mjs.map +1 -0
  165. package/dist/social-providers/naver.d.mts +11 -20
  166. package/dist/social-providers/naver.mjs +2 -1
  167. package/dist/social-providers/naver.mjs.map +1 -0
  168. package/dist/social-providers/notion.d.mts +2 -1
  169. package/dist/social-providers/notion.mjs +2 -1
  170. package/dist/social-providers/notion.mjs.map +1 -0
  171. package/dist/social-providers/paybin.d.mts +2 -1
  172. package/dist/social-providers/paybin.mjs +2 -1
  173. package/dist/social-providers/paybin.mjs.map +1 -0
  174. package/dist/social-providers/paypal.d.mts +2 -1
  175. package/dist/social-providers/paypal.mjs +2 -1
  176. package/dist/social-providers/paypal.mjs.map +1 -0
  177. package/dist/social-providers/polar.d.mts +2 -1
  178. package/dist/social-providers/polar.mjs +2 -1
  179. package/dist/social-providers/polar.mjs.map +1 -0
  180. package/dist/social-providers/reddit.d.mts +2 -1
  181. package/dist/social-providers/reddit.mjs +2 -1
  182. package/dist/social-providers/reddit.mjs.map +1 -0
  183. package/dist/social-providers/roblox.d.mts +2 -1
  184. package/dist/social-providers/roblox.mjs +2 -1
  185. package/dist/social-providers/roblox.mjs.map +1 -0
  186. package/dist/social-providers/salesforce.d.mts +2 -1
  187. package/dist/social-providers/salesforce.mjs +2 -1
  188. package/dist/social-providers/salesforce.mjs.map +1 -0
  189. package/dist/social-providers/slack.d.mts +2 -1
  190. package/dist/social-providers/slack.mjs +2 -1
  191. package/dist/social-providers/slack.mjs.map +1 -0
  192. package/dist/social-providers/spotify.d.mts +2 -1
  193. package/dist/social-providers/spotify.mjs +2 -1
  194. package/dist/social-providers/spotify.mjs.map +1 -0
  195. package/dist/social-providers/tiktok.d.mts +3 -3
  196. package/dist/social-providers/tiktok.mjs +2 -1
  197. package/dist/social-providers/tiktok.mjs.map +1 -0
  198. package/dist/social-providers/twitch.d.mts +2 -1
  199. package/dist/social-providers/twitch.mjs +2 -1
  200. package/dist/social-providers/twitch.mjs.map +1 -0
  201. package/dist/social-providers/twitter.d.mts +14 -25
  202. package/dist/social-providers/twitter.mjs +2 -1
  203. package/dist/social-providers/twitter.mjs.map +1 -0
  204. package/dist/social-providers/vercel.d.mts +2 -1
  205. package/dist/social-providers/vercel.mjs +2 -1
  206. package/dist/social-providers/vercel.mjs.map +1 -0
  207. package/dist/social-providers/vk.d.mts +2 -1
  208. package/dist/social-providers/vk.mjs +2 -1
  209. package/dist/social-providers/vk.mjs.map +1 -0
  210. package/dist/social-providers/zoom.d.mts +3 -10
  211. package/dist/social-providers/zoom.mjs +2 -1
  212. package/dist/social-providers/zoom.mjs.map +1 -0
  213. package/dist/types/context.d.mts +64 -11
  214. package/dist/types/cookie.d.mts +2 -1
  215. package/dist/types/helper.d.mts +3 -1
  216. package/dist/types/index.d.mts +4 -4
  217. package/dist/types/init-options.d.mts +79 -86
  218. package/dist/types/plugin-client.d.mts +10 -1
  219. package/dist/types/plugin.d.mts +12 -8
  220. package/dist/utils/db.d.mts +12 -0
  221. package/dist/utils/db.mjs +17 -0
  222. package/dist/utils/db.mjs.map +1 -0
  223. package/dist/utils/deprecate.d.mts +2 -2
  224. package/dist/utils/deprecate.mjs +2 -1
  225. package/dist/utils/deprecate.mjs.map +1 -0
  226. package/dist/utils/error-codes.d.mts +8 -3
  227. package/dist/utils/error-codes.mjs +7 -2
  228. package/dist/utils/error-codes.mjs.map +1 -0
  229. package/dist/utils/id.d.mts +2 -1
  230. package/dist/utils/id.mjs +2 -1
  231. package/dist/utils/id.mjs.map +1 -0
  232. package/dist/utils/ip.d.mts +2 -1
  233. package/dist/utils/ip.mjs +2 -1
  234. package/dist/utils/ip.mjs.map +1 -0
  235. package/dist/utils/json.d.mts +2 -1
  236. package/dist/utils/json.mjs +2 -1
  237. package/dist/utils/json.mjs.map +1 -0
  238. package/dist/utils/string.d.mts +2 -1
  239. package/dist/utils/string.mjs +2 -1
  240. package/dist/utils/string.mjs.map +1 -0
  241. package/dist/utils/url.d.mts +2 -1
  242. package/dist/utils/url.mjs +2 -1
  243. package/dist/utils/url.mjs.map +1 -0
  244. package/package.json +16 -13
  245. package/src/context/index.ts +1 -0
  246. package/src/context/transaction.ts +72 -9
  247. package/src/db/adapter/factory.ts +4 -54
  248. package/src/db/adapter/get-id-field.ts +2 -4
  249. package/src/db/adapter/types.ts +2 -41
  250. package/src/db/get-tables.ts +48 -37
  251. package/src/db/test/get-tables.test.ts +33 -0
  252. package/src/env/env-impl.ts +2 -2
  253. package/src/env/logger.ts +1 -1
  254. package/src/error/codes.ts +22 -1
  255. package/src/error/index.ts +26 -1
  256. package/src/oauth2/oauth-provider.ts +1 -1
  257. package/src/oauth2/refresh-access-token.ts +0 -2
  258. package/src/oauth2/validate-authorization-code.ts +7 -12
  259. package/src/oauth2/validate-token.test.ts +174 -0
  260. package/src/social-providers/apple.ts +14 -4
  261. package/src/social-providers/cognito.ts +1 -2
  262. package/src/social-providers/dropbox.ts +1 -1
  263. package/src/social-providers/facebook.ts +3 -3
  264. package/src/social-providers/github.ts +25 -3
  265. package/src/social-providers/google.ts +3 -4
  266. package/src/social-providers/zoom.ts +0 -8
  267. package/src/types/context.ts +94 -8
  268. package/src/types/helper.ts +8 -0
  269. package/src/types/index.ts +14 -2
  270. package/src/types/init-options.ts +83 -86
  271. package/src/types/plugin-client.ts +10 -0
  272. package/src/types/plugin.ts +9 -5
  273. package/src/utils/db.ts +20 -0
  274. package/src/utils/error-codes.ts +21 -4
  275. package/tsdown.config.ts +5 -1
  276. package/dist/utils/index.d.mts +0 -8
  277. package/dist/utils/index.mjs +0 -9
  278. package/src/utils/index.ts +0 -7
@@ -1,5 +1,4 @@
1
1
  import { defineErrorCodes } from "../utils/error-codes.mjs";
2
- import "../utils/index.mjs";
3
2
 
4
3
  //#region src/error/codes.ts
5
4
  const BASE_ERROR_CODES = defineErrorCodes({
@@ -11,9 +10,11 @@ const BASE_ERROR_CODES = defineErrorCodes({
11
10
  INVALID_PASSWORD: "Invalid password",
12
11
  INVALID_EMAIL: "Invalid email",
13
12
  INVALID_EMAIL_OR_PASSWORD: "Invalid email or password",
13
+ INVALID_USER: "Invalid user",
14
14
  SOCIAL_ACCOUNT_ALREADY_LINKED: "Social account already linked",
15
15
  PROVIDER_NOT_FOUND: "Provider not found",
16
16
  INVALID_TOKEN: "Invalid token",
17
+ TOKEN_EXPIRED: "Token expired",
17
18
  ID_TOKEN_NOT_SUPPORTED: "id_token not supported",
18
19
  FAILED_TO_GET_USER_INFO: "Failed to get user info",
19
20
  USER_EMAIL_NOT_FOUND: "User email not found",
@@ -45,8 +46,12 @@ const BASE_ERROR_CODES = defineErrorCodes({
45
46
  FIELD_NOT_ALLOWED: "Field not allowed to be set",
46
47
  ASYNC_VALIDATION_NOT_SUPPORTED: "Async validation is not supported",
47
48
  VALIDATION_ERROR: "Validation Error",
48
- MISSING_FIELD: "Field is required"
49
+ MISSING_FIELD: "Field is required",
50
+ METHOD_NOT_ALLOWED_DEFER_SESSION_REQUIRED: "POST method requires deferSessionRefresh to be enabled in session config",
51
+ BODY_MUST_BE_AN_OBJECT: "Body must be an object",
52
+ PASSWORD_ALREADY_SET: "User already has a password set"
49
53
  });
50
54
 
51
55
  //#endregion
52
- export { BASE_ERROR_CODES };
56
+ export { BASE_ERROR_CODES };
57
+ //# sourceMappingURL=codes.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codes.mjs","names":[],"sources":["../../src/error/codes.ts"],"sourcesContent":["import { defineErrorCodes } from \"../utils/error-codes\";\n\ndeclare module \"@better-auth/core\" {\n\tinterface BetterAuthPluginRegistry<AuthOptions, Options> {\n\t\t/**\n\t\t * This plugin does not exist, do not use it in runtime.\n\t\t */\n\t\t\"$internal:base\": {\n\t\t\tcreator: () => {\n\t\t\t\t$ERROR_CODES: typeof BASE_ERROR_CODES;\n\t\t\t};\n\t\t};\n\t}\n}\n\nexport const BASE_ERROR_CODES = defineErrorCodes({\n\tUSER_NOT_FOUND: \"User not found\",\n\tFAILED_TO_CREATE_USER: \"Failed to create user\",\n\tFAILED_TO_CREATE_SESSION: \"Failed to create session\",\n\tFAILED_TO_UPDATE_USER: \"Failed to update user\",\n\tFAILED_TO_GET_SESSION: \"Failed to get session\",\n\tINVALID_PASSWORD: \"Invalid password\",\n\tINVALID_EMAIL: \"Invalid email\",\n\tINVALID_EMAIL_OR_PASSWORD: \"Invalid email or password\",\n\tINVALID_USER: \"Invalid user\",\n\tSOCIAL_ACCOUNT_ALREADY_LINKED: \"Social account already linked\",\n\tPROVIDER_NOT_FOUND: \"Provider not found\",\n\tINVALID_TOKEN: \"Invalid token\",\n\tTOKEN_EXPIRED: \"Token expired\",\n\tID_TOKEN_NOT_SUPPORTED: \"id_token not supported\",\n\tFAILED_TO_GET_USER_INFO: \"Failed to get user info\",\n\tUSER_EMAIL_NOT_FOUND: \"User email not found\",\n\tEMAIL_NOT_VERIFIED: \"Email not verified\",\n\tPASSWORD_TOO_SHORT: \"Password too short\",\n\tPASSWORD_TOO_LONG: \"Password too long\",\n\tUSER_ALREADY_EXISTS: \"User already exists.\",\n\tUSER_ALREADY_EXISTS_USE_ANOTHER_EMAIL:\n\t\t\"User already exists. Use another email.\",\n\tEMAIL_CAN_NOT_BE_UPDATED: \"Email can not be updated\",\n\tCREDENTIAL_ACCOUNT_NOT_FOUND: \"Credential account not found\",\n\tSESSION_EXPIRED: \"Session expired. Re-authenticate to perform this action.\",\n\tFAILED_TO_UNLINK_LAST_ACCOUNT: \"You can't unlink your last account\",\n\tACCOUNT_NOT_FOUND: \"Account not found\",\n\tUSER_ALREADY_HAS_PASSWORD:\n\t\t\"User already has a password. Provide that to delete the account.\",\n\tCROSS_SITE_NAVIGATION_LOGIN_BLOCKED:\n\t\t\"Cross-site navigation login blocked. This request appears to be a CSRF attack.\",\n\tVERIFICATION_EMAIL_NOT_ENABLED: \"Verification email isn't enabled\",\n\tEMAIL_ALREADY_VERIFIED: \"Email is already verified\",\n\tEMAIL_MISMATCH: \"Email mismatch\",\n\tSESSION_NOT_FRESH: \"Session is not fresh\",\n\tLINKED_ACCOUNT_ALREADY_EXISTS: \"Linked account already exists\",\n\tINVALID_ORIGIN: \"Invalid origin\",\n\tINVALID_CALLBACK_URL: \"Invalid callbackURL\",\n\tINVALID_REDIRECT_URL: \"Invalid redirectURL\",\n\tINVALID_ERROR_CALLBACK_URL: \"Invalid errorCallbackURL\",\n\tINVALID_NEW_USER_CALLBACK_URL: \"Invalid newUserCallbackURL\",\n\tMISSING_OR_NULL_ORIGIN: \"Missing or null Origin\",\n\tCALLBACK_URL_REQUIRED: \"callbackURL is required\",\n\tFAILED_TO_CREATE_VERIFICATION: \"Unable to create verification\",\n\tFIELD_NOT_ALLOWED: \"Field not allowed to be set\",\n\tASYNC_VALIDATION_NOT_SUPPORTED: \"Async validation is not supported\",\n\tVALIDATION_ERROR: \"Validation Error\",\n\tMISSING_FIELD: \"Field is required\",\n\tMETHOD_NOT_ALLOWED_DEFER_SESSION_REQUIRED:\n\t\t\"POST method requires deferSessionRefresh to be enabled in session config\",\n\tBODY_MUST_BE_AN_OBJECT: \"Body must be an object\",\n\tPASSWORD_ALREADY_SET: \"User already has a password set\",\n});\n\nexport type APIErrorCode = keyof typeof BASE_ERROR_CODES;\n"],"mappings":";;;AAeA,MAAa,mBAAmB,iBAAiB;CAChD,gBAAgB;CAChB,uBAAuB;CACvB,0BAA0B;CAC1B,uBAAuB;CACvB,uBAAuB;CACvB,kBAAkB;CAClB,eAAe;CACf,2BAA2B;CAC3B,cAAc;CACd,+BAA+B;CAC/B,oBAAoB;CACpB,eAAe;CACf,eAAe;CACf,wBAAwB;CACxB,yBAAyB;CACzB,sBAAsB;CACtB,oBAAoB;CACpB,oBAAoB;CACpB,mBAAmB;CACnB,qBAAqB;CACrB,uCACC;CACD,0BAA0B;CAC1B,8BAA8B;CAC9B,iBAAiB;CACjB,+BAA+B;CAC/B,mBAAmB;CACnB,2BACC;CACD,qCACC;CACD,gCAAgC;CAChC,wBAAwB;CACxB,gBAAgB;CAChB,mBAAmB;CACnB,+BAA+B;CAC/B,gBAAgB;CAChB,sBAAsB;CACtB,sBAAsB;CACtB,4BAA4B;CAC5B,+BAA+B;CAC/B,wBAAwB;CACxB,uBAAuB;CACvB,+BAA+B;CAC/B,mBAAmB;CACnB,gCAAgC;CAChC,kBAAkB;CAClB,eAAe;CACf,2CACC;CACD,wBAAwB;CACxB,sBAAsB;CACtB,CAAC"}
@@ -1,4 +1,5 @@
1
- import { BASE_ERROR_CODES } from "./codes.mjs";
1
+ import { APIErrorCode, BASE_ERROR_CODES } from "./codes.mjs";
2
+ import { APIError as APIError$1 } from "better-call/error";
2
3
 
3
4
  //#region src/error/index.d.ts
4
5
  declare class BetterAuthError extends Error {
@@ -6,5 +7,14 @@ declare class BetterAuthError extends Error {
6
7
  cause?: unknown | undefined;
7
8
  });
8
9
  }
10
+ declare class APIError extends APIError$1 {
11
+ constructor(...args: ConstructorParameters<typeof APIError$1>);
12
+ static fromStatus(status: ConstructorParameters<typeof APIError$1>[0], body?: ConstructorParameters<typeof APIError$1>[1]): APIError;
13
+ static from(status: ConstructorParameters<typeof APIError$1>[0], error: {
14
+ code: string;
15
+ message: string;
16
+ }): APIError;
17
+ }
9
18
  //#endregion
10
- export { BASE_ERROR_CODES, BetterAuthError };
19
+ export { APIError, type APIErrorCode, BASE_ERROR_CODES, BetterAuthError };
20
+ //# sourceMappingURL=index.d.mts.map
@@ -1,4 +1,5 @@
1
1
  import { BASE_ERROR_CODES } from "./codes.mjs";
2
+ import { APIError as APIError$1 } from "better-call/error";
2
3
 
3
4
  //#region src/error/index.ts
4
5
  var BetterAuthError = class extends Error {
@@ -9,6 +10,21 @@ var BetterAuthError = class extends Error {
9
10
  this.stack = "";
10
11
  }
11
12
  };
13
+ var APIError = class APIError extends APIError$1 {
14
+ constructor(...args) {
15
+ super(...args);
16
+ }
17
+ static fromStatus(status, body) {
18
+ return new APIError(status, body);
19
+ }
20
+ static from(status, error) {
21
+ return new APIError(status, {
22
+ message: error.message,
23
+ code: error.code
24
+ });
25
+ }
26
+ };
12
27
 
13
28
  //#endregion
14
- export { BASE_ERROR_CODES, BetterAuthError };
29
+ export { APIError, BASE_ERROR_CODES, BetterAuthError };
30
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":["BaseAPIError"],"sources":["../../src/error/index.ts"],"sourcesContent":["import { APIError as BaseAPIError } from \"better-call/error\";\n\nexport class BetterAuthError extends Error {\n\tconstructor(message: string, options?: { cause?: unknown | undefined }) {\n\t\tsuper(message, options);\n\t\tthis.name = \"BetterAuthError\";\n\t\tthis.message = message;\n\t\tthis.stack = \"\";\n\t}\n}\n\nexport { type APIErrorCode, BASE_ERROR_CODES } from \"./codes\";\n\nexport class APIError extends BaseAPIError {\n\tconstructor(...args: ConstructorParameters<typeof BaseAPIError>) {\n\t\tsuper(...args);\n\t}\n\n\tstatic fromStatus(\n\t\tstatus: ConstructorParameters<typeof BaseAPIError>[0],\n\t\tbody?: ConstructorParameters<typeof BaseAPIError>[1],\n\t) {\n\t\treturn new APIError(status, body);\n\t}\n\n\tstatic from(\n\t\tstatus: ConstructorParameters<typeof BaseAPIError>[0],\n\t\terror: { code: string; message: string },\n\t) {\n\t\treturn new APIError(status, {\n\t\t\tmessage: error.message,\n\t\t\tcode: error.code,\n\t\t});\n\t}\n}\n"],"mappings":";;;;AAEA,IAAa,kBAAb,cAAqC,MAAM;CAC1C,YAAY,SAAiB,SAA2C;AACvE,QAAM,SAAS,QAAQ;AACvB,OAAK,OAAO;AACZ,OAAK,UAAU;AACf,OAAK,QAAQ;;;AAMf,IAAa,WAAb,MAAa,iBAAiBA,WAAa;CAC1C,YAAY,GAAG,MAAkD;AAChE,QAAM,GAAG,KAAK;;CAGf,OAAO,WACN,QACA,MACC;AACD,SAAO,IAAI,SAAS,QAAQ,KAAK;;CAGlC,OAAO,KACN,QACA,OACC;AACD,SAAO,IAAI,SAAS,QAAQ;GAC3B,SAAS,MAAM;GACf,MAAM,MAAM;GACZ,CAAC"}
package/dist/index.d.mts CHANGED
@@ -1,8 +1,8 @@
1
- import { Awaitable, LiteralString, LiteralUnion, Prettify, Primitive } from "./types/helper.mjs";
2
1
  import { BetterAuthCookie, BetterAuthCookies } from "./types/cookie.mjs";
3
- import { BetterAuthPlugin, HookEndpointContext } from "./types/plugin.mjs";
4
- import { BetterAuthAdvancedOptions, BetterAuthOptions, BetterAuthRateLimitOptions, GenerateIdFn } from "./types/init-options.mjs";
5
- import { AuthContext, GenericEndpointContext, InfoContext, InternalAdapter, PluginContext } from "./types/context.mjs";
2
+ import { Awaitable, LiteralString, LiteralUnion, Prettify, Primitive, UnionToIntersection } from "./types/helper.mjs";
3
+ import { BetterAuthPlugin, BetterAuthPluginErrorCodePart, HookEndpointContext } from "./types/plugin.mjs";
4
+ import { BetterAuthAdvancedOptions, BetterAuthOptions, BetterAuthRateLimitOptions, BetterAuthRateLimitRule, BetterAuthRateLimitStorage, GenerateIdFn, StoreIdentifierOption } from "./types/init-options.mjs";
5
+ import { AuthContext, BetterAuthPluginRegistry, BetterAuthPluginRegistryIdentifier, GenericEndpointContext, InfoContext, InternalAdapter, PluginContext } from "./types/context.mjs";
6
6
  import { BetterAuthClientOptions, BetterAuthClientPlugin, ClientAtomListener, ClientFetchOption, ClientStore } from "./types/plugin-client.mjs";
7
7
  import { StandardSchemaV1 } from "./types/index.mjs";
8
- export { AuthContext, Awaitable, BetterAuthAdvancedOptions, BetterAuthClientOptions, BetterAuthClientPlugin, BetterAuthCookie, BetterAuthCookies, BetterAuthOptions, BetterAuthPlugin, BetterAuthRateLimitOptions, ClientAtomListener, ClientFetchOption, ClientStore, GenerateIdFn, GenericEndpointContext, HookEndpointContext, InfoContext, InternalAdapter, LiteralString, LiteralUnion, PluginContext, Prettify, Primitive, StandardSchemaV1 };
8
+ export { AuthContext, Awaitable, BetterAuthAdvancedOptions, BetterAuthClientOptions, BetterAuthClientPlugin, BetterAuthCookie, BetterAuthCookies, BetterAuthOptions, BetterAuthPlugin, BetterAuthPluginErrorCodePart, BetterAuthPluginRegistry, BetterAuthPluginRegistryIdentifier, BetterAuthRateLimitOptions, BetterAuthRateLimitRule, BetterAuthRateLimitStorage, ClientAtomListener, ClientFetchOption, ClientStore, GenerateIdFn, GenericEndpointContext, HookEndpointContext, InfoContext, InternalAdapter, LiteralString, LiteralUnion, PluginContext, Prettify, Primitive, StandardSchemaV1, StoreIdentifierOption, UnionToIntersection };
@@ -33,4 +33,5 @@ declare function clientCredentialsToken({
33
33
  resource?: (string | string[]) | undefined;
34
34
  }): Promise<OAuth2Tokens>;
35
35
  //#endregion
36
- export { clientCredentialsToken, createClientCredentialsTokenRequest };
36
+ export { clientCredentialsToken, createClientCredentialsTokenRequest };
37
+ //# sourceMappingURL=client-credentials-token.d.mts.map
@@ -51,4 +51,5 @@ async function clientCredentialsToken({ options, tokenEndpoint, scope, authentic
51
51
  }
52
52
 
53
53
  //#endregion
54
- export { clientCredentialsToken, createClientCredentialsTokenRequest };
54
+ export { clientCredentialsToken, createClientCredentialsTokenRequest };
55
+ //# sourceMappingURL=client-credentials-token.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-credentials-token.mjs","names":[],"sources":["../../src/oauth2/client-credentials-token.ts"],"sourcesContent":["import { base64Url } from \"@better-auth/utils/base64\";\nimport { betterFetch } from \"@better-fetch/fetch\";\nimport type { OAuth2Tokens, ProviderOptions } from \"./oauth-provider\";\n\nexport function createClientCredentialsTokenRequest({\n\toptions,\n\tscope,\n\tauthentication,\n\tresource,\n}: {\n\toptions: ProviderOptions & { clientSecret: string };\n\tscope?: string | undefined;\n\tauthentication?: (\"basic\" | \"post\") | undefined;\n\tresource?: (string | string[]) | undefined;\n}) {\n\tconst body = new URLSearchParams();\n\tconst headers: Record<string, any> = {\n\t\t\"content-type\": \"application/x-www-form-urlencoded\",\n\t\taccept: \"application/json\",\n\t};\n\n\tbody.set(\"grant_type\", \"client_credentials\");\n\tscope && body.set(\"scope\", scope);\n\tif (resource) {\n\t\tif (typeof resource === \"string\") {\n\t\t\tbody.append(\"resource\", resource);\n\t\t} else {\n\t\t\tfor (const _resource of resource) {\n\t\t\t\tbody.append(\"resource\", _resource);\n\t\t\t}\n\t\t}\n\t}\n\tif (authentication === \"basic\") {\n\t\tconst primaryClientId = Array.isArray(options.clientId)\n\t\t\t? options.clientId[0]\n\t\t\t: options.clientId;\n\t\tconst encodedCredentials = base64Url.encode(\n\t\t\t`${primaryClientId}:${options.clientSecret}`,\n\t\t);\n\t\theaders[\"authorization\"] = `Basic ${encodedCredentials}`;\n\t} else {\n\t\tconst primaryClientId = Array.isArray(options.clientId)\n\t\t\t? options.clientId[0]\n\t\t\t: options.clientId;\n\t\tbody.set(\"client_id\", primaryClientId);\n\t\tbody.set(\"client_secret\", options.clientSecret);\n\t}\n\n\treturn {\n\t\tbody,\n\t\theaders,\n\t};\n}\n\nexport async function clientCredentialsToken({\n\toptions,\n\ttokenEndpoint,\n\tscope,\n\tauthentication,\n\tresource,\n}: {\n\toptions: ProviderOptions & { clientSecret: string };\n\ttokenEndpoint: string;\n\tscope: string;\n\tauthentication?: (\"basic\" | \"post\") | undefined;\n\tresource?: (string | string[]) | undefined;\n}): Promise<OAuth2Tokens> {\n\tconst { body, headers } = createClientCredentialsTokenRequest({\n\t\toptions,\n\t\tscope,\n\t\tauthentication,\n\t\tresource,\n\t});\n\n\tconst { data, error } = await betterFetch<{\n\t\taccess_token: string;\n\t\texpires_in?: number | undefined;\n\t\ttoken_type?: string | undefined;\n\t\tscope?: string | undefined;\n\t}>(tokenEndpoint, {\n\t\tmethod: \"POST\",\n\t\tbody,\n\t\theaders,\n\t});\n\tif (error) {\n\t\tthrow error;\n\t}\n\tconst tokens: OAuth2Tokens = {\n\t\taccessToken: data.access_token,\n\t\ttokenType: data.token_type,\n\t\tscopes: data.scope?.split(\" \"),\n\t};\n\n\tif (data.expires_in) {\n\t\tconst now = new Date();\n\t\ttokens.accessTokenExpiresAt = new Date(\n\t\t\tnow.getTime() + data.expires_in * 1000,\n\t\t);\n\t}\n\n\treturn tokens;\n}\n"],"mappings":";;;;AAIA,SAAgB,oCAAoC,EACnD,SACA,OACA,gBACA,YAME;CACF,MAAM,OAAO,IAAI,iBAAiB;CAClC,MAAM,UAA+B;EACpC,gBAAgB;EAChB,QAAQ;EACR;AAED,MAAK,IAAI,cAAc,qBAAqB;AAC5C,UAAS,KAAK,IAAI,SAAS,MAAM;AACjC,KAAI,SACH,KAAI,OAAO,aAAa,SACvB,MAAK,OAAO,YAAY,SAAS;KAEjC,MAAK,MAAM,aAAa,SACvB,MAAK,OAAO,YAAY,UAAU;AAIrC,KAAI,mBAAmB,SAAS;EAC/B,MAAM,kBAAkB,MAAM,QAAQ,QAAQ,SAAS,GACpD,QAAQ,SAAS,KACjB,QAAQ;AAIX,UAAQ,mBAAmB,SAHA,UAAU,OACpC,GAAG,gBAAgB,GAAG,QAAQ,eAC9B;QAEK;EACN,MAAM,kBAAkB,MAAM,QAAQ,QAAQ,SAAS,GACpD,QAAQ,SAAS,KACjB,QAAQ;AACX,OAAK,IAAI,aAAa,gBAAgB;AACtC,OAAK,IAAI,iBAAiB,QAAQ,aAAa;;AAGhD,QAAO;EACN;EACA;EACA;;AAGF,eAAsB,uBAAuB,EAC5C,SACA,eACA,OACA,gBACA,YAOyB;CACzB,MAAM,EAAE,MAAM,YAAY,oCAAoC;EAC7D;EACA;EACA;EACA;EACA,CAAC;CAEF,MAAM,EAAE,MAAM,UAAU,MAAM,YAK3B,eAAe;EACjB,QAAQ;EACR;EACA;EACA,CAAC;AACF,KAAI,MACH,OAAM;CAEP,MAAM,SAAuB;EAC5B,aAAa,KAAK;EAClB,WAAW,KAAK;EAChB,QAAQ,KAAK,OAAO,MAAM,IAAI;EAC9B;AAED,KAAI,KAAK,YAAY;EACpB,MAAM,sBAAM,IAAI,MAAM;AACtB,SAAO,uBAAuB,IAAI,KACjC,IAAI,SAAS,GAAG,KAAK,aAAa,IAClC;;AAGF,QAAO"}
@@ -42,4 +42,5 @@ declare function createAuthorizationURL({
42
42
  scopeJoiner?: string | undefined;
43
43
  }): Promise<URL>;
44
44
  //#endregion
45
- export { createAuthorizationURL };
45
+ export { createAuthorizationURL };
46
+ //# sourceMappingURL=create-authorization-url.d.mts.map
@@ -39,4 +39,5 @@ async function createAuthorizationURL({ id, options, authorizationEndpoint, stat
39
39
  }
40
40
 
41
41
  //#endregion
42
- export { createAuthorizationURL };
42
+ export { createAuthorizationURL };
43
+ //# sourceMappingURL=create-authorization-url.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-authorization-url.mjs","names":[],"sources":["../../src/oauth2/create-authorization-url.ts"],"sourcesContent":["import type { ProviderOptions } from \"./index\";\nimport { generateCodeChallenge } from \"./utils\";\n\nexport async function createAuthorizationURL({\n\tid,\n\toptions,\n\tauthorizationEndpoint,\n\tstate,\n\tcodeVerifier,\n\tscopes,\n\tclaims,\n\tredirectURI,\n\tduration,\n\tprompt,\n\taccessType,\n\tresponseType,\n\tdisplay,\n\tloginHint,\n\thd,\n\tresponseMode,\n\tadditionalParams,\n\tscopeJoiner,\n}: {\n\tid: string;\n\toptions: ProviderOptions;\n\tredirectURI: string;\n\tauthorizationEndpoint: string;\n\tstate: string;\n\tcodeVerifier?: string | undefined;\n\tscopes?: string[] | undefined;\n\tclaims?: string[] | undefined;\n\tduration?: string | undefined;\n\tprompt?: string | undefined;\n\taccessType?: string | undefined;\n\tresponseType?: string | undefined;\n\tdisplay?: string | undefined;\n\tloginHint?: string | undefined;\n\thd?: string | undefined;\n\tresponseMode?: string | undefined;\n\tadditionalParams?: Record<string, string> | undefined;\n\tscopeJoiner?: string | undefined;\n}) {\n\tconst url = new URL(options.authorizationEndpoint || authorizationEndpoint);\n\turl.searchParams.set(\"response_type\", responseType || \"code\");\n\tconst primaryClientId = Array.isArray(options.clientId)\n\t\t? options.clientId[0]\n\t\t: options.clientId;\n\turl.searchParams.set(\"client_id\", primaryClientId);\n\turl.searchParams.set(\"state\", state);\n\tif (scopes) {\n\t\turl.searchParams.set(\"scope\", scopes.join(scopeJoiner || \" \"));\n\t}\n\turl.searchParams.set(\"redirect_uri\", options.redirectURI || redirectURI);\n\tduration && url.searchParams.set(\"duration\", duration);\n\tdisplay && url.searchParams.set(\"display\", display);\n\tloginHint && url.searchParams.set(\"login_hint\", loginHint);\n\tprompt && url.searchParams.set(\"prompt\", prompt);\n\thd && url.searchParams.set(\"hd\", hd);\n\taccessType && url.searchParams.set(\"access_type\", accessType);\n\tresponseMode && url.searchParams.set(\"response_mode\", responseMode);\n\tif (codeVerifier) {\n\t\tconst codeChallenge = await generateCodeChallenge(codeVerifier);\n\t\turl.searchParams.set(\"code_challenge_method\", \"S256\");\n\t\turl.searchParams.set(\"code_challenge\", codeChallenge);\n\t}\n\tif (claims) {\n\t\tconst claimsObj = claims.reduce(\n\t\t\t(acc, claim) => {\n\t\t\t\tacc[claim] = null;\n\t\t\t\treturn acc;\n\t\t\t},\n\t\t\t{} as Record<string, null>,\n\t\t);\n\t\turl.searchParams.set(\n\t\t\t\"claims\",\n\t\t\tJSON.stringify({\n\t\t\t\tid_token: { email: null, email_verified: null, ...claimsObj },\n\t\t\t}),\n\t\t);\n\t}\n\tif (additionalParams) {\n\t\tObject.entries(additionalParams).forEach(([key, value]) => {\n\t\t\turl.searchParams.set(key, value);\n\t\t});\n\t}\n\treturn url;\n}\n"],"mappings":";;;AAGA,eAAsB,uBAAuB,EAC5C,IACA,SACA,uBACA,OACA,cACA,QACA,QACA,aACA,UACA,QACA,YACA,cACA,SACA,WACA,IACA,cACA,kBACA,eAoBE;CACF,MAAM,MAAM,IAAI,IAAI,QAAQ,yBAAyB,sBAAsB;AAC3E,KAAI,aAAa,IAAI,iBAAiB,gBAAgB,OAAO;CAC7D,MAAM,kBAAkB,MAAM,QAAQ,QAAQ,SAAS,GACpD,QAAQ,SAAS,KACjB,QAAQ;AACX,KAAI,aAAa,IAAI,aAAa,gBAAgB;AAClD,KAAI,aAAa,IAAI,SAAS,MAAM;AACpC,KAAI,OACH,KAAI,aAAa,IAAI,SAAS,OAAO,KAAK,eAAe,IAAI,CAAC;AAE/D,KAAI,aAAa,IAAI,gBAAgB,QAAQ,eAAe,YAAY;AACxE,aAAY,IAAI,aAAa,IAAI,YAAY,SAAS;AACtD,YAAW,IAAI,aAAa,IAAI,WAAW,QAAQ;AACnD,cAAa,IAAI,aAAa,IAAI,cAAc,UAAU;AAC1D,WAAU,IAAI,aAAa,IAAI,UAAU,OAAO;AAChD,OAAM,IAAI,aAAa,IAAI,MAAM,GAAG;AACpC,eAAc,IAAI,aAAa,IAAI,eAAe,WAAW;AAC7D,iBAAgB,IAAI,aAAa,IAAI,iBAAiB,aAAa;AACnE,KAAI,cAAc;EACjB,MAAM,gBAAgB,MAAM,sBAAsB,aAAa;AAC/D,MAAI,aAAa,IAAI,yBAAyB,OAAO;AACrD,MAAI,aAAa,IAAI,kBAAkB,cAAc;;AAEtD,KAAI,QAAQ;EACX,MAAM,YAAY,OAAO,QACvB,KAAK,UAAU;AACf,OAAI,SAAS;AACb,UAAO;KAER,EAAE,CACF;AACD,MAAI,aAAa,IAChB,UACA,KAAK,UAAU,EACd,UAAU;GAAE,OAAO;GAAM,gBAAgB;GAAM,GAAG;GAAW,EAC7D,CAAC,CACF;;AAEF,KAAI,iBACH,QAAO,QAAQ,iBAAiB,CAAC,SAAS,CAAC,KAAK,WAAW;AAC1D,MAAI,aAAa,IAAI,KAAK,MAAM;GAC/B;AAEH,QAAO"}
@@ -39,7 +39,7 @@ interface OAuthProvider<T extends Record<string, any> = Record<string, any>, O e
39
39
  redirectURI: string;
40
40
  codeVerifier?: string | undefined;
41
41
  deviceId?: string | undefined;
42
- }) => Promise<OAuth2Tokens>;
42
+ }) => Promise<OAuth2Tokens | null>;
43
43
  getUserInfo: (token: OAuth2Tokens & {
44
44
  /**
45
45
  * The user object from the provider
@@ -191,4 +191,5 @@ type ProviderOptions<Profile extends Record<string, any> = any> = {
191
191
  overrideUserInfoOnSignIn?: boolean | undefined;
192
192
  };
193
193
  //#endregion
194
- export { OAuth2Tokens, OAuth2UserInfo, OAuthProvider, ProviderOptions };
194
+ export { OAuth2Tokens, OAuth2UserInfo, OAuthProvider, ProviderOptions };
195
+ //# sourceMappingURL=oauth-provider.d.mts.map
@@ -29,8 +29,7 @@ declare function refreshAccessToken({
29
29
  tokenEndpoint: string;
30
30
  authentication?: ("basic" | "post") | undefined;
31
31
  extraParams?: Record<string, string> | undefined;
32
- /** @deprecated always "refresh_token" */
33
- grantType?: string | undefined;
34
32
  }): Promise<OAuth2Tokens>;
35
33
  //#endregion
36
- export { createRefreshAccessTokenRequest, refreshAccessToken };
34
+ export { createRefreshAccessTokenRequest, refreshAccessToken };
35
+ //# sourceMappingURL=refresh-access-token.d.mts.map
@@ -55,4 +55,5 @@ async function refreshAccessToken({ refreshToken, options, tokenEndpoint, authen
55
55
  }
56
56
 
57
57
  //#endregion
58
- export { createRefreshAccessTokenRequest, refreshAccessToken };
58
+ export { createRefreshAccessTokenRequest, refreshAccessToken };
59
+ //# sourceMappingURL=refresh-access-token.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refresh-access-token.mjs","names":[],"sources":["../../src/oauth2/refresh-access-token.ts"],"sourcesContent":["import { base64 } from \"@better-auth/utils/base64\";\nimport { betterFetch } from \"@better-fetch/fetch\";\nimport type { OAuth2Tokens, ProviderOptions } from \"./oauth-provider\";\n\nexport function createRefreshAccessTokenRequest({\n\trefreshToken,\n\toptions,\n\tauthentication,\n\textraParams,\n\tresource,\n}: {\n\trefreshToken: string;\n\toptions: Partial<ProviderOptions>;\n\tauthentication?: (\"basic\" | \"post\") | undefined;\n\textraParams?: Record<string, string> | undefined;\n\tresource?: (string | string[]) | undefined;\n}) {\n\tconst body = new URLSearchParams();\n\tconst headers: Record<string, any> = {\n\t\t\"content-type\": \"application/x-www-form-urlencoded\",\n\t\taccept: \"application/json\",\n\t};\n\n\tbody.set(\"grant_type\", \"refresh_token\");\n\tbody.set(\"refresh_token\", refreshToken);\n\t// Use standard Base64 encoding for HTTP Basic Auth (OAuth2 spec, RFC 7617)\n\t// Fixes compatibility with providers like Notion, Twitter, etc.\n\tif (authentication === \"basic\") {\n\t\tconst primaryClientId = Array.isArray(options.clientId)\n\t\t\t? options.clientId[0]\n\t\t\t: options.clientId;\n\t\tif (primaryClientId) {\n\t\t\theaders[\"authorization\"] =\n\t\t\t\t\"Basic \" +\n\t\t\t\tbase64.encode(`${primaryClientId}:${options.clientSecret ?? \"\"}`);\n\t\t} else {\n\t\t\theaders[\"authorization\"] =\n\t\t\t\t\"Basic \" + base64.encode(`:${options.clientSecret ?? \"\"}`);\n\t\t}\n\t} else {\n\t\tconst primaryClientId = Array.isArray(options.clientId)\n\t\t\t? options.clientId[0]\n\t\t\t: options.clientId;\n\t\tbody.set(\"client_id\", primaryClientId);\n\t\tif (options.clientSecret) {\n\t\t\tbody.set(\"client_secret\", options.clientSecret);\n\t\t}\n\t}\n\n\tif (resource) {\n\t\tif (typeof resource === \"string\") {\n\t\t\tbody.append(\"resource\", resource);\n\t\t} else {\n\t\t\tfor (const _resource of resource) {\n\t\t\t\tbody.append(\"resource\", _resource);\n\t\t\t}\n\t\t}\n\t}\n\tif (extraParams) {\n\t\tfor (const [key, value] of Object.entries(extraParams)) {\n\t\t\tbody.set(key, value);\n\t\t}\n\t}\n\n\treturn {\n\t\tbody,\n\t\theaders,\n\t};\n}\n\nexport async function refreshAccessToken({\n\trefreshToken,\n\toptions,\n\ttokenEndpoint,\n\tauthentication,\n\textraParams,\n}: {\n\trefreshToken: string;\n\toptions: Partial<ProviderOptions>;\n\ttokenEndpoint: string;\n\tauthentication?: (\"basic\" | \"post\") | undefined;\n\textraParams?: Record<string, string> | undefined;\n}): Promise<OAuth2Tokens> {\n\tconst { body, headers } = createRefreshAccessTokenRequest({\n\t\trefreshToken,\n\t\toptions,\n\t\tauthentication,\n\t\textraParams,\n\t});\n\n\tconst { data, error } = await betterFetch<{\n\t\taccess_token: string;\n\t\trefresh_token?: string | undefined;\n\t\texpires_in?: number | undefined;\n\t\ttoken_type?: string | undefined;\n\t\tscope?: string | undefined;\n\t\tid_token?: string | undefined;\n\t}>(tokenEndpoint, {\n\t\tmethod: \"POST\",\n\t\tbody,\n\t\theaders,\n\t});\n\tif (error) {\n\t\tthrow error;\n\t}\n\tconst tokens: OAuth2Tokens = {\n\t\taccessToken: data.access_token,\n\t\trefreshToken: data.refresh_token,\n\t\ttokenType: data.token_type,\n\t\tscopes: data.scope?.split(\" \"),\n\t\tidToken: data.id_token,\n\t};\n\n\tif (data.expires_in) {\n\t\tconst now = new Date();\n\t\ttokens.accessTokenExpiresAt = new Date(\n\t\t\tnow.getTime() + data.expires_in * 1000,\n\t\t);\n\t}\n\n\treturn tokens;\n}\n"],"mappings":";;;;AAIA,SAAgB,gCAAgC,EAC/C,cACA,SACA,gBACA,aACA,YAOE;CACF,MAAM,OAAO,IAAI,iBAAiB;CAClC,MAAM,UAA+B;EACpC,gBAAgB;EAChB,QAAQ;EACR;AAED,MAAK,IAAI,cAAc,gBAAgB;AACvC,MAAK,IAAI,iBAAiB,aAAa;AAGvC,KAAI,mBAAmB,SAAS;EAC/B,MAAM,kBAAkB,MAAM,QAAQ,QAAQ,SAAS,GACpD,QAAQ,SAAS,KACjB,QAAQ;AACX,MAAI,gBACH,SAAQ,mBACP,WACA,OAAO,OAAO,GAAG,gBAAgB,GAAG,QAAQ,gBAAgB,KAAK;MAElE,SAAQ,mBACP,WAAW,OAAO,OAAO,IAAI,QAAQ,gBAAgB,KAAK;QAEtD;EACN,MAAM,kBAAkB,MAAM,QAAQ,QAAQ,SAAS,GACpD,QAAQ,SAAS,KACjB,QAAQ;AACX,OAAK,IAAI,aAAa,gBAAgB;AACtC,MAAI,QAAQ,aACX,MAAK,IAAI,iBAAiB,QAAQ,aAAa;;AAIjD,KAAI,SACH,KAAI,OAAO,aAAa,SACvB,MAAK,OAAO,YAAY,SAAS;KAEjC,MAAK,MAAM,aAAa,SACvB,MAAK,OAAO,YAAY,UAAU;AAIrC,KAAI,YACH,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,YAAY,CACrD,MAAK,IAAI,KAAK,MAAM;AAItB,QAAO;EACN;EACA;EACA;;AAGF,eAAsB,mBAAmB,EACxC,cACA,SACA,eACA,gBACA,eAOyB;CACzB,MAAM,EAAE,MAAM,YAAY,gCAAgC;EACzD;EACA;EACA;EACA;EACA,CAAC;CAEF,MAAM,EAAE,MAAM,UAAU,MAAM,YAO3B,eAAe;EACjB,QAAQ;EACR;EACA;EACA,CAAC;AACF,KAAI,MACH,OAAM;CAEP,MAAM,SAAuB;EAC5B,aAAa,KAAK;EAClB,cAAc,KAAK;EACnB,WAAW,KAAK;EAChB,QAAQ,KAAK,OAAO,MAAM,IAAI;EAC9B,SAAS,KAAK;EACd;AAED,KAAI,KAAK,YAAY;EACpB,MAAM,sBAAM,IAAI,MAAM;AACtB,SAAO,uBAAuB,IAAI,KACjC,IAAI,SAAS,GAAG,KAAK,aAAa,IAClC;;AAGF,QAAO"}
@@ -4,4 +4,5 @@ import { OAuth2Tokens } from "./oauth-provider.mjs";
4
4
  declare function getOAuth2Tokens(data: Record<string, any>): OAuth2Tokens;
5
5
  declare function generateCodeChallenge(codeVerifier: string): Promise<string>;
6
6
  //#endregion
7
- export { generateCodeChallenge, getOAuth2Tokens };
7
+ export { generateCodeChallenge, getOAuth2Tokens };
8
+ //# sourceMappingURL=utils.d.mts.map
@@ -24,4 +24,5 @@ async function generateCodeChallenge(codeVerifier) {
24
24
  }
25
25
 
26
26
  //#endregion
27
- export { generateCodeChallenge, getOAuth2Tokens };
27
+ export { generateCodeChallenge, getOAuth2Tokens };
28
+ //# sourceMappingURL=utils.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.mjs","names":[],"sources":["../../src/oauth2/utils.ts"],"sourcesContent":["import { base64Url } from \"@better-auth/utils/base64\";\nimport type { OAuth2Tokens } from \"./oauth-provider\";\n\nexport function getOAuth2Tokens(data: Record<string, any>): OAuth2Tokens {\n\tconst getDate = (seconds: number) => {\n\t\tconst now = new Date();\n\t\treturn new Date(now.getTime() + seconds * 1000);\n\t};\n\n\treturn {\n\t\ttokenType: data.token_type,\n\t\taccessToken: data.access_token,\n\t\trefreshToken: data.refresh_token,\n\t\taccessTokenExpiresAt: data.expires_in\n\t\t\t? getDate(data.expires_in)\n\t\t\t: undefined,\n\t\trefreshTokenExpiresAt: data.refresh_token_expires_in\n\t\t\t? getDate(data.refresh_token_expires_in)\n\t\t\t: undefined,\n\t\tscopes: data?.scope\n\t\t\t? typeof data.scope === \"string\"\n\t\t\t\t? data.scope.split(\" \")\n\t\t\t\t: data.scope\n\t\t\t: [],\n\t\tidToken: data.id_token,\n\t\t// Preserve the raw token response for provider-specific fields\n\t\traw: data,\n\t};\n}\n\nexport async function generateCodeChallenge(codeVerifier: string) {\n\tconst encoder = new TextEncoder();\n\tconst data = encoder.encode(codeVerifier);\n\tconst hash = await crypto.subtle.digest(\"SHA-256\", data);\n\treturn base64Url.encode(new Uint8Array(hash), {\n\t\tpadding: false,\n\t});\n}\n"],"mappings":";;;AAGA,SAAgB,gBAAgB,MAAyC;CACxE,MAAM,WAAW,YAAoB;EACpC,MAAM,sBAAM,IAAI,MAAM;AACtB,SAAO,IAAI,KAAK,IAAI,SAAS,GAAG,UAAU,IAAK;;AAGhD,QAAO;EACN,WAAW,KAAK;EAChB,aAAa,KAAK;EAClB,cAAc,KAAK;EACnB,sBAAsB,KAAK,aACxB,QAAQ,KAAK,WAAW,GACxB;EACH,uBAAuB,KAAK,2BACzB,QAAQ,KAAK,yBAAyB,GACtC;EACH,QAAQ,MAAM,QACX,OAAO,KAAK,UAAU,WACrB,KAAK,MAAM,MAAM,IAAI,GACrB,KAAK,QACN,EAAE;EACL,SAAS,KAAK;EAEd,KAAK;EACL;;AAGF,eAAsB,sBAAsB,cAAsB;CAEjE,MAAM,OADU,IAAI,aAAa,CACZ,OAAO,aAAa;CACzC,MAAM,OAAO,MAAM,OAAO,OAAO,OAAO,WAAW,KAAK;AACxD,QAAO,UAAU,OAAO,IAAI,WAAW,KAAK,EAAE,EAC7C,SAAS,OACT,CAAC"}
@@ -52,4 +52,5 @@ declare function validateAuthorizationCode({
52
52
  }): Promise<OAuth2Tokens>;
53
53
  declare function validateToken(token: string, jwksEndpoint: string): Promise<jose0.JWTVerifyResult<jose0.JWTPayload>>;
54
54
  //#endregion
55
- export { createAuthorizationCodeRequest, validateAuthorizationCode, validateToken };
55
+ export { createAuthorizationCodeRequest, validateAuthorizationCode, validateToken };
56
+ //# sourceMappingURL=validate-authorization-code.d.mts.map
@@ -2,7 +2,7 @@ import { getOAuth2Tokens } from "./utils.mjs";
2
2
  import "./index.mjs";
3
3
  import { base64 } from "@better-auth/utils/base64";
4
4
  import { betterFetch } from "@better-fetch/fetch";
5
- import { jwtVerify } from "jose";
5
+ import { decodeProtectedHeader, importJWK, jwtVerify } from "jose";
6
6
 
7
7
  //#region src/oauth2/validate-authorization-code.ts
8
8
  function createAuthorizationCodeRequest({ code, codeVerifier, redirectURI, options, authentication, deviceId, headers, additionalParams = {}, resource }) {
@@ -61,11 +61,12 @@ async function validateToken(token, jwksEndpoint) {
61
61
  });
62
62
  if (error) throw error;
63
63
  const keys = data["keys"];
64
- const header = JSON.parse(atob(token.split(".")[0]));
65
- const key = keys.find((key$1) => key$1.kid === header.kid);
64
+ const header = decodeProtectedHeader(token);
65
+ const key = keys.find((k) => k.kid === header.kid);
66
66
  if (!key) throw new Error("Key not found");
67
- return await jwtVerify(token, key);
67
+ return await jwtVerify(token, await importJWK(key, header.alg));
68
68
  }
69
69
 
70
70
  //#endregion
71
- export { createAuthorizationCodeRequest, validateAuthorizationCode, validateToken };
71
+ export { createAuthorizationCodeRequest, validateAuthorizationCode, validateToken };
72
+ //# sourceMappingURL=validate-authorization-code.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-authorization-code.mjs","names":[],"sources":["../../src/oauth2/validate-authorization-code.ts"],"sourcesContent":["import { base64 } from \"@better-auth/utils/base64\";\nimport { betterFetch } from \"@better-fetch/fetch\";\nimport type { JWK } from \"jose\";\nimport { decodeProtectedHeader, importJWK, jwtVerify } from \"jose\";\nimport type { ProviderOptions } from \"./index\";\nimport { getOAuth2Tokens } from \"./index\";\n\nexport function createAuthorizationCodeRequest({\n\tcode,\n\tcodeVerifier,\n\tredirectURI,\n\toptions,\n\tauthentication,\n\tdeviceId,\n\theaders,\n\tadditionalParams = {},\n\tresource,\n}: {\n\tcode: string;\n\tredirectURI: string;\n\toptions: Partial<ProviderOptions>;\n\tcodeVerifier?: string | undefined;\n\tdeviceId?: string | undefined;\n\tauthentication?: (\"basic\" | \"post\") | undefined;\n\theaders?: Record<string, string> | undefined;\n\tadditionalParams?: Record<string, string> | undefined;\n\tresource?: (string | string[]) | undefined;\n}) {\n\tconst body = new URLSearchParams();\n\tconst requestHeaders: Record<string, any> = {\n\t\t\"content-type\": \"application/x-www-form-urlencoded\",\n\t\taccept: \"application/json\",\n\t\t...headers,\n\t};\n\tbody.set(\"grant_type\", \"authorization_code\");\n\tbody.set(\"code\", code);\n\tcodeVerifier && body.set(\"code_verifier\", codeVerifier);\n\toptions.clientKey && body.set(\"client_key\", options.clientKey);\n\tdeviceId && body.set(\"device_id\", deviceId);\n\tbody.set(\"redirect_uri\", options.redirectURI || redirectURI);\n\tif (resource) {\n\t\tif (typeof resource === \"string\") {\n\t\t\tbody.append(\"resource\", resource);\n\t\t} else {\n\t\t\tfor (const _resource of resource) {\n\t\t\t\tbody.append(\"resource\", _resource);\n\t\t\t}\n\t\t}\n\t}\n\t// Use standard Base64 encoding for HTTP Basic Auth (OAuth2 spec, RFC 7617)\n\t// Fixes compatibility with providers like Notion, Twitter, etc.\n\tif (authentication === \"basic\") {\n\t\tconst primaryClientId = Array.isArray(options.clientId)\n\t\t\t? options.clientId[0]\n\t\t\t: options.clientId;\n\t\tconst encodedCredentials = base64.encode(\n\t\t\t`${primaryClientId}:${options.clientSecret ?? \"\"}`,\n\t\t);\n\t\trequestHeaders[\"authorization\"] = `Basic ${encodedCredentials}`;\n\t} else {\n\t\tconst primaryClientId = Array.isArray(options.clientId)\n\t\t\t? options.clientId[0]\n\t\t\t: options.clientId;\n\t\tbody.set(\"client_id\", primaryClientId);\n\t\tif (options.clientSecret) {\n\t\t\tbody.set(\"client_secret\", options.clientSecret);\n\t\t}\n\t}\n\n\tfor (const [key, value] of Object.entries(additionalParams)) {\n\t\tif (!body.has(key)) body.append(key, value);\n\t}\n\n\treturn {\n\t\tbody,\n\t\theaders: requestHeaders,\n\t};\n}\n\nexport async function validateAuthorizationCode({\n\tcode,\n\tcodeVerifier,\n\tredirectURI,\n\toptions,\n\ttokenEndpoint,\n\tauthentication,\n\tdeviceId,\n\theaders,\n\tadditionalParams = {},\n\tresource,\n}: {\n\tcode: string;\n\tredirectURI: string;\n\toptions: Partial<ProviderOptions>;\n\tcodeVerifier?: string | undefined;\n\tdeviceId?: string | undefined;\n\ttokenEndpoint: string;\n\tauthentication?: (\"basic\" | \"post\") | undefined;\n\theaders?: Record<string, string> | undefined;\n\tadditionalParams?: Record<string, string> | undefined;\n\tresource?: (string | string[]) | undefined;\n}) {\n\tconst { body, headers: requestHeaders } = createAuthorizationCodeRequest({\n\t\tcode,\n\t\tcodeVerifier,\n\t\tredirectURI,\n\t\toptions,\n\t\tauthentication,\n\t\tdeviceId,\n\t\theaders,\n\t\tadditionalParams,\n\t\tresource,\n\t});\n\n\tconst { data, error } = await betterFetch<object>(tokenEndpoint, {\n\t\tmethod: \"POST\",\n\t\tbody: body,\n\t\theaders: requestHeaders,\n\t});\n\n\tif (error) {\n\t\tthrow error;\n\t}\n\tconst tokens = getOAuth2Tokens(data);\n\treturn tokens;\n}\n\nexport async function validateToken(token: string, jwksEndpoint: string) {\n\tconst { data, error } = await betterFetch<{\n\t\tkeys: JWK[];\n\t}>(jwksEndpoint, {\n\t\tmethod: \"GET\",\n\t\theaders: {\n\t\t\taccept: \"application/json\",\n\t\t},\n\t});\n\tif (error) {\n\t\tthrow error;\n\t}\n\tconst keys = data[\"keys\"];\n\tconst header = decodeProtectedHeader(token);\n\tconst key = keys.find((k) => k.kid === header.kid);\n\tif (!key) {\n\t\tthrow new Error(\"Key not found\");\n\t}\n\tconst cryptoKey = await importJWK(key, header.alg);\n\tconst verified = await jwtVerify(token, cryptoKey);\n\treturn verified;\n}\n"],"mappings":";;;;;;;AAOA,SAAgB,+BAA+B,EAC9C,MACA,cACA,aACA,SACA,gBACA,UACA,SACA,mBAAmB,EAAE,EACrB,YAWE;CACF,MAAM,OAAO,IAAI,iBAAiB;CAClC,MAAM,iBAAsC;EAC3C,gBAAgB;EAChB,QAAQ;EACR,GAAG;EACH;AACD,MAAK,IAAI,cAAc,qBAAqB;AAC5C,MAAK,IAAI,QAAQ,KAAK;AACtB,iBAAgB,KAAK,IAAI,iBAAiB,aAAa;AACvD,SAAQ,aAAa,KAAK,IAAI,cAAc,QAAQ,UAAU;AAC9D,aAAY,KAAK,IAAI,aAAa,SAAS;AAC3C,MAAK,IAAI,gBAAgB,QAAQ,eAAe,YAAY;AAC5D,KAAI,SACH,KAAI,OAAO,aAAa,SACvB,MAAK,OAAO,YAAY,SAAS;KAEjC,MAAK,MAAM,aAAa,SACvB,MAAK,OAAO,YAAY,UAAU;AAMrC,KAAI,mBAAmB,SAAS;EAC/B,MAAM,kBAAkB,MAAM,QAAQ,QAAQ,SAAS,GACpD,QAAQ,SAAS,KACjB,QAAQ;AAIX,iBAAe,mBAAmB,SAHP,OAAO,OACjC,GAAG,gBAAgB,GAAG,QAAQ,gBAAgB,KAC9C;QAEK;EACN,MAAM,kBAAkB,MAAM,QAAQ,QAAQ,SAAS,GACpD,QAAQ,SAAS,KACjB,QAAQ;AACX,OAAK,IAAI,aAAa,gBAAgB;AACtC,MAAI,QAAQ,aACX,MAAK,IAAI,iBAAiB,QAAQ,aAAa;;AAIjD,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,iBAAiB,CAC1D,KAAI,CAAC,KAAK,IAAI,IAAI,CAAE,MAAK,OAAO,KAAK,MAAM;AAG5C,QAAO;EACN;EACA,SAAS;EACT;;AAGF,eAAsB,0BAA0B,EAC/C,MACA,cACA,aACA,SACA,eACA,gBACA,UACA,SACA,mBAAmB,EAAE,EACrB,YAYE;CACF,MAAM,EAAE,MAAM,SAAS,mBAAmB,+BAA+B;EACxE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,CAAC;CAEF,MAAM,EAAE,MAAM,UAAU,MAAM,YAAoB,eAAe;EAChE,QAAQ;EACF;EACN,SAAS;EACT,CAAC;AAEF,KAAI,MACH,OAAM;AAGP,QADe,gBAAgB,KAAK;;AAIrC,eAAsB,cAAc,OAAe,cAAsB;CACxE,MAAM,EAAE,MAAM,UAAU,MAAM,YAE3B,cAAc;EAChB,QAAQ;EACR,SAAS,EACR,QAAQ,oBACR;EACD,CAAC;AACF,KAAI,MACH,OAAM;CAEP,MAAM,OAAO,KAAK;CAClB,MAAM,SAAS,sBAAsB,MAAM;CAC3C,MAAM,MAAM,KAAK,MAAM,MAAM,EAAE,QAAQ,OAAO,IAAI;AAClD,KAAI,CAAC,IACJ,OAAM,IAAI,MAAM,gBAAgB;AAIjC,QADiB,MAAM,UAAU,OADf,MAAM,UAAU,KAAK,OAAO,IAAI,CACA"}
@@ -21,14 +21,11 @@ interface VerifyAccessTokenRemote {
21
21
  * Can also be configured for remote verification.
22
22
  */
23
23
  declare function verifyJwsAccessToken(token: string, opts: {
24
- /** Jwks url or promise of a Jwks */
25
- jwksFetch: string | (() => Promise<JSONWebKeySet | undefined>);
26
- /** Verify options */
24
+ /** Jwks url or promise of a Jwks */jwksFetch: string | (() => Promise<JSONWebKeySet | undefined>); /** Verify options */
27
25
  verifyOptions: JWTVerifyOptions & Required<Pick<JWTVerifyOptions, "audience" | "issuer">>;
28
26
  }): Promise<JWTPayload>;
29
27
  declare function getJwks(token: string, opts: {
30
- /** Jwks url or promise of a Jwks */
31
- jwksFetch: string | (() => Promise<JSONWebKeySet | undefined>);
28
+ /** Jwks url or promise of a Jwks */jwksFetch: string | (() => Promise<JSONWebKeySet | undefined>);
32
29
  }): Promise<JSONWebKeySet>;
33
30
  /**
34
31
  * Performs local verification of an access token for your API.
@@ -36,14 +33,11 @@ declare function getJwks(token: string, opts: {
36
33
  * Can also be configured for remote verification.
37
34
  */
38
35
  declare function verifyAccessToken(token: string, opts: {
39
- /** Verify options */
40
- verifyOptions: JWTVerifyOptions & Required<Pick<JWTVerifyOptions, "audience" | "issuer">>;
41
- /** Scopes to additionally verify. Token must include all but not exact. */
42
- scopes?: string[];
43
- /** Required to verify access token locally */
44
- jwksUrl?: string;
45
- /** If provided, can verify a token remotely */
36
+ /** Verify options */verifyOptions: JWTVerifyOptions & Required<Pick<JWTVerifyOptions, "audience" | "issuer">>; /** Scopes to additionally verify. Token must include all but not exact. */
37
+ scopes?: string[]; /** Required to verify access token locally */
38
+ jwksUrl?: string; /** If provided, can verify a token remotely */
46
39
  remoteVerify?: VerifyAccessTokenRemote;
47
40
  }): Promise<JWTPayload>;
48
41
  //#endregion
49
- export { getJwks, verifyAccessToken, verifyJwsAccessToken };
42
+ export { getJwks, verifyAccessToken, verifyJwsAccessToken };
43
+ //# sourceMappingURL=verify.d.mts.map
@@ -1,8 +1,8 @@
1
1
  import { logger } from "../env/logger.mjs";
2
2
  import "../env/index.mjs";
3
+ import { APIError } from "better-call";
3
4
  import { betterFetch } from "@better-fetch/fetch";
4
5
  import { UnsecuredJWT, createLocalJWKSet, decodeProtectedHeader, jwtVerify } from "jose";
5
- import { APIError } from "better-call";
6
6
 
7
7
  //#region src/oauth2/verify.ts
8
8
  /** Last fetched jwks used locally in getJwks @internal */
@@ -92,4 +92,5 @@ async function verifyAccessToken(token, opts) {
92
92
  }
93
93
 
94
94
  //#endregion
95
- export { getJwks, verifyAccessToken, verifyJwsAccessToken };
95
+ export { getJwks, verifyAccessToken, verifyJwsAccessToken };
96
+ //# sourceMappingURL=verify.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.mjs","names":[],"sources":["../../src/oauth2/verify.ts"],"sourcesContent":["import { betterFetch } from \"@better-fetch/fetch\";\nimport { APIError } from \"better-call\";\nimport type {\n\tJSONWebKeySet,\n\tJWTPayload,\n\tJWTVerifyOptions,\n\tProtectedHeaderParameters,\n} from \"jose\";\nimport {\n\tcreateLocalJWKSet,\n\tdecodeProtectedHeader,\n\tjwtVerify,\n\tUnsecuredJWT,\n} from \"jose\";\nimport { logger } from \"../env\";\n\n/** Last fetched jwks used locally in getJwks @internal */\nlet jwks: JSONWebKeySet | undefined;\n\nexport interface VerifyAccessTokenRemote {\n\t/** Full url of the introspect endpoint. Should end with `/oauth2/introspect` */\n\tintrospectUrl: string;\n\t/** Client Secret */\n\tclientId: string;\n\t/** Client Secret */\n\tclientSecret: string;\n\t/**\n\t * Forces remote verification of a token.\n\t * This ensures attached session (if applicable)\n\t * is also still active.\n\t */\n\tforce?: boolean;\n}\n\n/**\n * Performs local verification of an access token for your APIs.\n *\n * Can also be configured for remote verification.\n */\nexport async function verifyJwsAccessToken(\n\ttoken: string,\n\topts: {\n\t\t/** Jwks url or promise of a Jwks */\n\t\tjwksFetch: string | (() => Promise<JSONWebKeySet | undefined>);\n\t\t/** Verify options */\n\t\tverifyOptions: JWTVerifyOptions &\n\t\t\tRequired<Pick<JWTVerifyOptions, \"audience\" | \"issuer\">>;\n\t},\n) {\n\ttry {\n\t\tconst jwks = await getJwks(token, opts);\n\t\tconst jwt = await jwtVerify<JWTPayload>(\n\t\t\ttoken,\n\t\t\tcreateLocalJWKSet(jwks),\n\t\t\topts.verifyOptions,\n\t\t);\n\t\t// Return the JWT payload in introspection format\n\t\t// https://datatracker.ietf.org/doc/html/rfc7662#section-2.2\n\t\tif (jwt.payload.azp) {\n\t\t\tjwt.payload.client_id = jwt.payload.azp;\n\t\t}\n\t\treturn jwt.payload;\n\t} catch (error) {\n\t\tif (error instanceof Error) throw error;\n\t\tthrow new Error(error as unknown as string);\n\t}\n}\n\nexport async function getJwks(\n\ttoken: string,\n\topts: {\n\t\t/** Jwks url or promise of a Jwks */\n\t\tjwksFetch: string | (() => Promise<JSONWebKeySet | undefined>);\n\t},\n) {\n\t// Attempt to decode the token and find a matching kid in jwks\n\tlet jwtHeaders: ProtectedHeaderParameters | undefined;\n\ttry {\n\t\tjwtHeaders = decodeProtectedHeader(token);\n\t} catch (error) {\n\t\tif (error instanceof Error) throw error;\n\t\tthrow new Error(error as unknown as string);\n\t}\n\n\tif (!jwtHeaders.kid) throw new Error(\"Missing jwt kid\");\n\n\t// Fetch jwks if not set or has a different kid than the one stored\n\tif (!jwks || !jwks.keys.find((jwk) => jwk.kid === jwtHeaders.kid)) {\n\t\tjwks =\n\t\t\ttypeof opts.jwksFetch === \"string\"\n\t\t\t\t? await betterFetch<JSONWebKeySet>(opts.jwksFetch, {\n\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\tAccept: \"application/json\",\n\t\t\t\t\t\t},\n\t\t\t\t\t}).then(async (res) => {\n\t\t\t\t\t\tif (res.error)\n\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t`Jwks failed: ${res.error.message ?? res.error.statusText}`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\treturn res.data;\n\t\t\t\t\t})\n\t\t\t\t: await opts.jwksFetch();\n\t\tif (!jwks) throw new Error(\"No jwks found\");\n\t}\n\n\treturn jwks;\n}\n\n/**\n * Performs local verification of an access token for your API.\n *\n * Can also be configured for remote verification.\n */\nexport async function verifyAccessToken(\n\ttoken: string,\n\topts: {\n\t\t/** Verify options */\n\t\tverifyOptions: JWTVerifyOptions &\n\t\t\tRequired<Pick<JWTVerifyOptions, \"audience\" | \"issuer\">>;\n\t\t/** Scopes to additionally verify. Token must include all but not exact. */\n\t\tscopes?: string[];\n\t\t/** Required to verify access token locally */\n\t\tjwksUrl?: string;\n\t\t/** If provided, can verify a token remotely */\n\t\tremoteVerify?: VerifyAccessTokenRemote;\n\t},\n) {\n\tlet payload: JWTPayload | undefined;\n\t// Locally verify\n\tif (opts.jwksUrl && !opts?.remoteVerify?.force) {\n\t\ttry {\n\t\t\tpayload = await verifyJwsAccessToken(token, {\n\t\t\t\tjwksFetch: opts.jwksUrl,\n\t\t\t\tverifyOptions: opts.verifyOptions,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error) {\n\t\t\t\tif (error.name === \"TypeError\" || error.name === \"JWSInvalid\") {\n\t\t\t\t\t// likely an opaque token (continue)\n\t\t\t\t} else if (error.name === \"JWTExpired\") {\n\t\t\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\t\t\tmessage: \"token expired\",\n\t\t\t\t\t});\n\t\t\t\t} else if (error.name === \"JWTInvalid\") {\n\t\t\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\t\t\tmessage: \"token invalid\",\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthrow new Error(error as unknown as string);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Remote verify\n\tif (opts?.remoteVerify) {\n\t\tconst { data: introspect, error: introspectError } = await betterFetch<\n\t\t\tJWTPayload & {\n\t\t\t\tactive: boolean;\n\t\t\t}\n\t\t>(opts.remoteVerify.introspectUrl, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\tAccept: \"application/json\",\n\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t},\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tclient_id: opts.remoteVerify.clientId,\n\t\t\t\tclient_secret: opts.remoteVerify.clientSecret,\n\t\t\t\ttoken,\n\t\t\t\ttoken_type_hint: \"access_token\",\n\t\t\t}).toString(),\n\t\t});\n\t\tif (introspectError)\n\t\t\tlogger.error(\n\t\t\t\t`Introspection failed: ${introspectError.message ?? introspectError.statusText}`,\n\t\t\t);\n\t\tif (!introspect)\n\t\t\tthrow new APIError(\"INTERNAL_SERVER_ERROR\", {\n\t\t\t\tmessage: \"introspection failed\",\n\t\t\t});\n\t\tif (!introspect.active)\n\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\tmessage: \"token inactive\",\n\t\t\t});\n\t\t// Verifies payload using verify options (token valid through introspect)\n\t\ttry {\n\t\t\tconst unsecuredJwt = new UnsecuredJWT(introspect).encode();\n\t\t\tconst { audience: _audience, ...verifyOptions } = opts.verifyOptions;\n\t\t\tconst verify = introspect.aud\n\t\t\t\t? UnsecuredJWT.decode(unsecuredJwt, opts.verifyOptions)\n\t\t\t\t: UnsecuredJWT.decode(unsecuredJwt, verifyOptions);\n\t\t\tpayload = verify.payload;\n\t\t} catch (error) {\n\t\t\tthrow new Error(error as unknown as string);\n\t\t}\n\t}\n\n\tif (!payload)\n\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\tmessage: `no token payload`,\n\t\t});\n\n\t// Check scopes if provided\n\tif (opts.scopes) {\n\t\tconst validScopes = new Set(\n\t\t\t(payload.scope as string | undefined)?.split(\" \"),\n\t\t);\n\t\tfor (const sc of opts.scopes) {\n\t\t\tif (!validScopes.has(sc)) {\n\t\t\t\tthrow new APIError(\"FORBIDDEN\", {\n\t\t\t\t\tmessage: `invalid scope ${sc}`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn payload;\n}\n"],"mappings":";;;;;;;;AAiBA,IAAI;;;;;;AAsBJ,eAAsB,qBACrB,OACA,MAOC;AACD,KAAI;EAEH,MAAM,MAAM,MAAM,UACjB,OACA,kBAHY,MAAM,QAAQ,OAAO,KAAK,CAGf,EACvB,KAAK,cACL;AAGD,MAAI,IAAI,QAAQ,IACf,KAAI,QAAQ,YAAY,IAAI,QAAQ;AAErC,SAAO,IAAI;UACH,OAAO;AACf,MAAI,iBAAiB,MAAO,OAAM;AAClC,QAAM,IAAI,MAAM,MAA2B;;;AAI7C,eAAsB,QACrB,OACA,MAIC;CAED,IAAI;AACJ,KAAI;AACH,eAAa,sBAAsB,MAAM;UACjC,OAAO;AACf,MAAI,iBAAiB,MAAO,OAAM;AAClC,QAAM,IAAI,MAAM,MAA2B;;AAG5C,KAAI,CAAC,WAAW,IAAK,OAAM,IAAI,MAAM,kBAAkB;AAGvD,KAAI,CAAC,QAAQ,CAAC,KAAK,KAAK,MAAM,QAAQ,IAAI,QAAQ,WAAW,IAAI,EAAE;AAClE,SACC,OAAO,KAAK,cAAc,WACvB,MAAM,YAA2B,KAAK,WAAW,EACjD,SAAS,EACR,QAAQ,oBACR,EACD,CAAC,CAAC,KAAK,OAAO,QAAQ;AACtB,OAAI,IAAI,MACP,OAAM,IAAI,MACT,gBAAgB,IAAI,MAAM,WAAW,IAAI,MAAM,aAC/C;AACF,UAAO,IAAI;IACV,GACD,MAAM,KAAK,WAAW;AAC1B,MAAI,CAAC,KAAM,OAAM,IAAI,MAAM,gBAAgB;;AAG5C,QAAO;;;;;;;AAQR,eAAsB,kBACrB,OACA,MAWC;CACD,IAAI;AAEJ,KAAI,KAAK,WAAW,CAAC,MAAM,cAAc,MACxC,KAAI;AACH,YAAU,MAAM,qBAAqB,OAAO;GAC3C,WAAW,KAAK;GAChB,eAAe,KAAK;GACpB,CAAC;UACM,OAAO;AACf,MAAI,iBAAiB,MACpB,KAAI,MAAM,SAAS,eAAe,MAAM,SAAS,cAAc,YAEpD,MAAM,SAAS,aACzB,OAAM,IAAI,SAAS,gBAAgB,EAClC,SAAS,iBACT,CAAC;WACQ,MAAM,SAAS,aACzB,OAAM,IAAI,SAAS,gBAAgB,EAClC,SAAS,iBACT,CAAC;MAEF,OAAM;MAGP,OAAM,IAAI,MAAM,MAA2B;;AAM9C,KAAI,MAAM,cAAc;EACvB,MAAM,EAAE,MAAM,YAAY,OAAO,oBAAoB,MAAM,YAIzD,KAAK,aAAa,eAAe;GAClC,QAAQ;GACR,SAAS;IACR,QAAQ;IACR,gBAAgB;IAChB;GACD,MAAM,IAAI,gBAAgB;IACzB,WAAW,KAAK,aAAa;IAC7B,eAAe,KAAK,aAAa;IACjC;IACA,iBAAiB;IACjB,CAAC,CAAC,UAAU;GACb,CAAC;AACF,MAAI,gBACH,QAAO,MACN,yBAAyB,gBAAgB,WAAW,gBAAgB,aACpE;AACF,MAAI,CAAC,WACJ,OAAM,IAAI,SAAS,yBAAyB,EAC3C,SAAS,wBACT,CAAC;AACH,MAAI,CAAC,WAAW,OACf,OAAM,IAAI,SAAS,gBAAgB,EAClC,SAAS,kBACT,CAAC;AAEH,MAAI;GACH,MAAM,eAAe,IAAI,aAAa,WAAW,CAAC,QAAQ;GAC1D,MAAM,EAAE,UAAU,WAAW,GAAG,kBAAkB,KAAK;AAIvD,cAHe,WAAW,MACvB,aAAa,OAAO,cAAc,KAAK,cAAc,GACrD,aAAa,OAAO,cAAc,cAAc,EAClC;WACT,OAAO;AACf,SAAM,IAAI,MAAM,MAA2B;;;AAI7C,KAAI,CAAC,QACJ,OAAM,IAAI,SAAS,gBAAgB,EAClC,SAAS,oBACT,CAAC;AAGH,KAAI,KAAK,QAAQ;EAChB,MAAM,cAAc,IAAI,IACtB,QAAQ,OAA8B,MAAM,IAAI,CACjD;AACD,OAAK,MAAM,MAAM,KAAK,OACrB,KAAI,CAAC,YAAY,IAAI,GAAG,CACvB,OAAM,IAAI,SAAS,aAAa,EAC/B,SAAS,iBAAiB,MAC1B,CAAC;;AAKL,QAAO"}
@@ -116,4 +116,5 @@ declare const apple: (options: AppleOptions) => {
116
116
  };
117
117
  declare const getApplePublicKey: (kid: string) => Promise<Uint8Array<ArrayBufferLike> | CryptoKey>;
118
118
  //#endregion
119
- export { AppleNonConformUser, AppleOptions, AppleProfile, apple, getApplePublicKey };
119
+ export { AppleNonConformUser, AppleOptions, AppleProfile, apple, getApplePublicKey };
120
+ //# sourceMappingURL=apple.d.mts.map
@@ -1,10 +1,10 @@
1
+ import { APIError } from "../error/index.mjs";
1
2
  import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
2
3
  import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
3
4
  import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
4
5
  import "../oauth2/index.mjs";
5
6
  import { betterFetch } from "@better-fetch/fetch";
6
7
  import { decodeJwt, decodeProtectedHeader, importJWK, jwtVerify } from "jose";
7
- import { APIError } from "better-call";
8
8
 
9
9
  //#region src/social-providers/apple.ts
10
10
  const apple = (options) => {
@@ -69,7 +69,9 @@ const apple = (options) => {
69
69
  if (!token.idToken) return null;
70
70
  const profile = decodeJwt(token.idToken);
71
71
  if (!profile) return null;
72
- const name = token.user ? `${token.user.name?.firstName} ${token.user.name?.lastName}` : profile.name || profile.email;
72
+ let name;
73
+ if (token.user?.name) name = `${token.user.name.firstName || ""} ${token.user.name.lastName || ""}`.trim() || " ";
74
+ else name = profile.name || " ";
73
75
  const emailVerified = typeof profile.email_verified === "boolean" ? profile.email_verified : profile.email_verified === "true";
74
76
  const enrichedProfile = {
75
77
  ...profile,
@@ -99,4 +101,5 @@ const getApplePublicKey = async (kid) => {
99
101
  };
100
102
 
101
103
  //#endregion
102
- export { apple, getApplePublicKey };
104
+ export { apple, getApplePublicKey };
105
+ //# sourceMappingURL=apple.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apple.mjs","names":[],"sources":["../../src/social-providers/apple.ts"],"sourcesContent":["import { betterFetch } from \"@better-fetch/fetch\";\n\nimport { decodeJwt, decodeProtectedHeader, importJWK, jwtVerify } from \"jose\";\nimport { APIError } from \"../error\";\nimport type { OAuthProvider, ProviderOptions } from \"../oauth2\";\nimport {\n\tcreateAuthorizationURL,\n\trefreshAccessToken,\n\tvalidateAuthorizationCode,\n} from \"../oauth2\";\nexport interface AppleProfile {\n\t/**\n\t * The subject registered claim identifies the principal that’s the subject\n\t * of the identity token. Because this token is for your app, the value is\n\t * the unique identifier for the user.\n\t */\n\tsub: string;\n\t/**\n\t * A String value representing the user's email address.\n\t * The email address is either the user's real email address or the proxy\n\t * address, depending on their status private email relay service.\n\t */\n\temail: string;\n\t/**\n\t * A string or Boolean value that indicates whether the service verifies\n\t * the email. The value can either be a string (\"true\" or \"false\") or a\n\t * Boolean (true or false). The system may not verify email addresses for\n\t * Sign in with Apple at Work & School users, and this claim is \"false\" or\n\t * false for those users.\n\t */\n\temail_verified: true | \"true\";\n\t/**\n\t * A string or Boolean value that indicates whether the email that the user\n\t * shares is the proxy address. The value can either be a string (\"true\" or\n\t * \"false\") or a Boolean (true or false).\n\t */\n\tis_private_email: boolean;\n\t/**\n\t * An Integer value that indicates whether the user appears to be a real\n\t * person. Use the value of this claim to mitigate fraud. The possible\n\t * values are: 0 (or Unsupported), 1 (or Unknown), 2 (or LikelyReal). For\n\t * more information, see ASUserDetectionStatus. This claim is present only\n\t * in iOS 14 and later, macOS 11 and later, watchOS 7 and later, tvOS 14\n\t * and later. The claim isn’t present or supported for web-based apps.\n\t */\n\treal_user_status: number;\n\t/**\n\t * The user’s full name in the format provided during the authorization\n\t * process.\n\t */\n\tname: string;\n\t/**\n\t * The URL to the user's profile picture.\n\t */\n\tpicture: string;\n\tuser?: AppleNonConformUser | undefined;\n}\n\n/**\n * This is the shape of the `user` query parameter that Apple sends the first\n * time the user consents to the app.\n * @see https://developer.apple.com/documentation/signinwithapplerestapi/request-an-authorization-to-the-sign-in-with-apple-server./\n */\nexport interface AppleNonConformUser {\n\tname: {\n\t\tfirstName: string;\n\t\tlastName: string;\n\t};\n\temail: string;\n}\n\nexport interface AppleOptions extends ProviderOptions<AppleProfile> {\n\tclientId: string;\n\tappBundleIdentifier?: string | undefined;\n\taudience?: (string | string[]) | undefined;\n}\n\nexport const apple = (options: AppleOptions) => {\n\tconst tokenEndpoint = \"https://appleid.apple.com/auth/token\";\n\treturn {\n\t\tid: \"apple\",\n\t\tname: \"Apple\",\n\t\tasync createAuthorizationURL({ state, scopes, redirectURI }) {\n\t\t\tconst _scope = options.disableDefaultScope ? [] : [\"email\", \"name\"];\n\t\t\tif (options.scope) _scope.push(...options.scope);\n\t\t\tif (scopes) _scope.push(...scopes);\n\t\t\tconst url = await createAuthorizationURL({\n\t\t\t\tid: \"apple\",\n\t\t\t\toptions,\n\t\t\t\tauthorizationEndpoint: \"https://appleid.apple.com/auth/authorize\",\n\t\t\t\tscopes: _scope,\n\t\t\t\tstate,\n\t\t\t\tredirectURI,\n\t\t\t\tresponseMode: \"form_post\",\n\t\t\t\tresponseType: \"code id_token\",\n\t\t\t});\n\t\t\treturn url;\n\t\t},\n\t\tvalidateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {\n\t\t\treturn validateAuthorizationCode({\n\t\t\t\tcode,\n\t\t\t\tcodeVerifier,\n\t\t\t\tredirectURI,\n\t\t\t\toptions,\n\t\t\t\ttokenEndpoint,\n\t\t\t});\n\t\t},\n\t\tasync verifyIdToken(token, nonce) {\n\t\t\tif (options.disableIdTokenSignIn) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (options.verifyIdToken) {\n\t\t\t\treturn options.verifyIdToken(token, nonce);\n\t\t\t}\n\t\t\tconst decodedHeader = decodeProtectedHeader(token);\n\t\t\tconst { kid, alg: jwtAlg } = decodedHeader;\n\t\t\tif (!kid || !jwtAlg) return false;\n\t\t\tconst publicKey = await getApplePublicKey(kid);\n\t\t\tconst { payload: jwtClaims } = await jwtVerify(token, publicKey, {\n\t\t\t\talgorithms: [jwtAlg],\n\t\t\t\tissuer: \"https://appleid.apple.com\",\n\t\t\t\taudience:\n\t\t\t\t\toptions.audience && options.audience.length\n\t\t\t\t\t\t? options.audience\n\t\t\t\t\t\t: options.appBundleIdentifier\n\t\t\t\t\t\t\t? options.appBundleIdentifier\n\t\t\t\t\t\t\t: options.clientId,\n\t\t\t\tmaxTokenAge: \"1h\",\n\t\t\t});\n\t\t\t[\"email_verified\", \"is_private_email\"].forEach((field) => {\n\t\t\t\tif (jwtClaims[field] !== undefined) {\n\t\t\t\t\tjwtClaims[field] = Boolean(jwtClaims[field]);\n\t\t\t\t}\n\t\t\t});\n\t\t\tif (nonce && jwtClaims.nonce !== nonce) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn !!jwtClaims;\n\t\t},\n\t\trefreshAccessToken: options.refreshAccessToken\n\t\t\t? options.refreshAccessToken\n\t\t\t: async (refreshToken) => {\n\t\t\t\t\treturn refreshAccessToken({\n\t\t\t\t\t\trefreshToken,\n\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\tclientId: options.clientId,\n\t\t\t\t\t\t\tclientKey: options.clientKey,\n\t\t\t\t\t\t\tclientSecret: options.clientSecret,\n\t\t\t\t\t\t},\n\t\t\t\t\t\ttokenEndpoint: \"https://appleid.apple.com/auth/token\",\n\t\t\t\t\t});\n\t\t\t\t},\n\t\tasync getUserInfo(token) {\n\t\t\tif (options.getUserInfo) {\n\t\t\t\treturn options.getUserInfo(token);\n\t\t\t}\n\t\t\tif (!token.idToken) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst profile = decodeJwt<AppleProfile>(token.idToken);\n\t\t\tif (!profile) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// TODO: \" \" masking will be removed when the name field is made optional\n\t\t\tlet name: string;\n\t\t\tif (token.user?.name) {\n\t\t\t\tconst firstName = token.user.name.firstName || \"\";\n\t\t\t\tconst lastName = token.user.name.lastName || \"\";\n\t\t\t\tconst fullName = `${firstName} ${lastName}`.trim();\n\t\t\t\tname = fullName || \" \";\n\t\t\t} else {\n\t\t\t\tname = profile.name || \" \";\n\t\t\t}\n\n\t\t\tconst emailVerified =\n\t\t\t\ttypeof profile.email_verified === \"boolean\"\n\t\t\t\t\t? profile.email_verified\n\t\t\t\t\t: profile.email_verified === \"true\";\n\t\t\tconst enrichedProfile = {\n\t\t\t\t...profile,\n\t\t\t\tname,\n\t\t\t};\n\t\t\tconst userMap = await options.mapProfileToUser?.(enrichedProfile);\n\t\t\treturn {\n\t\t\t\tuser: {\n\t\t\t\t\tid: profile.sub,\n\t\t\t\t\tname: enrichedProfile.name,\n\t\t\t\t\temailVerified: emailVerified,\n\t\t\t\t\temail: profile.email,\n\t\t\t\t\t...userMap,\n\t\t\t\t},\n\t\t\t\tdata: enrichedProfile,\n\t\t\t};\n\t\t},\n\t\toptions,\n\t} satisfies OAuthProvider<AppleProfile>;\n};\n\nexport const getApplePublicKey = async (kid: string) => {\n\tconst APPLE_BASE_URL = \"https://appleid.apple.com\";\n\tconst JWKS_APPLE_URI = \"/auth/keys\";\n\tconst { data } = await betterFetch<{\n\t\tkeys: Array<{\n\t\t\tkid: string;\n\t\t\talg: string;\n\t\t\tkty: string;\n\t\t\tuse: string;\n\t\t\tn: string;\n\t\t\te: string;\n\t\t}>;\n\t}>(`${APPLE_BASE_URL}${JWKS_APPLE_URI}`);\n\tif (!data?.keys) {\n\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\tmessage: \"Keys not found\",\n\t\t});\n\t}\n\tconst jwk = data.keys.find((key) => key.kid === kid);\n\tif (!jwk) {\n\t\tthrow new Error(`JWK with kid ${kid} not found`);\n\t}\n\treturn await importJWK(jwk, jwk.alg);\n};\n"],"mappings":";;;;;;;;;AA6EA,MAAa,SAAS,YAA0B;CAC/C,MAAM,gBAAgB;AACtB,QAAO;EACN,IAAI;EACJ,MAAM;EACN,MAAM,uBAAuB,EAAE,OAAO,QAAQ,eAAe;GAC5D,MAAM,SAAS,QAAQ,sBAAsB,EAAE,GAAG,CAAC,SAAS,OAAO;AACnE,OAAI,QAAQ,MAAO,QAAO,KAAK,GAAG,QAAQ,MAAM;AAChD,OAAI,OAAQ,QAAO,KAAK,GAAG,OAAO;AAWlC,UAVY,MAAM,uBAAuB;IACxC,IAAI;IACJ;IACA,uBAAuB;IACvB,QAAQ;IACR;IACA;IACA,cAAc;IACd,cAAc;IACd,CAAC;;EAGH,2BAA2B,OAAO,EAAE,MAAM,cAAc,kBAAkB;AACzE,UAAO,0BAA0B;IAChC;IACA;IACA;IACA;IACA;IACA,CAAC;;EAEH,MAAM,cAAc,OAAO,OAAO;AACjC,OAAI,QAAQ,qBACX,QAAO;AAER,OAAI,QAAQ,cACX,QAAO,QAAQ,cAAc,OAAO,MAAM;GAG3C,MAAM,EAAE,KAAK,KAAK,WADI,sBAAsB,MAAM;AAElD,OAAI,CAAC,OAAO,CAAC,OAAQ,QAAO;GAE5B,MAAM,EAAE,SAAS,cAAc,MAAM,UAAU,OAD7B,MAAM,kBAAkB,IAAI,EACmB;IAChE,YAAY,CAAC,OAAO;IACpB,QAAQ;IACR,UACC,QAAQ,YAAY,QAAQ,SAAS,SAClC,QAAQ,WACR,QAAQ,sBACP,QAAQ,sBACR,QAAQ;IACb,aAAa;IACb,CAAC;AACF,IAAC,kBAAkB,mBAAmB,CAAC,SAAS,UAAU;AACzD,QAAI,UAAU,WAAW,OACxB,WAAU,SAAS,QAAQ,UAAU,OAAO;KAE5C;AACF,OAAI,SAAS,UAAU,UAAU,MAChC,QAAO;AAER,UAAO,CAAC,CAAC;;EAEV,oBAAoB,QAAQ,qBACzB,QAAQ,qBACR,OAAO,iBAAiB;AACxB,UAAO,mBAAmB;IACzB;IACA,SAAS;KACR,UAAU,QAAQ;KAClB,WAAW,QAAQ;KACnB,cAAc,QAAQ;KACtB;IACD,eAAe;IACf,CAAC;;EAEL,MAAM,YAAY,OAAO;AACxB,OAAI,QAAQ,YACX,QAAO,QAAQ,YAAY,MAAM;AAElC,OAAI,CAAC,MAAM,QACV,QAAO;GAER,MAAM,UAAU,UAAwB,MAAM,QAAQ;AACtD,OAAI,CAAC,QACJ,QAAO;GAIR,IAAI;AACJ,OAAI,MAAM,MAAM,KAIf,QADiB,GAFC,MAAM,KAAK,KAAK,aAAa,GAEjB,GADb,MAAM,KAAK,KAAK,YAAY,KACD,MAAM,IAC/B;OAEnB,QAAO,QAAQ,QAAQ;GAGxB,MAAM,gBACL,OAAO,QAAQ,mBAAmB,YAC/B,QAAQ,iBACR,QAAQ,mBAAmB;GAC/B,MAAM,kBAAkB;IACvB,GAAG;IACH;IACA;GACD,MAAM,UAAU,MAAM,QAAQ,mBAAmB,gBAAgB;AACjE,UAAO;IACN,MAAM;KACL,IAAI,QAAQ;KACZ,MAAM,gBAAgB;KACP;KACf,OAAO,QAAQ;KACf,GAAG;KACH;IACD,MAAM;IACN;;EAEF;EACA;;AAGF,MAAa,oBAAoB,OAAO,QAAgB;CAGvD,MAAM,EAAE,SAAS,MAAM,YASpB,sCAAqC;AACxC,KAAI,CAAC,MAAM,KACV,OAAM,IAAI,SAAS,eAAe,EACjC,SAAS,kBACT,CAAC;CAEH,MAAM,MAAM,KAAK,KAAK,MAAM,QAAQ,IAAI,QAAQ,IAAI;AACpD,KAAI,CAAC,IACJ,OAAM,IAAI,MAAM,gBAAgB,IAAI,YAAY;AAEjD,QAAO,MAAM,UAAU,KAAK,IAAI,IAAI"}
@@ -69,4 +69,5 @@ declare const atlassian: (options: AtlassianOptions) => {
69
69
  options: AtlassianOptions;
70
70
  };
71
71
  //#endregion
72
- export { AtlassianOptions, AtlassianProfile, atlassian };
72
+ export { AtlassianOptions, AtlassianProfile, atlassian };
73
+ //# sourceMappingURL=atlassian.d.mts.map
@@ -80,4 +80,5 @@ const atlassian = (options) => {
80
80
  };
81
81
 
82
82
  //#endregion
83
- export { atlassian };
83
+ export { atlassian };
84
+ //# sourceMappingURL=atlassian.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atlassian.mjs","names":[],"sources":["../../src/social-providers/atlassian.ts"],"sourcesContent":["import { betterFetch } from \"@better-fetch/fetch\";\nimport { logger } from \"../env\";\nimport { BetterAuthError } from \"../error\";\nimport type { OAuthProvider, ProviderOptions } from \"../oauth2\";\nimport {\n\tcreateAuthorizationURL,\n\trefreshAccessToken,\n\tvalidateAuthorizationCode,\n} from \"../oauth2\";\n\nexport interface AtlassianProfile {\n\taccount_type?: string | undefined;\n\taccount_id: string;\n\temail?: string | undefined;\n\tname: string;\n\tpicture?: string | undefined;\n\tnickname?: string | undefined;\n\tlocale?: string | undefined;\n\textended_profile?:\n\t\t| {\n\t\t\t\tjob_title?: string;\n\t\t\t\torganization?: string;\n\t\t\t\tdepartment?: string;\n\t\t\t\tlocation?: string;\n\t\t }\n\t\t| undefined;\n}\nexport interface AtlassianOptions extends ProviderOptions<AtlassianProfile> {\n\tclientId: string;\n}\n\nexport const atlassian = (options: AtlassianOptions) => {\n\treturn {\n\t\tid: \"atlassian\",\n\t\tname: \"Atlassian\",\n\n\t\tasync createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {\n\t\t\tif (!options.clientId || !options.clientSecret) {\n\t\t\t\tlogger.error(\"Client Id and Secret are required for Atlassian\");\n\t\t\t\tthrow new BetterAuthError(\"CLIENT_ID_AND_SECRET_REQUIRED\");\n\t\t\t}\n\t\t\tif (!codeVerifier) {\n\t\t\t\tthrow new BetterAuthError(\"codeVerifier is required for Atlassian\");\n\t\t\t}\n\n\t\t\tconst _scopes = options.disableDefaultScope\n\t\t\t\t? []\n\t\t\t\t: [\"read:jira-user\", \"offline_access\"];\n\t\t\tif (options.scope) _scopes.push(...options.scope);\n\t\t\tif (scopes) _scopes.push(...scopes);\n\n\t\t\treturn createAuthorizationURL({\n\t\t\t\tid: \"atlassian\",\n\t\t\t\toptions,\n\t\t\t\tauthorizationEndpoint: \"https://auth.atlassian.com/authorize\",\n\t\t\t\tscopes: _scopes,\n\t\t\t\tstate,\n\t\t\t\tcodeVerifier,\n\t\t\t\tredirectURI,\n\t\t\t\tadditionalParams: {\n\t\t\t\t\taudience: \"api.atlassian.com\",\n\t\t\t\t},\n\t\t\t\tprompt: options.prompt,\n\t\t\t});\n\t\t},\n\n\t\tvalidateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {\n\t\t\treturn validateAuthorizationCode({\n\t\t\t\tcode,\n\t\t\t\tcodeVerifier,\n\t\t\t\tredirectURI,\n\t\t\t\toptions,\n\t\t\t\ttokenEndpoint: \"https://auth.atlassian.com/oauth/token\",\n\t\t\t});\n\t\t},\n\n\t\trefreshAccessToken: options.refreshAccessToken\n\t\t\t? options.refreshAccessToken\n\t\t\t: async (refreshToken) => {\n\t\t\t\t\treturn refreshAccessToken({\n\t\t\t\t\t\trefreshToken,\n\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\tclientId: options.clientId,\n\t\t\t\t\t\t\tclientSecret: options.clientSecret,\n\t\t\t\t\t\t},\n\t\t\t\t\t\ttokenEndpoint: \"https://auth.atlassian.com/oauth/token\",\n\t\t\t\t\t});\n\t\t\t\t},\n\n\t\tasync getUserInfo(token) {\n\t\t\tif (options.getUserInfo) {\n\t\t\t\treturn options.getUserInfo(token);\n\t\t\t}\n\n\t\t\tif (!token.accessToken) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst { data: profile } = await betterFetch<{\n\t\t\t\t\taccount_id: string;\n\t\t\t\t\tname: string;\n\t\t\t\t\temail?: string | undefined;\n\t\t\t\t\tpicture?: string | undefined;\n\t\t\t\t}>(\"https://api.atlassian.com/me\", {\n\t\t\t\t\theaders: { Authorization: `Bearer ${token.accessToken}` },\n\t\t\t\t});\n\n\t\t\t\tif (!profile) return null;\n\n\t\t\t\tconst userMap = await options.mapProfileToUser?.(profile);\n\n\t\t\t\treturn {\n\t\t\t\t\tuser: {\n\t\t\t\t\t\tid: profile.account_id,\n\t\t\t\t\t\tname: profile.name,\n\t\t\t\t\t\temail: profile.email,\n\t\t\t\t\t\timage: profile.picture,\n\t\t\t\t\t\temailVerified: false,\n\t\t\t\t\t\t...userMap,\n\t\t\t\t\t},\n\t\t\t\t\tdata: profile,\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\"Failed to fetch user info from Figma:\", error);\n\t\t\t\treturn null;\n\t\t\t}\n\t\t},\n\n\t\toptions,\n\t} satisfies OAuthProvider<AtlassianProfile>;\n};\n"],"mappings":";;;;;;;;;;AA+BA,MAAa,aAAa,YAA8B;AACvD,QAAO;EACN,IAAI;EACJ,MAAM;EAEN,MAAM,uBAAuB,EAAE,OAAO,QAAQ,cAAc,eAAe;AAC1E,OAAI,CAAC,QAAQ,YAAY,CAAC,QAAQ,cAAc;AAC/C,WAAO,MAAM,kDAAkD;AAC/D,UAAM,IAAI,gBAAgB,gCAAgC;;AAE3D,OAAI,CAAC,aACJ,OAAM,IAAI,gBAAgB,yCAAyC;GAGpE,MAAM,UAAU,QAAQ,sBACrB,EAAE,GACF,CAAC,kBAAkB,iBAAiB;AACvC,OAAI,QAAQ,MAAO,SAAQ,KAAK,GAAG,QAAQ,MAAM;AACjD,OAAI,OAAQ,SAAQ,KAAK,GAAG,OAAO;AAEnC,UAAO,uBAAuB;IAC7B,IAAI;IACJ;IACA,uBAAuB;IACvB,QAAQ;IACR;IACA;IACA;IACA,kBAAkB,EACjB,UAAU,qBACV;IACD,QAAQ,QAAQ;IAChB,CAAC;;EAGH,2BAA2B,OAAO,EAAE,MAAM,cAAc,kBAAkB;AACzE,UAAO,0BAA0B;IAChC;IACA;IACA;IACA;IACA,eAAe;IACf,CAAC;;EAGH,oBAAoB,QAAQ,qBACzB,QAAQ,qBACR,OAAO,iBAAiB;AACxB,UAAO,mBAAmB;IACzB;IACA,SAAS;KACR,UAAU,QAAQ;KAClB,cAAc,QAAQ;KACtB;IACD,eAAe;IACf,CAAC;;EAGL,MAAM,YAAY,OAAO;AACxB,OAAI,QAAQ,YACX,QAAO,QAAQ,YAAY,MAAM;AAGlC,OAAI,CAAC,MAAM,YACV,QAAO;AAGR,OAAI;IACH,MAAM,EAAE,MAAM,YAAY,MAAM,YAK7B,gCAAgC,EAClC,SAAS,EAAE,eAAe,UAAU,MAAM,eAAe,EACzD,CAAC;AAEF,QAAI,CAAC,QAAS,QAAO;IAErB,MAAM,UAAU,MAAM,QAAQ,mBAAmB,QAAQ;AAEzD,WAAO;KACN,MAAM;MACL,IAAI,QAAQ;MACZ,MAAM,QAAQ;MACd,OAAO,QAAQ;MACf,OAAO,QAAQ;MACf,eAAe;MACf,GAAG;MACH;KACD,MAAM;KACN;YACO,OAAO;AACf,WAAO,MAAM,yCAAyC,MAAM;AAC5D,WAAO;;;EAIT;EACA"}
@@ -84,4 +84,5 @@ declare const cognito: (options: CognitoOptions) => {
84
84
  };
85
85
  declare const getCognitoPublicKey: (kid: string, region: string, userPoolId: string) => Promise<Uint8Array<ArrayBufferLike> | CryptoKey>;
86
86
  //#endregion
87
- export { CognitoOptions, CognitoProfile, cognito, getCognitoPublicKey };
87
+ export { CognitoOptions, CognitoProfile, cognito, getCognitoPublicKey };
88
+ //# sourceMappingURL=cognito.d.mts.map
@@ -1,13 +1,12 @@
1
1
  import { logger } from "../env/logger.mjs";
2
2
  import "../env/index.mjs";
3
- import { BetterAuthError } from "../error/index.mjs";
3
+ import { APIError, BetterAuthError } from "../error/index.mjs";
4
4
  import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
5
5
  import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
6
6
  import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
7
7
  import "../oauth2/index.mjs";
8
8
  import { betterFetch } from "@better-fetch/fetch";
9
9
  import { decodeJwt, decodeProtectedHeader, importJWK, jwtVerify } from "jose";
10
- import { APIError } from "better-call";
11
10
 
12
11
  //#region src/social-providers/cognito.ts
13
12
  const cognito = (options) => {
@@ -163,4 +162,5 @@ const getCognitoPublicKey = async (kid, region, userPoolId) => {
163
162
  };
164
163
 
165
164
  //#endregion
166
- export { cognito, getCognitoPublicKey };
165
+ export { cognito, getCognitoPublicKey };
166
+ //# sourceMappingURL=cognito.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cognito.mjs","names":[],"sources":["../../src/social-providers/cognito.ts"],"sourcesContent":["import { betterFetch } from \"@better-fetch/fetch\";\nimport { decodeJwt, decodeProtectedHeader, importJWK, jwtVerify } from \"jose\";\nimport { logger } from \"../env\";\nimport { APIError, BetterAuthError } from \"../error\";\nimport type { OAuthProvider, ProviderOptions } from \"../oauth2\";\nimport {\n\tcreateAuthorizationURL,\n\trefreshAccessToken,\n\tvalidateAuthorizationCode,\n} from \"../oauth2\";\n\nexport interface CognitoProfile {\n\tsub: string;\n\temail: string;\n\temail_verified: boolean;\n\tname: string;\n\tgiven_name?: string | undefined;\n\tfamily_name?: string | undefined;\n\tpicture?: string | undefined;\n\tusername?: string | undefined;\n\tlocale?: string | undefined;\n\tphone_number?: string | undefined;\n\tphone_number_verified?: boolean | undefined;\n\taud: string;\n\tiss: string;\n\texp: number;\n\tiat: number;\n\t// Custom attributes from Cognito can be added here\n\t[key: string]: any;\n}\n\nexport interface CognitoOptions extends ProviderOptions<CognitoProfile> {\n\tclientId: string;\n\t/**\n\t * The Cognito domain (e.g., \"your-app.auth.us-east-1.amazoncognito.com\")\n\t */\n\tdomain: string;\n\t/**\n\t * AWS region where User Pool is hosted (e.g., \"us-east-1\")\n\t */\n\tregion: string;\n\tuserPoolId: string;\n\trequireClientSecret?: boolean | undefined;\n}\n\nexport const cognito = (options: CognitoOptions) => {\n\tif (!options.domain || !options.region || !options.userPoolId) {\n\t\tlogger.error(\n\t\t\t\"Domain, region and userPoolId are required for Amazon Cognito. Make sure to provide them in the options.\",\n\t\t);\n\t\tthrow new BetterAuthError(\"DOMAIN_AND_REGION_REQUIRED\");\n\t}\n\n\tconst cleanDomain = options.domain.replace(/^https?:\\/\\//, \"\");\n\tconst authorizationEndpoint = `https://${cleanDomain}/oauth2/authorize`;\n\tconst tokenEndpoint = `https://${cleanDomain}/oauth2/token`;\n\tconst userInfoEndpoint = `https://${cleanDomain}/oauth2/userinfo`;\n\n\treturn {\n\t\tid: \"cognito\",\n\t\tname: \"Cognito\",\n\t\tasync createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {\n\t\t\tif (!options.clientId) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t\"ClientId is required for Amazon Cognito. Make sure to provide them in the options.\",\n\t\t\t\t);\n\t\t\t\tthrow new BetterAuthError(\"CLIENT_ID_AND_SECRET_REQUIRED\");\n\t\t\t}\n\n\t\t\tif (options.requireClientSecret && !options.clientSecret) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t\"Client Secret is required when requireClientSecret is true. Make sure to provide it in the options.\",\n\t\t\t\t);\n\t\t\t\tthrow new BetterAuthError(\"CLIENT_SECRET_REQUIRED\");\n\t\t\t}\n\t\t\tconst _scopes = options.disableDefaultScope\n\t\t\t\t? []\n\t\t\t\t: [\"openid\", \"profile\", \"email\"];\n\t\t\tif (options.scope) _scopes.push(...options.scope);\n\t\t\tif (scopes) _scopes.push(...scopes);\n\n\t\t\tconst url = await createAuthorizationURL({\n\t\t\t\tid: \"cognito\",\n\t\t\t\toptions: {\n\t\t\t\t\t...options,\n\t\t\t\t},\n\t\t\t\tauthorizationEndpoint,\n\t\t\t\tscopes: _scopes,\n\t\t\t\tstate,\n\t\t\t\tcodeVerifier,\n\t\t\t\tredirectURI,\n\t\t\t\tprompt: options.prompt,\n\t\t\t});\n\t\t\t// AWS Cognito requires scopes to be encoded with %20 instead of +\n\t\t\t// URLSearchParams encodes spaces as + by default, so we need to fix this\n\t\t\tconst scopeValue = url.searchParams.get(\"scope\");\n\t\t\tif (scopeValue) {\n\t\t\t\turl.searchParams.delete(\"scope\");\n\t\t\t\tconst encodedScope = encodeURIComponent(scopeValue);\n\t\t\t\t// Manually append the scope with proper encoding to the URL\n\t\t\t\tconst urlString = url.toString();\n\t\t\t\tconst separator = urlString.includes(\"?\") ? \"&\" : \"?\";\n\t\t\t\treturn new URL(`${urlString}${separator}scope=${encodedScope}`);\n\t\t\t}\n\t\t\treturn url;\n\t\t},\n\n\t\tvalidateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {\n\t\t\treturn validateAuthorizationCode({\n\t\t\t\tcode,\n\t\t\t\tcodeVerifier,\n\t\t\t\tredirectURI,\n\t\t\t\toptions,\n\t\t\t\ttokenEndpoint,\n\t\t\t});\n\t\t},\n\n\t\trefreshAccessToken: options.refreshAccessToken\n\t\t\t? options.refreshAccessToken\n\t\t\t: async (refreshToken) => {\n\t\t\t\t\treturn refreshAccessToken({\n\t\t\t\t\t\trefreshToken,\n\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\tclientId: options.clientId,\n\t\t\t\t\t\t\tclientKey: options.clientKey,\n\t\t\t\t\t\t\tclientSecret: options.clientSecret,\n\t\t\t\t\t\t},\n\t\t\t\t\t\ttokenEndpoint,\n\t\t\t\t\t});\n\t\t\t\t},\n\n\t\tasync verifyIdToken(token, nonce) {\n\t\t\tif (options.disableIdTokenSignIn) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (options.verifyIdToken) {\n\t\t\t\treturn options.verifyIdToken(token, nonce);\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst decodedHeader = decodeProtectedHeader(token);\n\t\t\t\tconst { kid, alg: jwtAlg } = decodedHeader;\n\t\t\t\tif (!kid || !jwtAlg) return false;\n\n\t\t\t\tconst publicKey = await getCognitoPublicKey(\n\t\t\t\t\tkid,\n\t\t\t\t\toptions.region,\n\t\t\t\t\toptions.userPoolId,\n\t\t\t\t);\n\t\t\t\tconst expectedIssuer = `https://cognito-idp.${options.region}.amazonaws.com/${options.userPoolId}`;\n\n\t\t\t\tconst { payload: jwtClaims } = await jwtVerify(token, publicKey, {\n\t\t\t\t\talgorithms: [jwtAlg],\n\t\t\t\t\tissuer: expectedIssuer,\n\t\t\t\t\taudience: options.clientId,\n\t\t\t\t\tmaxTokenAge: \"1h\",\n\t\t\t\t});\n\n\t\t\t\tif (nonce && jwtClaims.nonce !== nonce) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\"Failed to verify ID token:\", error);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t},\n\n\t\tasync getUserInfo(token) {\n\t\t\tif (options.getUserInfo) {\n\t\t\t\treturn options.getUserInfo(token);\n\t\t\t}\n\n\t\t\tif (token.idToken) {\n\t\t\t\ttry {\n\t\t\t\t\tconst profile = decodeJwt<CognitoProfile>(token.idToken);\n\t\t\t\t\tif (!profile) {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\t\t\t\t\tconst name =\n\t\t\t\t\t\tprofile.name ||\n\t\t\t\t\t\tprofile.given_name ||\n\t\t\t\t\t\tprofile.username ||\n\t\t\t\t\t\tprofile.email;\n\t\t\t\t\tconst enrichedProfile = {\n\t\t\t\t\t\t...profile,\n\t\t\t\t\t\tname,\n\t\t\t\t\t};\n\t\t\t\t\tconst userMap = await options.mapProfileToUser?.(enrichedProfile);\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\tid: profile.sub,\n\t\t\t\t\t\t\tname: enrichedProfile.name,\n\t\t\t\t\t\t\temail: profile.email,\n\t\t\t\t\t\t\timage: profile.picture,\n\t\t\t\t\t\t\temailVerified: profile.email_verified,\n\t\t\t\t\t\t\t...userMap,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tdata: enrichedProfile,\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\tlogger.error(\"Failed to decode ID token:\", error);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (token.accessToken) {\n\t\t\t\ttry {\n\t\t\t\t\tconst { data: userInfo } = await betterFetch<CognitoProfile>(\n\t\t\t\t\t\tuserInfoEndpoint,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t\tAuthorization: `Bearer ${token.accessToken}`,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\n\t\t\t\t\tif (userInfo) {\n\t\t\t\t\t\tconst userMap = await options.mapProfileToUser?.(userInfo);\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\t\tid: userInfo.sub,\n\t\t\t\t\t\t\t\tname: userInfo.name || userInfo.given_name || userInfo.username,\n\t\t\t\t\t\t\t\temail: userInfo.email,\n\t\t\t\t\t\t\t\timage: userInfo.picture,\n\t\t\t\t\t\t\t\temailVerified: userInfo.email_verified,\n\t\t\t\t\t\t\t\t...userMap,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tdata: userInfo,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tlogger.error(\"Failed to fetch user info from Cognito:\", error);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\t\t},\n\n\t\toptions,\n\t} satisfies OAuthProvider<CognitoProfile>;\n};\n\nexport const getCognitoPublicKey = async (\n\tkid: string,\n\tregion: string,\n\tuserPoolId: string,\n) => {\n\tconst COGNITO_JWKS_URI = `https://cognito-idp.${region}.amazonaws.com/${userPoolId}/.well-known/jwks.json`;\n\n\ttry {\n\t\tconst { data } = await betterFetch<{\n\t\t\tkeys: Array<{\n\t\t\t\tkid: string;\n\t\t\t\talg: string;\n\t\t\t\tkty: string;\n\t\t\t\tuse: string;\n\t\t\t\tn: string;\n\t\t\t\te: string;\n\t\t\t}>;\n\t\t}>(COGNITO_JWKS_URI);\n\n\t\tif (!data?.keys) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Keys not found\",\n\t\t\t});\n\t\t}\n\n\t\tconst jwk = data.keys.find((key) => key.kid === kid);\n\t\tif (!jwk) {\n\t\t\tthrow new Error(`JWK with kid ${kid} not found`);\n\t\t}\n\n\t\treturn await importJWK(jwk, jwk.alg);\n\t} catch (error) {\n\t\tlogger.error(\"Failed to fetch Cognito public key:\", error);\n\t\tthrow error;\n\t}\n};\n"],"mappings":"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"}
@@ -123,4 +123,5 @@ declare const discord: (options: DiscordOptions) => {
123
123
  options: DiscordOptions;
124
124
  };
125
125
  //#endregion
126
- export { DiscordOptions, DiscordProfile, discord };
126
+ export { DiscordOptions, DiscordProfile, discord };
127
+ //# sourceMappingURL=discord.d.mts.map
@@ -61,4 +61,5 @@ const discord = (options) => {
61
61
  };
62
62
 
63
63
  //#endregion
64
- export { discord };
64
+ export { discord };
65
+ //# sourceMappingURL=discord.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discord.mjs","names":[],"sources":["../../src/social-providers/discord.ts"],"sourcesContent":["import { betterFetch } from \"@better-fetch/fetch\";\nimport type { OAuthProvider, ProviderOptions } from \"../oauth2\";\nimport { refreshAccessToken, validateAuthorizationCode } from \"../oauth2\";\nexport interface DiscordProfile extends Record<string, any> {\n\t/** the user's id (i.e. the numerical snowflake) */\n\tid: string;\n\t/** the user's username, not unique across the platform */\n\tusername: string;\n\t/** the user's Discord-tag */\n\tdiscriminator: string;\n\t/** the user's display name, if it is set */\n\tglobal_name: string | null;\n\t/**\n\t * the user's avatar hash:\n\t * https://discord.com/developers/docs/reference#image-formatting\n\t */\n\tavatar: string | null;\n\t/** whether the user belongs to an OAuth2 application */\n\tbot?: boolean | undefined;\n\t/**\n\t * whether the user is an Official Discord System user (part of the urgent\n\t * message system)\n\t */\n\tsystem?: boolean | undefined;\n\t/** whether the user has two factor enabled on their account */\n\tmfa_enabled: boolean;\n\t/**\n\t * the user's banner hash:\n\t * https://discord.com/developers/docs/reference#image-formatting\n\t */\n\tbanner: string | null;\n\n\t/** the user's banner color encoded as an integer representation of hexadecimal color code */\n\taccent_color: number | null;\n\n\t/**\n\t * the user's chosen language option:\n\t * https://discord.com/developers/docs/reference#locales\n\t */\n\tlocale: string;\n\t/** whether the email on this account has been verified */\n\tverified: boolean;\n\t/** the user's email */\n\temail: string;\n\t/**\n\t * the flags on a user's account:\n\t * https://discord.com/developers/docs/resources/user#user-object-user-flags\n\t */\n\tflags: number;\n\t/**\n\t * the type of Nitro subscription on a user's account:\n\t * https://discord.com/developers/docs/resources/user#user-object-premium-types\n\t */\n\tpremium_type: number;\n\t/**\n\t * the public flags on a user's account:\n\t * https://discord.com/developers/docs/resources/user#user-object-user-flags\n\t */\n\tpublic_flags: number;\n\t/** undocumented field; corresponds to the user's custom nickname */\n\tdisplay_name: string | null;\n\t/**\n\t * undocumented field; corresponds to the Discord feature where you can e.g.\n\t * put your avatar inside of an ice cube\n\t */\n\tavatar_decoration: string | null;\n\t/**\n\t * undocumented field; corresponds to the premium feature where you can\n\t * select a custom banner color\n\t */\n\tbanner_color: string | null;\n\t/** undocumented field; the CDN URL of their profile picture */\n\timage_url: string;\n}\n\nexport interface DiscordOptions extends ProviderOptions<DiscordProfile> {\n\tclientId: string;\n\tprompt?: (\"none\" | \"consent\") | undefined;\n\tpermissions?: number | undefined;\n}\n\nexport const discord = (options: DiscordOptions) => {\n\treturn {\n\t\tid: \"discord\",\n\t\tname: \"Discord\",\n\t\tcreateAuthorizationURL({ state, scopes, redirectURI }) {\n\t\t\tconst _scopes = options.disableDefaultScope ? [] : [\"identify\", \"email\"];\n\t\t\tif (scopes) _scopes.push(...scopes);\n\t\t\tif (options.scope) _scopes.push(...options.scope);\n\t\t\tconst hasBotScope = _scopes.includes(\"bot\");\n\t\t\tconst permissionsParam =\n\t\t\t\thasBotScope && options.permissions !== undefined\n\t\t\t\t\t? `&permissions=${options.permissions}`\n\t\t\t\t\t: \"\";\n\t\t\treturn new URL(\n\t\t\t\t`https://discord.com/api/oauth2/authorize?scope=${_scopes.join(\n\t\t\t\t\t\"+\",\n\t\t\t\t)}&response_type=code&client_id=${\n\t\t\t\t\toptions.clientId\n\t\t\t\t}&redirect_uri=${encodeURIComponent(\n\t\t\t\t\toptions.redirectURI || redirectURI,\n\t\t\t\t)}&state=${state}&prompt=${\n\t\t\t\t\toptions.prompt || \"none\"\n\t\t\t\t}${permissionsParam}`,\n\t\t\t);\n\t\t},\n\t\tvalidateAuthorizationCode: async ({ code, redirectURI }) => {\n\t\t\treturn validateAuthorizationCode({\n\t\t\t\tcode,\n\t\t\t\tredirectURI,\n\t\t\t\toptions,\n\t\t\t\ttokenEndpoint: \"https://discord.com/api/oauth2/token\",\n\t\t\t});\n\t\t},\n\t\trefreshAccessToken: options.refreshAccessToken\n\t\t\t? options.refreshAccessToken\n\t\t\t: async (refreshToken) => {\n\t\t\t\t\treturn refreshAccessToken({\n\t\t\t\t\t\trefreshToken,\n\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\tclientId: options.clientId,\n\t\t\t\t\t\t\tclientKey: options.clientKey,\n\t\t\t\t\t\t\tclientSecret: options.clientSecret,\n\t\t\t\t\t\t},\n\t\t\t\t\t\ttokenEndpoint: \"https://discord.com/api/oauth2/token\",\n\t\t\t\t\t});\n\t\t\t\t},\n\t\tasync getUserInfo(token) {\n\t\t\tif (options.getUserInfo) {\n\t\t\t\treturn options.getUserInfo(token);\n\t\t\t}\n\t\t\tconst { data: profile, error } = await betterFetch<DiscordProfile>(\n\t\t\t\t\"https://discord.com/api/users/@me\",\n\t\t\t\t{\n\t\t\t\t\theaders: {\n\t\t\t\t\t\tauthorization: `Bearer ${token.accessToken}`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tif (error) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tif (profile.avatar === null) {\n\t\t\t\tconst defaultAvatarNumber =\n\t\t\t\t\tprofile.discriminator === \"0\"\n\t\t\t\t\t\t? Number(BigInt(profile.id) >> BigInt(22)) % 6\n\t\t\t\t\t\t: parseInt(profile.discriminator) % 5;\n\t\t\t\tprofile.image_url = `https://cdn.discordapp.com/embed/avatars/${defaultAvatarNumber}.png`;\n\t\t\t} else {\n\t\t\t\tconst format = profile.avatar.startsWith(\"a_\") ? \"gif\" : \"png\";\n\t\t\t\tprofile.image_url = `https://cdn.discordapp.com/avatars/${profile.id}/${profile.avatar}.${format}`;\n\t\t\t}\n\t\t\tconst userMap = await options.mapProfileToUser?.(profile);\n\t\t\treturn {\n\t\t\t\tuser: {\n\t\t\t\t\tid: profile.id,\n\t\t\t\t\tname: profile.global_name || profile.username || \"\",\n\t\t\t\t\temail: profile.email,\n\t\t\t\t\temailVerified: profile.verified,\n\t\t\t\t\timage: profile.image_url,\n\t\t\t\t\t...userMap,\n\t\t\t\t},\n\t\t\t\tdata: profile,\n\t\t\t};\n\t\t},\n\t\toptions,\n\t} satisfies OAuthProvider<DiscordProfile>;\n};\n"],"mappings":";;;;;;AAiFA,MAAa,WAAW,YAA4B;AACnD,QAAO;EACN,IAAI;EACJ,MAAM;EACN,uBAAuB,EAAE,OAAO,QAAQ,eAAe;GACtD,MAAM,UAAU,QAAQ,sBAAsB,EAAE,GAAG,CAAC,YAAY,QAAQ;AACxE,OAAI,OAAQ,SAAQ,KAAK,GAAG,OAAO;AACnC,OAAI,QAAQ,MAAO,SAAQ,KAAK,GAAG,QAAQ,MAAM;GAEjD,MAAM,mBADc,QAAQ,SAAS,MAAM,IAE3B,QAAQ,gBAAgB,SACpC,gBAAgB,QAAQ,gBACxB;AACJ,UAAO,IAAI,IACV,kDAAkD,QAAQ,KACzD,IACA,CAAC,gCACD,QAAQ,SACR,gBAAgB,mBAChB,QAAQ,eAAe,YACvB,CAAC,SAAS,MAAM,UAChB,QAAQ,UAAU,SAChB,mBACH;;EAEF,2BAA2B,OAAO,EAAE,MAAM,kBAAkB;AAC3D,UAAO,0BAA0B;IAChC;IACA;IACA;IACA,eAAe;IACf,CAAC;;EAEH,oBAAoB,QAAQ,qBACzB,QAAQ,qBACR,OAAO,iBAAiB;AACxB,UAAO,mBAAmB;IACzB;IACA,SAAS;KACR,UAAU,QAAQ;KAClB,WAAW,QAAQ;KACnB,cAAc,QAAQ;KACtB;IACD,eAAe;IACf,CAAC;;EAEL,MAAM,YAAY,OAAO;AACxB,OAAI,QAAQ,YACX,QAAO,QAAQ,YAAY,MAAM;GAElC,MAAM,EAAE,MAAM,SAAS,UAAU,MAAM,YACtC,qCACA,EACC,SAAS,EACR,eAAe,UAAU,MAAM,eAC/B,EACD,CACD;AAED,OAAI,MACH,QAAO;AAER,OAAI,QAAQ,WAAW,KAKtB,SAAQ,YAAY,4CAHnB,QAAQ,kBAAkB,MACvB,OAAO,OAAO,QAAQ,GAAG,IAAI,OAAO,GAAG,CAAC,GAAG,IAC3C,SAAS,QAAQ,cAAc,GAAG,EAC8C;QAC9E;IACN,MAAM,SAAS,QAAQ,OAAO,WAAW,KAAK,GAAG,QAAQ;AACzD,YAAQ,YAAY,sCAAsC,QAAQ,GAAG,GAAG,QAAQ,OAAO,GAAG;;GAE3F,MAAM,UAAU,MAAM,QAAQ,mBAAmB,QAAQ;AACzD,UAAO;IACN,MAAM;KACL,IAAI,QAAQ;KACZ,MAAM,QAAQ,eAAe,QAAQ,YAAY;KACjD,OAAO,QAAQ;KACf,eAAe,QAAQ;KACvB,OAAO,QAAQ;KACf,GAAG;KACH;IACD,MAAM;IACN;;EAEF;EACA"}
@@ -68,4 +68,5 @@ declare const dropbox: (options: DropboxOptions) => {
68
68
  options: DropboxOptions;
69
69
  };
70
70
  //#endregion
71
- export { DropboxOptions, DropboxProfile, dropbox };
71
+ export { DropboxOptions, DropboxProfile, dropbox };
72
+ //# sourceMappingURL=dropbox.d.mts.map
@@ -44,7 +44,7 @@ const dropbox = (options) => {
44
44
  clientKey: options.clientKey,
45
45
  clientSecret: options.clientSecret
46
46
  },
47
- tokenEndpoint: "https://api.dropbox.com/oauth2/token"
47
+ tokenEndpoint
48
48
  });
49
49
  },
50
50
  async getUserInfo(token) {
@@ -72,4 +72,5 @@ const dropbox = (options) => {
72
72
  };
73
73
 
74
74
  //#endregion
75
- export { dropbox };
75
+ export { dropbox };
76
+ //# sourceMappingURL=dropbox.mjs.map