@better-auth/core 1.3.27 → 1.3.29

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 (121) hide show
  1. package/.turbo/turbo-build.log +54 -4
  2. package/build.config.ts +6 -0
  3. package/dist/db/adapter/index.d.cts +13 -23
  4. package/dist/db/adapter/index.d.mts +13 -23
  5. package/dist/db/adapter/index.d.ts +13 -23
  6. package/dist/db/index.cjs +16 -0
  7. package/dist/db/index.d.cts +6 -83
  8. package/dist/db/index.d.mts +6 -83
  9. package/dist/db/index.d.ts +6 -83
  10. package/dist/db/index.mjs +16 -1
  11. package/dist/env/index.cjs +312 -0
  12. package/dist/env/index.d.cts +36 -0
  13. package/dist/env/index.d.mts +36 -0
  14. package/dist/env/index.d.ts +36 -0
  15. package/dist/env/index.mjs +297 -0
  16. package/dist/error/index.cjs +44 -0
  17. package/dist/error/index.d.cts +33 -0
  18. package/dist/error/index.d.mts +33 -0
  19. package/dist/error/index.d.ts +33 -0
  20. package/dist/error/index.mjs +41 -0
  21. package/dist/index.d.cts +156 -101
  22. package/dist/index.d.mts +156 -101
  23. package/dist/index.d.ts +156 -101
  24. package/dist/middleware/index.cjs +25 -0
  25. package/dist/middleware/index.d.cts +13 -0
  26. package/dist/middleware/index.d.mts +13 -0
  27. package/dist/middleware/index.d.ts +13 -0
  28. package/dist/middleware/index.mjs +21 -0
  29. package/dist/oauth2/index.cjs +368 -0
  30. package/dist/oauth2/index.d.cts +100 -0
  31. package/dist/oauth2/index.d.mts +100 -0
  32. package/dist/oauth2/index.d.ts +100 -0
  33. package/dist/oauth2/index.mjs +357 -0
  34. package/dist/shared/core.Bl6TpxyD.d.mts +181 -0
  35. package/dist/shared/core.Bqe5IGAi.d.ts +13 -0
  36. package/dist/shared/core.Bshk2o_x.d.ts +1721 -0
  37. package/dist/shared/core.BwoNUcJQ.d.cts +53 -0
  38. package/dist/shared/core.BwoNUcJQ.d.mts +53 -0
  39. package/dist/shared/core.BwoNUcJQ.d.ts +53 -0
  40. package/dist/shared/core.C6_2xGyf.d.mts +1721 -0
  41. package/dist/shared/{core.CnvFgghY.d.cts → core.CajxAutx.d.cts} +27 -1
  42. package/dist/shared/{core.CnvFgghY.d.mts → core.CajxAutx.d.mts} +27 -1
  43. package/dist/shared/{core.CnvFgghY.d.ts → core.CajxAutx.d.ts} +27 -1
  44. package/dist/shared/core.CfqdiZTu.d.cts +1721 -0
  45. package/dist/shared/core.DkdZ1o38.d.ts +181 -0
  46. package/dist/shared/core.Dl-70uns.d.cts +84 -0
  47. package/dist/shared/core.Dl-70uns.d.mts +84 -0
  48. package/dist/shared/core.Dl-70uns.d.ts +84 -0
  49. package/dist/shared/core.DyEdx0m7.d.cts +181 -0
  50. package/dist/shared/core.E9DfzGLz.d.mts +13 -0
  51. package/dist/shared/core.HqYn20Fi.d.cts +13 -0
  52. package/dist/social-providers/index.cjs +2793 -0
  53. package/dist/social-providers/index.d.cts +3903 -0
  54. package/dist/social-providers/index.d.mts +3903 -0
  55. package/dist/social-providers/index.d.ts +3903 -0
  56. package/dist/social-providers/index.mjs +2743 -0
  57. package/dist/utils/index.cjs +7 -0
  58. package/dist/utils/index.d.cts +10 -0
  59. package/dist/utils/index.d.mts +10 -0
  60. package/dist/utils/index.d.ts +10 -0
  61. package/dist/utils/index.mjs +5 -0
  62. package/package.json +98 -2
  63. package/src/db/adapter/index.ts +424 -0
  64. package/src/db/index.ts +2 -0
  65. package/src/db/schema/rate-limit.ts +21 -0
  66. package/src/db/type.ts +28 -0
  67. package/src/env/color-depth.ts +172 -0
  68. package/src/env/env-impl.ts +124 -0
  69. package/src/env/index.ts +23 -0
  70. package/src/env/logger.test.ts +33 -0
  71. package/src/env/logger.ts +145 -0
  72. package/src/error/codes.ts +31 -0
  73. package/src/error/index.ts +11 -0
  74. package/src/index.ts +0 -2
  75. package/src/middleware/index.ts +33 -0
  76. package/src/oauth2/client-credentials-token.ts +102 -0
  77. package/src/oauth2/create-authorization-url.ts +85 -0
  78. package/src/oauth2/index.ts +22 -0
  79. package/src/oauth2/oauth-provider.ts +194 -0
  80. package/src/oauth2/refresh-access-token.ts +124 -0
  81. package/src/oauth2/utils.ts +36 -0
  82. package/src/oauth2/validate-authorization-code.ts +156 -0
  83. package/src/social-providers/apple.ts +213 -0
  84. package/src/social-providers/atlassian.ts +130 -0
  85. package/src/social-providers/cognito.ts +269 -0
  86. package/src/social-providers/discord.ts +172 -0
  87. package/src/social-providers/dropbox.ts +112 -0
  88. package/src/social-providers/facebook.ts +204 -0
  89. package/src/social-providers/figma.ts +115 -0
  90. package/src/social-providers/github.ts +154 -0
  91. package/src/social-providers/gitlab.ts +152 -0
  92. package/src/social-providers/google.ts +171 -0
  93. package/src/social-providers/huggingface.ts +116 -0
  94. package/src/social-providers/index.ts +118 -0
  95. package/src/social-providers/kakao.ts +178 -0
  96. package/src/social-providers/kick.ts +95 -0
  97. package/src/social-providers/line.ts +169 -0
  98. package/src/social-providers/linear.ts +120 -0
  99. package/src/social-providers/linkedin.ts +110 -0
  100. package/src/social-providers/microsoft-entra-id.ts +243 -0
  101. package/src/social-providers/naver.ts +112 -0
  102. package/src/social-providers/notion.ts +106 -0
  103. package/src/social-providers/paypal.ts +261 -0
  104. package/src/social-providers/reddit.ts +122 -0
  105. package/src/social-providers/roblox.ts +110 -0
  106. package/src/social-providers/salesforce.ts +157 -0
  107. package/src/social-providers/slack.ts +114 -0
  108. package/src/social-providers/spotify.ts +93 -0
  109. package/src/social-providers/tiktok.ts +211 -0
  110. package/src/social-providers/twitch.ts +111 -0
  111. package/src/social-providers/twitter.ts +194 -0
  112. package/src/social-providers/vk.ts +128 -0
  113. package/src/social-providers/zoom.ts +218 -0
  114. package/src/types/context.ts +334 -0
  115. package/src/types/cookie.ts +7 -0
  116. package/src/types/index.ts +19 -1
  117. package/src/types/init-options.ts +1048 -2
  118. package/src/types/plugin-client.ts +69 -0
  119. package/src/types/plugin.ts +134 -0
  120. package/src/utils/error-codes.ts +51 -0
  121. package/src/utils/index.ts +1 -0
@@ -0,0 +1,154 @@
1
+ import { betterFetch } from "@better-fetch/fetch";
2
+ import type { OAuthProvider, ProviderOptions } from "@better-auth/core/oauth2";
3
+ import {
4
+ createAuthorizationURL,
5
+ refreshAccessToken,
6
+ validateAuthorizationCode,
7
+ } from "@better-auth/core/oauth2";
8
+
9
+ export interface GithubProfile {
10
+ login: string;
11
+ id: string;
12
+ node_id: string;
13
+ avatar_url: string;
14
+ gravatar_id: string;
15
+ url: string;
16
+ html_url: string;
17
+ followers_url: string;
18
+ following_url: string;
19
+ gists_url: string;
20
+ starred_url: string;
21
+ subscriptions_url: string;
22
+ organizations_url: string;
23
+ repos_url: string;
24
+ events_url: string;
25
+ received_events_url: string;
26
+ type: string;
27
+ site_admin: boolean;
28
+ name: string;
29
+ company: string;
30
+ blog: string;
31
+ location: string;
32
+ email: string;
33
+ hireable: boolean;
34
+ bio: string;
35
+ twitter_username: string;
36
+ public_repos: string;
37
+ public_gists: string;
38
+ followers: string;
39
+ following: string;
40
+ created_at: string;
41
+ updated_at: string;
42
+ private_gists: string;
43
+ total_private_repos: string;
44
+ owned_private_repos: string;
45
+ disk_usage: string;
46
+ collaborators: string;
47
+ two_factor_authentication: boolean;
48
+ plan: {
49
+ name: string;
50
+ space: string;
51
+ private_repos: string;
52
+ collaborators: string;
53
+ };
54
+ }
55
+
56
+ export interface GithubOptions extends ProviderOptions<GithubProfile> {
57
+ clientId: string;
58
+ }
59
+ export const github = (options: GithubOptions) => {
60
+ const tokenEndpoint = "https://github.com/login/oauth/access_token";
61
+ return {
62
+ id: "github",
63
+ name: "GitHub",
64
+ createAuthorizationURL({ state, scopes, loginHint, redirectURI }) {
65
+ const _scopes = options.disableDefaultScope
66
+ ? []
67
+ : ["read:user", "user:email"];
68
+ options.scope && _scopes.push(...options.scope);
69
+ scopes && _scopes.push(...scopes);
70
+ return createAuthorizationURL({
71
+ id: "github",
72
+ options,
73
+ authorizationEndpoint: "https://github.com/login/oauth/authorize",
74
+ scopes: _scopes,
75
+ state,
76
+ redirectURI,
77
+ loginHint,
78
+ prompt: options.prompt,
79
+ });
80
+ },
81
+ validateAuthorizationCode: async ({ code, redirectURI }) => {
82
+ return validateAuthorizationCode({
83
+ code,
84
+ redirectURI,
85
+ options,
86
+ tokenEndpoint,
87
+ });
88
+ },
89
+ refreshAccessToken: options.refreshAccessToken
90
+ ? options.refreshAccessToken
91
+ : async (refreshToken) => {
92
+ return refreshAccessToken({
93
+ refreshToken,
94
+ options: {
95
+ clientId: options.clientId,
96
+ clientKey: options.clientKey,
97
+ clientSecret: options.clientSecret,
98
+ },
99
+ tokenEndpoint: "https://github.com/login/oauth/access_token",
100
+ });
101
+ },
102
+ async getUserInfo(token) {
103
+ if (options.getUserInfo) {
104
+ return options.getUserInfo(token);
105
+ }
106
+ const { data: profile, error } = await betterFetch<GithubProfile>(
107
+ "https://api.github.com/user",
108
+ {
109
+ headers: {
110
+ "User-Agent": "better-auth",
111
+ authorization: `Bearer ${token.accessToken}`,
112
+ },
113
+ },
114
+ );
115
+ if (error) {
116
+ return null;
117
+ }
118
+ const { data: emails } = await betterFetch<
119
+ {
120
+ email: string;
121
+ primary: boolean;
122
+ verified: boolean;
123
+ visibility: "public" | "private";
124
+ }[]
125
+ >("https://api.github.com/user/emails", {
126
+ headers: {
127
+ Authorization: `Bearer ${token.accessToken}`,
128
+ "User-Agent": "better-auth",
129
+ },
130
+ });
131
+
132
+ if (!profile.email && emails) {
133
+ profile.email = (emails.find((e) => e.primary) ?? emails[0])
134
+ ?.email as string;
135
+ }
136
+ const emailVerified =
137
+ emails?.find((e) => e.email === profile.email)?.verified ?? false;
138
+
139
+ const userMap = await options.mapProfileToUser?.(profile);
140
+ return {
141
+ user: {
142
+ id: profile.id,
143
+ name: profile.name || profile.login,
144
+ email: profile.email,
145
+ image: profile.avatar_url,
146
+ emailVerified,
147
+ ...userMap,
148
+ },
149
+ data: profile,
150
+ };
151
+ },
152
+ options,
153
+ } satisfies OAuthProvider<GithubProfile>;
154
+ };
@@ -0,0 +1,152 @@
1
+ import { betterFetch } from "@better-fetch/fetch";
2
+ import type { OAuthProvider, ProviderOptions } from "@better-auth/core/oauth2";
3
+ import {
4
+ createAuthorizationURL,
5
+ validateAuthorizationCode,
6
+ refreshAccessToken,
7
+ } from "@better-auth/core/oauth2";
8
+
9
+ export interface GitlabProfile extends Record<string, any> {
10
+ id: number;
11
+ username: string;
12
+ email: string;
13
+ name: string;
14
+ state: string;
15
+ avatar_url: string;
16
+ web_url: string;
17
+ created_at: string;
18
+ bio: string;
19
+ location?: string;
20
+ public_email: string;
21
+ skype: string;
22
+ linkedin: string;
23
+ twitter: string;
24
+ website_url: string;
25
+ organization: string;
26
+ job_title: string;
27
+ pronouns: string;
28
+ bot: boolean;
29
+ work_information?: string;
30
+ followers: number;
31
+ following: number;
32
+ local_time: string;
33
+ last_sign_in_at: string;
34
+ confirmed_at: string;
35
+ theme_id: number;
36
+ last_activity_on: string;
37
+ color_scheme_id: number;
38
+ projects_limit: number;
39
+ current_sign_in_at: string;
40
+ identities: Array<{
41
+ provider: string;
42
+ extern_uid: string;
43
+ }>;
44
+ can_create_group: boolean;
45
+ can_create_project: boolean;
46
+ two_factor_enabled: boolean;
47
+ external: boolean;
48
+ private_profile: boolean;
49
+ commit_email: string;
50
+ shared_runners_minutes_limit: number;
51
+ extra_shared_runners_minutes_limit: number;
52
+ }
53
+
54
+ export interface GitlabOptions extends ProviderOptions<GitlabProfile> {
55
+ clientId: string;
56
+ issuer?: string;
57
+ }
58
+
59
+ const cleanDoubleSlashes = (input: string = "") => {
60
+ return input
61
+ .split("://")
62
+ .map((str) => str.replace(/\/{2,}/g, "/"))
63
+ .join("://");
64
+ };
65
+
66
+ const issuerToEndpoints = (issuer?: string) => {
67
+ let baseUrl = issuer || "https://gitlab.com";
68
+ return {
69
+ authorizationEndpoint: cleanDoubleSlashes(`${baseUrl}/oauth/authorize`),
70
+ tokenEndpoint: cleanDoubleSlashes(`${baseUrl}/oauth/token`),
71
+ userinfoEndpoint: cleanDoubleSlashes(`${baseUrl}/api/v4/user`),
72
+ };
73
+ };
74
+
75
+ export const gitlab = (options: GitlabOptions) => {
76
+ const { authorizationEndpoint, tokenEndpoint, userinfoEndpoint } =
77
+ issuerToEndpoints(options.issuer);
78
+ const issuerId = "gitlab";
79
+ const issuerName = "Gitlab";
80
+ return {
81
+ id: issuerId,
82
+ name: issuerName,
83
+ createAuthorizationURL: async ({
84
+ state,
85
+ scopes,
86
+ codeVerifier,
87
+ loginHint,
88
+ redirectURI,
89
+ }) => {
90
+ const _scopes = options.disableDefaultScope ? [] : ["read_user"];
91
+ options.scope && _scopes.push(...options.scope);
92
+ scopes && _scopes.push(...scopes);
93
+ return await createAuthorizationURL({
94
+ id: issuerId,
95
+ options,
96
+ authorizationEndpoint,
97
+ scopes: _scopes,
98
+ state,
99
+ redirectURI,
100
+ codeVerifier,
101
+ loginHint,
102
+ });
103
+ },
104
+ validateAuthorizationCode: async ({ code, redirectURI, codeVerifier }) => {
105
+ return validateAuthorizationCode({
106
+ code,
107
+ redirectURI,
108
+ options,
109
+ codeVerifier,
110
+ tokenEndpoint,
111
+ });
112
+ },
113
+ refreshAccessToken: options.refreshAccessToken
114
+ ? options.refreshAccessToken
115
+ : async (refreshToken) => {
116
+ return refreshAccessToken({
117
+ refreshToken,
118
+ options: {
119
+ clientId: options.clientId,
120
+ clientKey: options.clientKey,
121
+ clientSecret: options.clientSecret,
122
+ },
123
+ tokenEndpoint: tokenEndpoint,
124
+ });
125
+ },
126
+ async getUserInfo(token) {
127
+ if (options.getUserInfo) {
128
+ return options.getUserInfo(token);
129
+ }
130
+ const { data: profile, error } = await betterFetch<GitlabProfile>(
131
+ userinfoEndpoint,
132
+ { headers: { authorization: `Bearer ${token.accessToken}` } },
133
+ );
134
+ if (error || profile.state !== "active" || profile.locked) {
135
+ return null;
136
+ }
137
+ const userMap = await options.mapProfileToUser?.(profile);
138
+ return {
139
+ user: {
140
+ id: profile.id,
141
+ name: profile.name ?? profile.username,
142
+ email: profile.email,
143
+ image: profile.avatar_url,
144
+ emailVerified: true,
145
+ ...userMap,
146
+ },
147
+ data: profile,
148
+ };
149
+ },
150
+ options,
151
+ } satisfies OAuthProvider<GitlabProfile>;
152
+ };
@@ -0,0 +1,171 @@
1
+ import { betterFetch } from "@better-fetch/fetch";
2
+ import { decodeJwt } from "jose";
3
+ import { BetterAuthError } from "../error";
4
+ import type { OAuthProvider, ProviderOptions } from "@better-auth/core/oauth2";
5
+ import {
6
+ createAuthorizationURL,
7
+ validateAuthorizationCode,
8
+ } from "@better-auth/core/oauth2";
9
+ import { logger } from "@better-auth/core/env";
10
+ import { refreshAccessToken } from "@better-auth/core/oauth2";
11
+
12
+ export interface GoogleProfile {
13
+ aud: string;
14
+ azp: string;
15
+ email: string;
16
+ email_verified: boolean;
17
+ exp: number;
18
+ /**
19
+ * The family name of the user, or last name in most
20
+ * Western languages.
21
+ */
22
+ family_name: string;
23
+ /**
24
+ * The given name of the user, or first name in most
25
+ * Western languages.
26
+ */
27
+ given_name: string;
28
+ hd?: string;
29
+ iat: number;
30
+ iss: string;
31
+ jti?: string;
32
+ locale?: string;
33
+ name: string;
34
+ nbf?: number;
35
+ picture: string;
36
+ sub: string;
37
+ }
38
+
39
+ export interface GoogleOptions extends ProviderOptions<GoogleProfile> {
40
+ clientId: string;
41
+ /**
42
+ * The access type to use for the authorization code request
43
+ */
44
+ accessType?: "offline" | "online";
45
+ /**
46
+ * The display mode to use for the authorization code request
47
+ */
48
+ display?: "page" | "popup" | "touch" | "wap";
49
+ /**
50
+ * The hosted domain of the user
51
+ */
52
+ hd?: string;
53
+ }
54
+
55
+ export const google = (options: GoogleOptions) => {
56
+ return {
57
+ id: "google",
58
+ name: "Google",
59
+ async createAuthorizationURL({
60
+ state,
61
+ scopes,
62
+ codeVerifier,
63
+ redirectURI,
64
+ loginHint,
65
+ display,
66
+ }) {
67
+ if (!options.clientId || !options.clientSecret) {
68
+ logger.error(
69
+ "Client Id and Client Secret is required for Google. Make sure to provide them in the options.",
70
+ );
71
+ throw new BetterAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
72
+ }
73
+ if (!codeVerifier) {
74
+ throw new BetterAuthError("codeVerifier is required for Google");
75
+ }
76
+ const _scopes = options.disableDefaultScope
77
+ ? []
78
+ : ["email", "profile", "openid"];
79
+ options.scope && _scopes.push(...options.scope);
80
+ scopes && _scopes.push(...scopes);
81
+ const url = await createAuthorizationURL({
82
+ id: "google",
83
+ options,
84
+ authorizationEndpoint: "https://accounts.google.com/o/oauth2/auth",
85
+ scopes: _scopes,
86
+ state,
87
+ codeVerifier,
88
+ redirectURI,
89
+ prompt: options.prompt,
90
+ accessType: options.accessType,
91
+ display: display || options.display,
92
+ loginHint,
93
+ hd: options.hd,
94
+ additionalParams: {
95
+ include_granted_scopes: "true",
96
+ },
97
+ });
98
+ return url;
99
+ },
100
+ validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
101
+ return validateAuthorizationCode({
102
+ code,
103
+ codeVerifier,
104
+ redirectURI,
105
+ options,
106
+ tokenEndpoint: "https://oauth2.googleapis.com/token",
107
+ });
108
+ },
109
+ refreshAccessToken: options.refreshAccessToken
110
+ ? options.refreshAccessToken
111
+ : async (refreshToken) => {
112
+ return refreshAccessToken({
113
+ refreshToken,
114
+ options: {
115
+ clientId: options.clientId,
116
+ clientKey: options.clientKey,
117
+ clientSecret: options.clientSecret,
118
+ },
119
+ tokenEndpoint: "https://www.googleapis.com/oauth2/v4/token",
120
+ });
121
+ },
122
+ async verifyIdToken(token, nonce) {
123
+ if (options.disableIdTokenSignIn) {
124
+ return false;
125
+ }
126
+ if (options.verifyIdToken) {
127
+ return options.verifyIdToken(token, nonce);
128
+ }
129
+ const googlePublicKeyUrl = `https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=${token}`;
130
+ const { data: tokenInfo } = await betterFetch<{
131
+ aud: string;
132
+ iss: string;
133
+ email: string;
134
+ email_verified: boolean;
135
+ name: string;
136
+ picture: string;
137
+ sub: string;
138
+ }>(googlePublicKeyUrl);
139
+ if (!tokenInfo) {
140
+ return false;
141
+ }
142
+ const isValid =
143
+ tokenInfo.aud === options.clientId &&
144
+ (tokenInfo.iss === "https://accounts.google.com" ||
145
+ tokenInfo.iss === "accounts.google.com");
146
+ return isValid;
147
+ },
148
+ async getUserInfo(token) {
149
+ if (options.getUserInfo) {
150
+ return options.getUserInfo(token);
151
+ }
152
+ if (!token.idToken) {
153
+ return null;
154
+ }
155
+ const user = decodeJwt(token.idToken) as GoogleProfile;
156
+ const userMap = await options.mapProfileToUser?.(user);
157
+ return {
158
+ user: {
159
+ id: user.sub,
160
+ name: user.name,
161
+ email: user.email,
162
+ image: user.picture,
163
+ emailVerified: user.email_verified,
164
+ ...userMap,
165
+ },
166
+ data: user,
167
+ };
168
+ },
169
+ options,
170
+ } satisfies OAuthProvider<GoogleProfile>;
171
+ };
@@ -0,0 +1,116 @@
1
+ import { betterFetch } from "@better-fetch/fetch";
2
+ import type { OAuthProvider, ProviderOptions } from "@better-auth/core/oauth2";
3
+ import {
4
+ createAuthorizationURL,
5
+ validateAuthorizationCode,
6
+ refreshAccessToken,
7
+ } from "@better-auth/core/oauth2";
8
+
9
+ export interface HuggingFaceProfile {
10
+ sub: string;
11
+ name: string;
12
+ preferred_username: string;
13
+ profile: string;
14
+ picture: string;
15
+ website?: string;
16
+ email?: string;
17
+ email_verified?: boolean;
18
+ isPro: boolean;
19
+ canPay?: boolean;
20
+ orgs?: {
21
+ sub: string;
22
+ name: string;
23
+ picture: string;
24
+ preferred_username: string;
25
+ isEnterprise: boolean | "plus";
26
+ canPay?: boolean;
27
+ roleInOrg?: "admin" | "write" | "contributor" | "read";
28
+ pendingSSO?: boolean;
29
+ missingMFA?: boolean;
30
+ resourceGroups?: {
31
+ sub: string;
32
+ name: string;
33
+ role: "admin" | "write" | "contributor" | "read";
34
+ }[];
35
+ };
36
+ }
37
+
38
+ export interface HuggingFaceOptions
39
+ extends ProviderOptions<HuggingFaceProfile> {
40
+ clientId: string;
41
+ }
42
+
43
+ export const huggingface = (options: HuggingFaceOptions) => {
44
+ return {
45
+ id: "huggingface",
46
+ name: "Hugging Face",
47
+ createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {
48
+ const _scopes = options.disableDefaultScope
49
+ ? []
50
+ : ["openid", "profile", "email"];
51
+ options.scope && _scopes.push(...options.scope);
52
+ scopes && _scopes.push(...scopes);
53
+ return createAuthorizationURL({
54
+ id: "huggingface",
55
+ options,
56
+ authorizationEndpoint: "https://huggingface.co/oauth/authorize",
57
+ scopes: _scopes,
58
+ state,
59
+ codeVerifier,
60
+ redirectURI,
61
+ });
62
+ },
63
+ validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
64
+ return validateAuthorizationCode({
65
+ code,
66
+ codeVerifier,
67
+ redirectURI,
68
+ options,
69
+ tokenEndpoint: "https://huggingface.co/oauth/token",
70
+ });
71
+ },
72
+ refreshAccessToken: options.refreshAccessToken
73
+ ? options.refreshAccessToken
74
+ : async (refreshToken) => {
75
+ return refreshAccessToken({
76
+ refreshToken,
77
+ options: {
78
+ clientId: options.clientId,
79
+ clientKey: options.clientKey,
80
+ clientSecret: options.clientSecret,
81
+ },
82
+ tokenEndpoint: "https://huggingface.co/oauth/token",
83
+ });
84
+ },
85
+ async getUserInfo(token) {
86
+ if (options.getUserInfo) {
87
+ return options.getUserInfo(token);
88
+ }
89
+ const { data: profile, error } = await betterFetch<HuggingFaceProfile>(
90
+ "https://huggingface.co/oauth/userinfo",
91
+ {
92
+ method: "GET",
93
+ headers: {
94
+ Authorization: `Bearer ${token.accessToken}`,
95
+ },
96
+ },
97
+ );
98
+ if (error) {
99
+ return null;
100
+ }
101
+ const userMap = await options.mapProfileToUser?.(profile);
102
+ return {
103
+ user: {
104
+ id: profile.sub,
105
+ name: profile.name || profile.preferred_username,
106
+ email: profile.email,
107
+ image: profile.picture,
108
+ emailVerified: profile.email_verified ?? false,
109
+ ...userMap,
110
+ },
111
+ data: profile,
112
+ };
113
+ },
114
+ options,
115
+ } satisfies OAuthProvider<HuggingFaceProfile>;
116
+ };
@@ -0,0 +1,118 @@
1
+ import * as z from "zod";
2
+ import { apple } from "./apple";
3
+ import { atlassian } from "./atlassian";
4
+ import { cognito } from "./cognito";
5
+ import { discord } from "./discord";
6
+ import { facebook } from "./facebook";
7
+ import { figma } from "./figma";
8
+ import { github } from "./github";
9
+ import { google } from "./google";
10
+ import { kick } from "./kick";
11
+ import { huggingface } from "./huggingface";
12
+ import { microsoft } from "./microsoft-entra-id";
13
+ import { slack } from "./slack";
14
+ import { notion } from "./notion";
15
+ import { spotify } from "./spotify";
16
+ import { twitch } from "./twitch";
17
+ import { twitter } from "./twitter";
18
+ import { dropbox } from "./dropbox";
19
+ import { linear } from "./linear";
20
+ import { linkedin } from "./linkedin";
21
+ import { gitlab } from "./gitlab";
22
+ import { tiktok } from "./tiktok";
23
+ import { reddit } from "./reddit";
24
+ import { roblox } from "./roblox";
25
+ import { salesforce } from "./salesforce";
26
+ import { vk } from "./vk";
27
+ import { zoom } from "./zoom";
28
+ import { kakao } from "./kakao";
29
+ import { naver } from "./naver";
30
+ import { line } from "./line";
31
+ import { paypal } from "./paypal";
32
+
33
+ export const socialProviders = {
34
+ apple,
35
+ atlassian,
36
+ cognito,
37
+ discord,
38
+ facebook,
39
+ figma,
40
+ github,
41
+ microsoft,
42
+ google,
43
+ huggingface,
44
+ slack,
45
+ spotify,
46
+ twitch,
47
+ twitter,
48
+ dropbox,
49
+ kick,
50
+ linear,
51
+ linkedin,
52
+ gitlab,
53
+ tiktok,
54
+ reddit,
55
+ roblox,
56
+ salesforce,
57
+ vk,
58
+ zoom,
59
+ notion,
60
+ kakao,
61
+ naver,
62
+ line,
63
+ paypal,
64
+ };
65
+
66
+ export const socialProviderList = Object.keys(socialProviders) as [
67
+ "github",
68
+ ...(keyof typeof socialProviders)[],
69
+ ];
70
+
71
+ export const SocialProviderListEnum = z
72
+ .enum(socialProviderList)
73
+ .or(z.string()) as z.ZodType<SocialProviderList[number] | (string & {})>;
74
+
75
+ export type SocialProvider = z.infer<typeof SocialProviderListEnum>;
76
+
77
+ export type SocialProviders = {
78
+ [K in SocialProviderList[number]]?: Parameters<
79
+ (typeof socialProviders)[K]
80
+ >[0] & {
81
+ enabled?: boolean;
82
+ };
83
+ };
84
+
85
+ export * from "./apple";
86
+ export * from "./atlassian";
87
+ export * from "./cognito";
88
+ export * from "./discord";
89
+ export * from "./dropbox";
90
+ export * from "./facebook";
91
+ export * from "./figma";
92
+ export * from "./github";
93
+ export * from "./linear";
94
+ export * from "./linkedin";
95
+ export * from "./gitlab";
96
+ export * from "./google";
97
+ export * from "./kick";
98
+ export * from "./linkedin";
99
+ export * from "./microsoft-entra-id";
100
+ export * from "./notion";
101
+ export * from "./reddit";
102
+ export * from "./roblox";
103
+ export * from "./salesforce";
104
+ export * from "./spotify";
105
+ export * from "./tiktok";
106
+ export * from "./twitch";
107
+ export * from "./twitter";
108
+ export * from "./vk";
109
+ export * from "./zoom";
110
+ export * from "./kick";
111
+ export * from "./huggingface";
112
+ export * from "./slack";
113
+ export * from "./kakao";
114
+ export * from "./naver";
115
+ export * from "./line";
116
+ export * from "./paypal";
117
+
118
+ export type SocialProviderList = typeof socialProviderList;