@better-auth/core 1.7.0-beta.4 → 1.7.0-beta.5
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.
- package/dist/api/index.d.mts +3 -3
- package/dist/context/global.mjs +1 -1
- package/dist/db/adapter/factory.mjs +2 -2
- package/dist/db/get-tables.mjs +3 -3
- package/dist/db/schema/account.d.mts +1 -1
- package/dist/db/schema/account.mjs +1 -1
- package/dist/env/env-impl.mjs +1 -1
- package/dist/error/codes.d.mts +5 -0
- package/dist/error/codes.mjs +5 -0
- package/dist/index.d.mts +2 -2
- package/dist/instrumentation/tracer.mjs +1 -1
- package/dist/oauth2/create-authorization-url.d.mts +4 -1
- package/dist/oauth2/create-authorization-url.mjs +5 -2
- package/dist/oauth2/index.d.mts +4 -2
- package/dist/oauth2/index.mjs +3 -1
- package/dist/oauth2/oauth-provider.d.mts +128 -9
- package/dist/oauth2/refresh-access-token.mjs +1 -1
- package/dist/oauth2/scopes.d.mts +76 -0
- package/dist/oauth2/scopes.mjs +96 -0
- package/dist/oauth2/utils.mjs +2 -1
- package/dist/oauth2/verify-id-token.d.mts +26 -0
- package/dist/oauth2/verify-id-token.mjs +62 -0
- package/dist/oauth2/verify.d.mts +14 -0
- package/dist/oauth2/verify.mjs +23 -7
- package/dist/social-providers/apple.d.mts +14 -2
- package/dist/social-providers/apple.mjs +12 -36
- package/dist/social-providers/atlassian.d.mts +5 -1
- package/dist/social-providers/atlassian.mjs +4 -4
- package/dist/social-providers/cognito.d.mts +13 -2
- package/dist/social-providers/cognito.mjs +24 -32
- package/dist/social-providers/discord.d.mts +5 -1
- package/dist/social-providers/discord.mjs +7 -6
- package/dist/social-providers/dropbox.d.mts +5 -1
- package/dist/social-providers/dropbox.mjs +5 -5
- package/dist/social-providers/facebook.d.mts +21 -2
- package/dist/social-providers/facebook.mjs +46 -22
- package/dist/social-providers/figma.d.mts +5 -1
- package/dist/social-providers/figma.mjs +5 -5
- package/dist/social-providers/github.d.mts +5 -1
- package/dist/social-providers/github.mjs +4 -4
- package/dist/social-providers/gitlab.d.mts +5 -1
- package/dist/social-providers/gitlab.mjs +6 -6
- package/dist/social-providers/google.d.mts +29 -3
- package/dist/social-providers/google.mjs +24 -30
- package/dist/social-providers/huggingface.d.mts +5 -1
- package/dist/social-providers/huggingface.mjs +8 -8
- package/dist/social-providers/index.d.mts +221 -42
- package/dist/social-providers/kakao.d.mts +5 -1
- package/dist/social-providers/kakao.mjs +8 -8
- package/dist/social-providers/kick.d.mts +5 -1
- package/dist/social-providers/kick.mjs +4 -4
- package/dist/social-providers/line.d.mts +8 -2
- package/dist/social-providers/line.mjs +12 -14
- package/dist/social-providers/linear.d.mts +5 -1
- package/dist/social-providers/linear.mjs +4 -4
- package/dist/social-providers/linkedin.d.mts +5 -1
- package/dist/social-providers/linkedin.mjs +10 -10
- package/dist/social-providers/microsoft-entra-id.d.mts +31 -6
- package/dist/social-providers/microsoft-entra-id.mjs +26 -37
- package/dist/social-providers/naver.d.mts +5 -1
- package/dist/social-providers/naver.mjs +4 -4
- package/dist/social-providers/notion.d.mts +5 -1
- package/dist/social-providers/notion.mjs +4 -4
- package/dist/social-providers/paybin.d.mts +5 -1
- package/dist/social-providers/paybin.mjs +10 -10
- package/dist/social-providers/paypal.d.mts +5 -2
- package/dist/social-providers/paypal.mjs +8 -13
- package/dist/social-providers/polar.d.mts +5 -1
- package/dist/social-providers/polar.mjs +8 -8
- package/dist/social-providers/railway.d.mts +5 -1
- package/dist/social-providers/railway.mjs +9 -9
- package/dist/social-providers/reddit.d.mts +5 -1
- package/dist/social-providers/reddit.mjs +9 -8
- package/dist/social-providers/roblox.d.mts +5 -1
- package/dist/social-providers/roblox.mjs +5 -5
- package/dist/social-providers/salesforce.d.mts +5 -1
- package/dist/social-providers/salesforce.mjs +8 -8
- package/dist/social-providers/slack.d.mts +5 -1
- package/dist/social-providers/slack.mjs +9 -9
- package/dist/social-providers/spotify.d.mts +5 -1
- package/dist/social-providers/spotify.mjs +5 -5
- package/dist/social-providers/tiktok.d.mts +5 -1
- package/dist/social-providers/tiktok.mjs +9 -5
- package/dist/social-providers/twitch.d.mts +5 -1
- package/dist/social-providers/twitch.mjs +4 -4
- package/dist/social-providers/twitter.d.mts +6 -4
- package/dist/social-providers/twitter.mjs +9 -9
- package/dist/social-providers/vercel.d.mts +5 -1
- package/dist/social-providers/vercel.mjs +4 -7
- package/dist/social-providers/vk.d.mts +5 -1
- package/dist/social-providers/vk.mjs +5 -5
- package/dist/social-providers/wechat.d.mts +5 -1
- package/dist/social-providers/wechat.mjs +9 -5
- package/dist/social-providers/zoom.d.mts +6 -1
- package/dist/social-providers/zoom.mjs +15 -9
- package/dist/types/context.d.mts +10 -8
- package/dist/types/index.d.mts +1 -1
- package/dist/types/init-options.d.mts +92 -1
- package/package.json +5 -5
- package/src/db/adapter/factory.ts +10 -2
- package/src/db/get-tables.ts +8 -3
- package/src/db/schema/account.ts +14 -2
- package/src/env/env-impl.ts +1 -2
- package/src/error/codes.ts +5 -0
- package/src/oauth2/create-authorization-url.ts +2 -2
- package/src/oauth2/index.ts +17 -1
- package/src/oauth2/oauth-provider.ts +140 -10
- package/src/oauth2/refresh-access-token.ts +2 -2
- package/src/oauth2/scopes.ts +118 -0
- package/src/oauth2/utils.ts +2 -5
- package/src/oauth2/verify-id-token.ts +111 -0
- package/src/oauth2/verify.ts +62 -11
- package/src/social-providers/apple.ts +24 -61
- package/src/social-providers/atlassian.ts +12 -8
- package/src/social-providers/cognito.ts +25 -47
- package/src/social-providers/discord.ts +19 -8
- package/src/social-providers/dropbox.ts +13 -7
- package/src/social-providers/facebook.ts +97 -51
- package/src/social-providers/figma.ts +13 -9
- package/src/social-providers/github.ts +12 -8
- package/src/social-providers/gitlab.ts +14 -8
- package/src/social-providers/google.ts +66 -47
- package/src/social-providers/huggingface.ts +12 -8
- package/src/social-providers/kakao.ts +16 -8
- package/src/social-providers/kick.ts +12 -7
- package/src/social-providers/line.ts +37 -37
- package/src/social-providers/linear.ts +12 -6
- package/src/social-providers/linkedin.ts +14 -10
- package/src/social-providers/microsoft-entra-id.ts +65 -64
- package/src/social-providers/naver.ts +12 -6
- package/src/social-providers/notion.ts +12 -6
- package/src/social-providers/paybin.ts +14 -11
- package/src/social-providers/paypal.ts +6 -25
- package/src/social-providers/polar.ts +12 -8
- package/src/social-providers/railway.ts +13 -9
- package/src/social-providers/reddit.ts +21 -10
- package/src/social-providers/roblox.ts +18 -7
- package/src/social-providers/salesforce.ts +12 -8
- package/src/social-providers/slack.ts +18 -9
- package/src/social-providers/spotify.ts +13 -7
- package/src/social-providers/tiktok.ts +13 -7
- package/src/social-providers/twitch.ts +12 -8
- package/src/social-providers/twitter.ts +17 -8
- package/src/social-providers/vercel.ts +16 -10
- package/src/social-providers/vk.ts +13 -7
- package/src/social-providers/wechat.ts +20 -8
- package/src/social-providers/zoom.ts +19 -6
- package/src/types/context.ts +8 -8
- package/src/types/index.ts +7 -0
- package/src/types/init-options.ts +119 -0
|
@@ -14,6 +14,7 @@ interface VercelOptions extends ProviderOptions<VercelProfile> {
|
|
|
14
14
|
declare const vercel: (options: VercelOptions) => {
|
|
15
15
|
id: "vercel";
|
|
16
16
|
name: string;
|
|
17
|
+
callbackPath: string;
|
|
17
18
|
createAuthorizationURL({
|
|
18
19
|
state,
|
|
19
20
|
scopes,
|
|
@@ -28,7 +29,10 @@ declare const vercel: (options: VercelOptions) => {
|
|
|
28
29
|
display?: string | undefined;
|
|
29
30
|
loginHint?: string | undefined;
|
|
30
31
|
additionalParams?: Record<string, string> | undefined;
|
|
31
|
-
}): Promise<
|
|
32
|
+
}): Promise<{
|
|
33
|
+
url: URL;
|
|
34
|
+
requestedScopes: string[];
|
|
35
|
+
}>;
|
|
32
36
|
validateAuthorizationCode: ({
|
|
33
37
|
code,
|
|
34
38
|
codeVerifier,
|
|
@@ -1,25 +1,22 @@
|
|
|
1
1
|
import { BetterAuthError } from "../error/index.mjs";
|
|
2
|
+
import { resolveRequestedScopes } from "../oauth2/scopes.mjs";
|
|
2
3
|
import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
|
|
3
4
|
import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
|
|
4
5
|
import { betterFetch } from "@better-fetch/fetch";
|
|
5
6
|
//#region src/social-providers/vercel.ts
|
|
7
|
+
const VERCEL_DEFAULT_SCOPES = [];
|
|
6
8
|
const vercel = (options) => {
|
|
7
9
|
return {
|
|
8
10
|
id: "vercel",
|
|
9
11
|
name: "Vercel",
|
|
12
|
+
callbackPath: "/callback/vercel",
|
|
10
13
|
createAuthorizationURL({ state, scopes, codeVerifier, redirectURI, additionalParams }) {
|
|
11
14
|
if (!codeVerifier) throw new BetterAuthError("codeVerifier is required for Vercel");
|
|
12
|
-
let _scopes = void 0;
|
|
13
|
-
if (options.scope !== void 0 || scopes !== void 0) {
|
|
14
|
-
_scopes = [];
|
|
15
|
-
if (options.scope) _scopes.push(...options.scope);
|
|
16
|
-
if (scopes) _scopes.push(...scopes);
|
|
17
|
-
}
|
|
18
15
|
return createAuthorizationURL({
|
|
19
16
|
id: "vercel",
|
|
20
17
|
options,
|
|
21
18
|
authorizationEndpoint: "https://vercel.com/oauth/authorize",
|
|
22
|
-
scopes:
|
|
19
|
+
scopes: resolveRequestedScopes(options, VERCEL_DEFAULT_SCOPES, scopes),
|
|
23
20
|
state,
|
|
24
21
|
codeVerifier,
|
|
25
22
|
redirectURI,
|
|
@@ -20,6 +20,7 @@ interface VkOption extends ProviderOptions {
|
|
|
20
20
|
declare const vk: (options: VkOption) => {
|
|
21
21
|
id: "vk";
|
|
22
22
|
name: string;
|
|
23
|
+
callbackPath: string;
|
|
23
24
|
createAuthorizationURL({
|
|
24
25
|
state,
|
|
25
26
|
scopes,
|
|
@@ -34,7 +35,10 @@ declare const vk: (options: VkOption) => {
|
|
|
34
35
|
display?: string | undefined;
|
|
35
36
|
loginHint?: string | undefined;
|
|
36
37
|
additionalParams?: Record<string, string> | undefined;
|
|
37
|
-
}): Promise<
|
|
38
|
+
}): Promise<{
|
|
39
|
+
url: URL;
|
|
40
|
+
requestedScopes: string[];
|
|
41
|
+
}>;
|
|
38
42
|
validateAuthorizationCode: ({
|
|
39
43
|
code,
|
|
40
44
|
codeVerifier,
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
+
import { resolveRequestedScopes } from "../oauth2/scopes.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 { betterFetch } from "@better-fetch/fetch";
|
|
5
6
|
//#region src/social-providers/vk.ts
|
|
7
|
+
const VK_DEFAULT_SCOPES = ["email", "phone"];
|
|
6
8
|
const vk = (options) => {
|
|
7
9
|
const tokenEndpoint = "https://id.vk.com/oauth2/auth";
|
|
8
10
|
return {
|
|
9
11
|
id: "vk",
|
|
10
12
|
name: "VK",
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
if (options.scope) _scopes.push(...options.scope);
|
|
14
|
-
if (scopes) _scopes.push(...scopes);
|
|
13
|
+
callbackPath: "/callback/vk",
|
|
14
|
+
createAuthorizationURL({ state, scopes, codeVerifier, redirectURI, additionalParams }) {
|
|
15
15
|
return createAuthorizationURL({
|
|
16
16
|
id: "vk",
|
|
17
17
|
options,
|
|
18
18
|
authorizationEndpoint: "https://id.vk.com/authorize",
|
|
19
|
-
scopes:
|
|
19
|
+
scopes: resolveRequestedScopes(options, VK_DEFAULT_SCOPES, scopes),
|
|
20
20
|
state,
|
|
21
21
|
redirectURI,
|
|
22
22
|
codeVerifier,
|
|
@@ -53,6 +53,7 @@ interface WeChatOptions extends ProviderOptions<WeChatProfile> {
|
|
|
53
53
|
declare const wechat: (options: WeChatOptions) => {
|
|
54
54
|
id: "wechat";
|
|
55
55
|
name: string;
|
|
56
|
+
callbackPath: string;
|
|
56
57
|
createAuthorizationURL({
|
|
57
58
|
state,
|
|
58
59
|
scopes,
|
|
@@ -66,7 +67,10 @@ declare const wechat: (options: WeChatOptions) => {
|
|
|
66
67
|
display?: string | undefined;
|
|
67
68
|
loginHint?: string | undefined;
|
|
68
69
|
additionalParams?: Record<string, string> | undefined;
|
|
69
|
-
}):
|
|
70
|
+
}): {
|
|
71
|
+
url: URL;
|
|
72
|
+
requestedScopes: string[];
|
|
73
|
+
};
|
|
70
74
|
validateAuthorizationCode: ({
|
|
71
75
|
code
|
|
72
76
|
}: {
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
+
import { resolveRequestedScopes } from "../oauth2/scopes.mjs";
|
|
1
2
|
import { RESERVED_AUTHORIZATION_PARAMS_SET } from "../oauth2/create-authorization-url.mjs";
|
|
2
3
|
import { betterFetch } from "@better-fetch/fetch";
|
|
3
4
|
//#region src/social-providers/wechat.ts
|
|
5
|
+
const WECHAT_DEFAULT_SCOPES = ["snsapi_login"];
|
|
4
6
|
const wechat = (options) => {
|
|
5
7
|
return {
|
|
6
8
|
id: "wechat",
|
|
7
9
|
name: "WeChat",
|
|
10
|
+
callbackPath: "/callback/wechat",
|
|
8
11
|
createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) {
|
|
9
|
-
const
|
|
10
|
-
options.scope && _scopes.push(...options.scope);
|
|
11
|
-
scopes && _scopes.push(...scopes);
|
|
12
|
+
const requestedScopes = resolveRequestedScopes(options, WECHAT_DEFAULT_SCOPES, scopes);
|
|
12
13
|
const url = new URL("https://open.weixin.qq.com/connect/qrconnect");
|
|
13
|
-
url.searchParams.set("scope",
|
|
14
|
+
url.searchParams.set("scope", requestedScopes.join(","));
|
|
14
15
|
url.searchParams.set("response_type", "code");
|
|
15
16
|
url.searchParams.set("appid", options.clientId);
|
|
16
17
|
url.searchParams.set("redirect_uri", options.redirectURI || redirectURI);
|
|
@@ -22,7 +23,10 @@ const wechat = (options) => {
|
|
|
22
23
|
url.searchParams.set(key, value);
|
|
23
24
|
}
|
|
24
25
|
url.hash = "wechat_redirect";
|
|
25
|
-
return
|
|
26
|
+
return {
|
|
27
|
+
url,
|
|
28
|
+
requestedScopes
|
|
29
|
+
};
|
|
26
30
|
},
|
|
27
31
|
validateAuthorizationCode: async ({ code }) => {
|
|
28
32
|
const { data: tokenData, error } = await betterFetch("https://api.weixin.qq.com/sns/oauth2/access_token?" + new URLSearchParams({
|
|
@@ -116,8 +116,10 @@ interface ZoomOptions extends ProviderOptions<ZoomProfile> {
|
|
|
116
116
|
declare const zoom: (userOptions: ZoomOptions) => {
|
|
117
117
|
id: "zoom";
|
|
118
118
|
name: string;
|
|
119
|
+
callbackPath: string;
|
|
119
120
|
createAuthorizationURL: ({
|
|
120
121
|
state,
|
|
122
|
+
scopes,
|
|
121
123
|
redirectURI,
|
|
122
124
|
codeVerifier,
|
|
123
125
|
additionalParams
|
|
@@ -129,7 +131,10 @@ declare const zoom: (userOptions: ZoomOptions) => {
|
|
|
129
131
|
display?: string | undefined;
|
|
130
132
|
loginHint?: string | undefined;
|
|
131
133
|
additionalParams?: Record<string, string> | undefined;
|
|
132
|
-
}) => Promise<
|
|
134
|
+
}) => Promise<{
|
|
135
|
+
url: URL;
|
|
136
|
+
requestedScopes: string[];
|
|
137
|
+
}>;
|
|
133
138
|
validateAuthorizationCode: ({
|
|
134
139
|
code,
|
|
135
140
|
redirectURI,
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { resolveRequestedScopes } from "../oauth2/scopes.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 { betterFetch } from "@better-fetch/fetch";
|
|
5
6
|
//#region src/social-providers/zoom.ts
|
|
7
|
+
const ZOOM_DEFAULT_SCOPES = [];
|
|
6
8
|
const zoom = (userOptions) => {
|
|
7
9
|
const options = {
|
|
8
10
|
pkce: true,
|
|
@@ -11,15 +13,19 @@ const zoom = (userOptions) => {
|
|
|
11
13
|
return {
|
|
12
14
|
id: "zoom",
|
|
13
15
|
name: "Zoom",
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
callbackPath: "/callback/zoom",
|
|
17
|
+
createAuthorizationURL: ({ state, scopes, redirectURI, codeVerifier, additionalParams }) => {
|
|
18
|
+
return createAuthorizationURL({
|
|
19
|
+
id: "zoom",
|
|
20
|
+
options,
|
|
21
|
+
authorizationEndpoint: "https://zoom.us/oauth/authorize",
|
|
22
|
+
scopes: resolveRequestedScopes(options, ZOOM_DEFAULT_SCOPES, scopes),
|
|
23
|
+
state,
|
|
24
|
+
redirectURI,
|
|
25
|
+
codeVerifier: options.pkce ? codeVerifier : void 0,
|
|
26
|
+
additionalParams
|
|
27
|
+
});
|
|
28
|
+
},
|
|
23
29
|
validateAuthorizationCode: async ({ code, redirectURI, codeVerifier }) => {
|
|
24
30
|
return validateAuthorizationCode({
|
|
25
31
|
code,
|
package/dist/types/context.d.mts
CHANGED
|
@@ -6,11 +6,11 @@ import { Verification } from "../db/schema/verification.mjs";
|
|
|
6
6
|
import { createLogger } from "../env/logger.mjs";
|
|
7
7
|
import { Awaitable, LiteralString } from "./helper.mjs";
|
|
8
8
|
import { BetterAuthPlugin } from "./plugin.mjs";
|
|
9
|
-
import { BetterAuthOptions, BetterAuthRateLimitOptions } from "./init-options.mjs";
|
|
9
|
+
import { BetterAuthOptions, BetterAuthRateLimitOptions, UserProvisioningSource } from "./init-options.mjs";
|
|
10
10
|
import { Account } from "../db/schema/account.mjs";
|
|
11
11
|
import { BetterAuthCookie, BetterAuthCookies } from "./cookie.mjs";
|
|
12
12
|
import { SecretConfig } from "./secret.mjs";
|
|
13
|
-
import {
|
|
13
|
+
import { UpstreamProvider } from "../oauth2/oauth-provider.mjs";
|
|
14
14
|
import { CookieOptions, EndpointContext } from "better-call";
|
|
15
15
|
|
|
16
16
|
//#region src/types/context.d.ts
|
|
@@ -54,11 +54,13 @@ type GenericEndpointContext<Options extends BetterAuthOptions = BetterAuthOption
|
|
|
54
54
|
context: AuthContext<Options>;
|
|
55
55
|
};
|
|
56
56
|
interface InternalAdapter<_Options extends BetterAuthOptions = BetterAuthOptions> {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
createUser<T extends Record<string, any>>(user: Omit<User, "id" | "createdAt" | "updatedAt" | "emailVerified"> & Partial<User> & Record<string, any>,
|
|
58
|
+
/**
|
|
59
|
+
* Provisioning source. The creation seam adds `action: "create-user"` and
|
|
60
|
+
* runs the `user.validateUserInfo` gate.
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
source: UserProvisioningSource): Promise<T & User>;
|
|
62
64
|
createAccount<T extends Record<string, any>>(account: Omit<Account, "id" | "createdAt" | "updatedAt"> & Partial<Account> & T): Promise<T & Account>;
|
|
63
65
|
listSessions(userId: string, options?: {
|
|
64
66
|
onlyActiveSessions?: boolean | undefined;
|
|
@@ -213,7 +215,7 @@ type AuthContext<Options extends BetterAuthOptions = BetterAuthOptions> = Plugin
|
|
|
213
215
|
session: Session & Record<string, any>;
|
|
214
216
|
user: User & Record<string, any>;
|
|
215
217
|
} | null) => void;
|
|
216
|
-
socialProviders:
|
|
218
|
+
socialProviders: UpstreamProvider[];
|
|
217
219
|
authCookies: BetterAuthCookies;
|
|
218
220
|
logger: ReturnType<typeof createLogger>;
|
|
219
221
|
rateLimit: {
|
package/dist/types/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Awaitable, AwaitableFunction, LiteralString, LiteralUnion, Prettify, Primitive, UnionToIntersection } from "./helper.mjs";
|
|
2
2
|
import { BetterAuthPlugin, BetterAuthPluginErrorCodePart, HookEndpointContext } from "./plugin.mjs";
|
|
3
|
-
import { BaseURLConfig, BetterAuthAdvancedOptions, BetterAuthDBOptions, BetterAuthOptions, BetterAuthRateLimitOptions, BetterAuthRateLimitRule, BetterAuthRateLimitStorage, DynamicBaseURLConfig, GenerateIdFn, StoreIdentifierOption } from "./init-options.mjs";
|
|
3
|
+
import { BaseURLConfig, BetterAuthAdvancedOptions, BetterAuthDBOptions, BetterAuthOptions, BetterAuthRateLimitOptions, BetterAuthRateLimitRule, BetterAuthRateLimitStorage, DynamicBaseURLConfig, GenerateIdFn, StoreIdentifierOption, UserProvisioningSource, ValidateUserInfoAction, ValidateUserInfoMethod, ValidateUserInfoOAuthInfo, ValidateUserInfoResult, ValidateUserInfoSSOInfo, ValidateUserInfoSource } from "./init-options.mjs";
|
|
4
4
|
import { BetterAuthCookie, BetterAuthCookies } from "./cookie.mjs";
|
|
5
5
|
import { SecretConfig } from "./secret.mjs";
|
|
6
6
|
import { AuthContext, BetterAuthPluginRegistry, BetterAuthPluginRegistryIdentifier, GenericEndpointContext, InfoContext, InternalAdapter, PluginContext } from "./context.mjs";
|
|
@@ -27,6 +27,73 @@ type GenerateIdFn = (options: {
|
|
|
27
27
|
model: ModelNames;
|
|
28
28
|
size?: number | undefined;
|
|
29
29
|
}) => string | false;
|
|
30
|
+
/**
|
|
31
|
+
* What Better Auth is about to do with an incoming identity when
|
|
32
|
+
* {@link BetterAuthOptions.user}'s `validateUserInfo` runs.
|
|
33
|
+
*
|
|
34
|
+
* - `create-user`: a brand-new user record is about to be created.
|
|
35
|
+
* - `link-account`: a new provider account is about to be linked to an
|
|
36
|
+
* already-existing user.
|
|
37
|
+
* - `sign-in`: an existing OAuth or SSO user is signing in again. This is the
|
|
38
|
+
* one case where the provider can assert *changed* data, so the hook receives
|
|
39
|
+
* the fresh provider email and profile (not the stored row), letting a domain
|
|
40
|
+
* or org policy reject a user whose provider identity moved out of bounds.
|
|
41
|
+
*
|
|
42
|
+
* Non-provider returning sign-ins are not re-validated: they carry only the
|
|
43
|
+
* stored row, which has not changed since `create-user` gated it. Use the admin
|
|
44
|
+
* plugin's ban controls or a `databaseHooks.session.create.before` hook to
|
|
45
|
+
* block those.
|
|
46
|
+
*/
|
|
47
|
+
type ValidateUserInfoAction = "create-user" | "link-account" | "sign-in";
|
|
48
|
+
/**
|
|
49
|
+
* The authentication method that produced the incoming user info. The named
|
|
50
|
+
* methods cover Better Auth's built-ins; the open `string` keeps it extensible
|
|
51
|
+
* for plugins (for example `"scim"`).
|
|
52
|
+
*/
|
|
53
|
+
type ValidateUserInfoMethod = "oauth" | "sso-oidc" | "sso-saml" | "email-password" | "magic-link" | "email-otp" | "anonymous" | "siwe" | "phone-number" | "admin" | (string & {});
|
|
54
|
+
/** OAuth-specific provisioning context; present only when `method` is `"oauth"`. */
|
|
55
|
+
type ValidateUserInfoOAuthInfo = {
|
|
56
|
+
/** The social or generic OAuth provider id (e.g. `"google"`). */providerId: string; /** The raw provider profile (userinfo or id-token claims), unmapped. */
|
|
57
|
+
profile?: Record<string, unknown> | undefined;
|
|
58
|
+
};
|
|
59
|
+
/** SSO-specific provisioning context; present for OIDC and SAML SSO methods. */
|
|
60
|
+
type ValidateUserInfoSSOInfo = {
|
|
61
|
+
/** The configured SSO provider id. */providerId: string; /** The raw OIDC claims or SAML assertion attributes, unmapped. */
|
|
62
|
+
profile?: Record<string, unknown> | undefined;
|
|
63
|
+
};
|
|
64
|
+
/** Provisioning origin passed to `createUser`; the creation seam adds `action: "create-user"` to build {@link ValidateUserInfoSource}. */
|
|
65
|
+
type UserProvisioningSource = {
|
|
66
|
+
method: ValidateUserInfoMethod; /** Provider id and raw profile; present iff `method` is `"oauth"`. */
|
|
67
|
+
oauth?: ValidateUserInfoOAuthInfo | undefined; /** Provider id and raw profile; present iff `method` is `"sso-oidc"` or `"sso-saml"`. */
|
|
68
|
+
sso?: ValidateUserInfoSSOInfo | undefined;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* The context passed to `validateUserInfo`: the lifecycle
|
|
72
|
+
* {@link ValidateUserInfoAction}, the {@link ValidateUserInfoMethod}, and (for
|
|
73
|
+
* OAuth/SSO provider methods) protocol-specific provider metadata.
|
|
74
|
+
*
|
|
75
|
+
* ```ts
|
|
76
|
+
* // Scope to one OAuth provider:
|
|
77
|
+
* if (source.oauth?.providerId !== "google") return;
|
|
78
|
+
* // Branch on the method:
|
|
79
|
+
* if (source.method === "anonymous") return { error: "no_anonymous" };
|
|
80
|
+
* // Inspect SSO claims:
|
|
81
|
+
* if (source.method === "sso-saml" && source.sso?.profile?.department !== "eng") {
|
|
82
|
+
* return { error: "invalid_department" };
|
|
83
|
+
* }
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
type ValidateUserInfoSource = UserProvisioningSource & {
|
|
87
|
+
action: ValidateUserInfoAction;
|
|
88
|
+
};
|
|
89
|
+
type ValidateUserInfoResult = {
|
|
90
|
+
/** A short, machine-readable rejection code, surfaced to the client. */error: string;
|
|
91
|
+
/**
|
|
92
|
+
* A human-readable reason, surfaced to the client. Do not put sensitive
|
|
93
|
+
* details here.
|
|
94
|
+
*/
|
|
95
|
+
errorDescription?: string | undefined;
|
|
96
|
+
};
|
|
30
97
|
/**
|
|
31
98
|
* Configuration for dynamic base URL resolution.
|
|
32
99
|
* Allows Better Auth to work with multiple domains (e.g., Vercel preview deployments).
|
|
@@ -684,6 +751,30 @@ type BetterAuthOptions = {
|
|
|
684
751
|
* User configuration
|
|
685
752
|
*/
|
|
686
753
|
user?: (BetterAuthDBOptions<"user", keyof BaseUser> & {
|
|
754
|
+
/**
|
|
755
|
+
* Gate which identities Better Auth admits. Called just before
|
|
756
|
+
* `create-user`, `link-account`, and (for OAuth) `sign-in`, across
|
|
757
|
+
* every authentication method, including stateless setups with no
|
|
758
|
+
* persistent database. On `sign-in` the hook receives the *fresh*
|
|
759
|
+
* provider email and profile, so a domain policy can reject a user
|
|
760
|
+
* whose provider identity moved out of bounds.
|
|
761
|
+
*
|
|
762
|
+
* Non-provider returning sign-ins are not re-validated; use the admin
|
|
763
|
+
* plugin's ban controls or a `databaseHooks.session.create.before`
|
|
764
|
+
* hook for those.
|
|
765
|
+
*
|
|
766
|
+
* Return nothing to allow; return `{ error }` to reject. Browser flows
|
|
767
|
+
* redirect to the configured error URL; programmatic flows surface a
|
|
768
|
+
* `403`.
|
|
769
|
+
*
|
|
770
|
+
* TODO: rename to `validateUser` (and the `ValidateUserInfo*` types).
|
|
771
|
+
* "UserInfo" is the OIDC term and misleads for the email/password,
|
|
772
|
+
* SIWE, phone, and admin methods.
|
|
773
|
+
*/
|
|
774
|
+
validateUserInfo?: (data: {
|
|
775
|
+
user: Partial<User> & Record<string, unknown>;
|
|
776
|
+
source: ValidateUserInfoSource;
|
|
777
|
+
}, context: GenericEndpointContext) => Awaitable<void | ValidateUserInfoResult>;
|
|
687
778
|
/**
|
|
688
779
|
* Changing email configuration
|
|
689
780
|
*/
|
|
@@ -1379,4 +1470,4 @@ type BetterAuthOptions = {
|
|
|
1379
1470
|
};
|
|
1380
1471
|
};
|
|
1381
1472
|
//#endregion
|
|
1382
|
-
export { BaseURLConfig, BetterAuthAdvancedOptions, BetterAuthDBOptions, BetterAuthOptions, BetterAuthRateLimitOptions, BetterAuthRateLimitRule, BetterAuthRateLimitStorage, DynamicBaseURLConfig, GenerateIdFn, StoreIdentifierOption };
|
|
1473
|
+
export { BaseURLConfig, BetterAuthAdvancedOptions, BetterAuthDBOptions, BetterAuthOptions, BetterAuthRateLimitOptions, BetterAuthRateLimitRule, BetterAuthRateLimitStorage, DynamicBaseURLConfig, GenerateIdFn, StoreIdentifierOption, UserProvisioningSource, ValidateUserInfoAction, ValidateUserInfoMethod, ValidateUserInfoOAuthInfo, ValidateUserInfoResult, ValidateUserInfoSSOInfo, ValidateUserInfoSource };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-auth/core",
|
|
3
|
-
"version": "1.7.0-beta.
|
|
3
|
+
"version": "1.7.0-beta.5",
|
|
4
4
|
"description": "The most comprehensive authentication framework for TypeScript.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -153,11 +153,11 @@
|
|
|
153
153
|
},
|
|
154
154
|
"devDependencies": {
|
|
155
155
|
"@better-auth/utils": "0.4.1",
|
|
156
|
-
"@better-fetch/fetch": "1.
|
|
156
|
+
"@better-fetch/fetch": "1.2.2",
|
|
157
157
|
"@opentelemetry/api": "^1.9.0",
|
|
158
158
|
"@opentelemetry/sdk-trace-base": "^1.30.0",
|
|
159
159
|
"@opentelemetry/sdk-trace-node": "^1.30.0",
|
|
160
|
-
"better-call": "1.3.
|
|
160
|
+
"better-call": "1.3.6",
|
|
161
161
|
"@cloudflare/workers-types": "^4.20250121.0",
|
|
162
162
|
"jose": "^6.1.3",
|
|
163
163
|
"kysely": "^0.28.17 || ^0.29.0",
|
|
@@ -166,9 +166,9 @@
|
|
|
166
166
|
},
|
|
167
167
|
"peerDependencies": {
|
|
168
168
|
"@better-auth/utils": "0.4.1",
|
|
169
|
-
"@better-fetch/fetch": "1.
|
|
169
|
+
"@better-fetch/fetch": "1.2.2",
|
|
170
170
|
"@opentelemetry/api": "^1.9.0",
|
|
171
|
-
"better-call": "1.3.
|
|
171
|
+
"better-call": "1.3.6",
|
|
172
172
|
"@cloudflare/workers-types": ">=4",
|
|
173
173
|
"jose": "^6.1.0",
|
|
174
174
|
"kysely": "^0.28.5 || ^0.29.0",
|
|
@@ -1391,13 +1391,21 @@ export const createAdapterFactory =
|
|
|
1391
1391
|
},
|
|
1392
1392
|
],
|
|
1393
1393
|
});
|
|
1394
|
-
//
|
|
1394
|
+
// `deleteMany` is typed `Promise<number>`. A non-number breaks
|
|
1395
|
+
// the contract, so fail loud. A finite-number check then closes
|
|
1396
|
+
// the NaN/Infinity hole: `NaN > 0` is false and `Infinity > 0`
|
|
1397
|
+
// is true, so a bare `deleted > 0` would misclassify both. Only
|
|
1398
|
+
// a finite positive count proves we won the delete race; any
|
|
1399
|
+
// other value fails closed (returns null) so a single-use row
|
|
1400
|
+
// is never reported consumed without proof.
|
|
1395
1401
|
if (typeof deleted !== "number") {
|
|
1396
1402
|
throw new BetterAuthError(
|
|
1397
1403
|
`Adapter "${config.adapterId}" returned a non-numeric value from deleteMany during the consumeOne fallback. Return the number of deleted rows, or implement a native consumeOne for atomic single-use consumption.`,
|
|
1398
1404
|
);
|
|
1399
1405
|
}
|
|
1400
|
-
return deleted > 0
|
|
1406
|
+
return Number.isFinite(deleted) && deleted > 0
|
|
1407
|
+
? (target as T)
|
|
1408
|
+
: null;
|
|
1401
1409
|
}),
|
|
1402
1410
|
);
|
|
1403
1411
|
resultNeedsOutputTransform = false;
|
package/src/db/get-tables.ts
CHANGED
|
@@ -261,10 +261,15 @@ export const getAuthTables = (
|
|
|
261
261
|
options.account?.fields?.refreshTokenExpiresAt ||
|
|
262
262
|
"refreshTokenExpiresAt",
|
|
263
263
|
},
|
|
264
|
-
scope
|
|
265
|
-
|
|
264
|
+
// Renamed from the legacy `scope` column. The migration generator
|
|
265
|
+
// only adds this column; it does not transform the legacy `scope`
|
|
266
|
+
// value. Upgrading installs need a manual data migration (split
|
|
267
|
+
// legacy `scope` on comma/space, trim, drop empties, dedupe). Order
|
|
268
|
+
// is insignificant per RFC 6749 §3.3.
|
|
269
|
+
grantedScopes: {
|
|
270
|
+
type: "string[]",
|
|
266
271
|
required: false,
|
|
267
|
-
fieldName: options.account?.fields?.
|
|
272
|
+
fieldName: options.account?.fields?.grantedScopes || "grantedScopes",
|
|
268
273
|
},
|
|
269
274
|
password: {
|
|
270
275
|
type: "string",
|
package/src/db/schema/account.ts
CHANGED
|
@@ -23,9 +23,21 @@ export const accountSchema = coreSchema.extend({
|
|
|
23
23
|
*/
|
|
24
24
|
refreshTokenExpiresAt: z.date().nullish(),
|
|
25
25
|
/**
|
|
26
|
-
* The scopes
|
|
26
|
+
* The scopes the user has granted, as last observed (durable, per-account,
|
|
27
|
+
* the unit of revocation and the refresh ceiling). A native array, not a
|
|
28
|
+
* delimited string: scope order is insignificant per RFC 6749 §3.3, so the
|
|
29
|
+
* value is normalized (trimmed, deduped, sorted) on write.
|
|
30
|
+
*
|
|
31
|
+
* Renamed from the legacy comma-joined `scope` string. Breaking, with no
|
|
32
|
+
* automatic data migration (and no read-time shim): the migration generator
|
|
33
|
+
* only adds the new `grantedScopes` column, so legacy accounts read as empty
|
|
34
|
+
* here until an upgrade backfills `grantedScopes` from the old `scope` values
|
|
35
|
+
* (split on comma/space, trim, drop empties, dedupe). See the release
|
|
36
|
+
* changeset for the backfill.
|
|
37
|
+
*
|
|
38
|
+
* @see https://www.rfc-editor.org/rfc/rfc6749#section-3.3
|
|
27
39
|
*/
|
|
28
|
-
|
|
40
|
+
grantedScopes: z.array(z.string()).nullish(),
|
|
29
41
|
/**
|
|
30
42
|
* Password is only stored in the credential provider
|
|
31
43
|
*/
|
package/src/env/env-impl.ts
CHANGED
|
@@ -46,8 +46,7 @@ function toBoolean(val: boolean | string | undefined) {
|
|
|
46
46
|
return val ? val !== "false" : false;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
export const nodeENV =
|
|
50
|
-
(typeof process !== "undefined" && process.env && process.env.NODE_ENV) || "";
|
|
49
|
+
export const nodeENV = env.NODE_ENV ?? "";
|
|
51
50
|
|
|
52
51
|
/** Detect if `NODE_ENV` environment variable is `production` */
|
|
53
52
|
export const isProduction = nodeENV === "production";
|
package/src/error/codes.ts
CHANGED
|
@@ -29,6 +29,11 @@ export const BASE_ERROR_CODES = defineErrorCodes({
|
|
|
29
29
|
TOKEN_EXPIRED: "Token expired",
|
|
30
30
|
ID_TOKEN_NOT_SUPPORTED: "id_token not supported",
|
|
31
31
|
FAILED_TO_GET_USER_INFO: "Failed to get user info",
|
|
32
|
+
PROVIDER_NOT_SUPPORTED: "Provider not supported",
|
|
33
|
+
TOKEN_REFRESH_NOT_SUPPORTED: "Token refresh not supported",
|
|
34
|
+
REFRESH_TOKEN_NOT_FOUND: "Refresh token not found",
|
|
35
|
+
FAILED_TO_GET_ACCESS_TOKEN: "Failed to get a valid access token",
|
|
36
|
+
FAILED_TO_REFRESH_ACCESS_TOKEN: "Failed to refresh access token",
|
|
32
37
|
USER_EMAIL_NOT_FOUND: "User email not found",
|
|
33
38
|
EMAIL_NOT_VERIFIED: "Email not verified",
|
|
34
39
|
PASSWORD_TOO_SHORT: "Password too short",
|
|
@@ -70,7 +70,7 @@ export async function createAuthorizationURL({
|
|
|
70
70
|
}
|
|
71
71
|
url.searchParams.set("client_id", primaryClientId);
|
|
72
72
|
url.searchParams.set("state", state);
|
|
73
|
-
if (scopes) {
|
|
73
|
+
if (scopes?.length) {
|
|
74
74
|
url.searchParams.set("scope", scopes.join(scopeJoiner || " "));
|
|
75
75
|
}
|
|
76
76
|
url.searchParams.set("redirect_uri", options.redirectURI || redirectURI);
|
|
@@ -107,5 +107,5 @@ export async function createAuthorizationURL({
|
|
|
107
107
|
url.searchParams.set(key, value);
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
|
-
return url;
|
|
110
|
+
return { url, requestedScopes: scopes ?? [] };
|
|
111
111
|
}
|
package/src/oauth2/index.ts
CHANGED
|
@@ -27,15 +27,27 @@ export {
|
|
|
27
27
|
RESERVED_AUTHORIZATION_PARAMS_SET,
|
|
28
28
|
} from "./create-authorization-url";
|
|
29
29
|
export type {
|
|
30
|
+
AuthorizationURLResult,
|
|
31
|
+
GrantAuthority,
|
|
30
32
|
OAuth2Tokens,
|
|
31
33
|
OAuth2UserInfo,
|
|
32
|
-
|
|
34
|
+
OAuthIdTokenConfig,
|
|
35
|
+
ProviderGrantAuthority,
|
|
33
36
|
ProviderOptions,
|
|
37
|
+
UpstreamProvider,
|
|
34
38
|
} from "./oauth-provider";
|
|
35
39
|
export {
|
|
36
40
|
refreshAccessToken,
|
|
37
41
|
refreshAccessTokenRequest,
|
|
38
42
|
} from "./refresh-access-token";
|
|
43
|
+
export {
|
|
44
|
+
includesGrantedScope,
|
|
45
|
+
normalizeScopes,
|
|
46
|
+
parseScopeField,
|
|
47
|
+
readGrantedScopes,
|
|
48
|
+
resolveRequestedScopes,
|
|
49
|
+
unionGrantedScopes,
|
|
50
|
+
} from "./scopes";
|
|
39
51
|
export type {
|
|
40
52
|
TokenEndpointAuth,
|
|
41
53
|
TokenEndpointAuthMethod,
|
|
@@ -57,3 +69,7 @@ export {
|
|
|
57
69
|
verifyAccessToken,
|
|
58
70
|
verifyJwsAccessToken,
|
|
59
71
|
} from "./verify";
|
|
72
|
+
export {
|
|
73
|
+
supportsIdTokenSignIn,
|
|
74
|
+
verifyProviderIdToken,
|
|
75
|
+
} from "./verify-id-token";
|