@better-auth/core 1.7.0-beta.6 → 1.7.0-beta.8
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/get-tables.mjs +3 -3
- package/dist/db/schema/account.d.mts +1 -1
- package/dist/db/schema/account.mjs +1 -1
- package/dist/error/codes.d.mts +0 -5
- package/dist/error/codes.mjs +0 -5
- package/dist/instrumentation/tracer.mjs +1 -1
- package/dist/oauth2/create-authorization-url.d.mts +4 -5
- package/dist/oauth2/create-authorization-url.mjs +4 -5
- package/dist/oauth2/index.d.mts +3 -4
- package/dist/oauth2/index.mjs +2 -3
- package/dist/oauth2/oauth-provider.d.mts +44 -48
- package/dist/oauth2/refresh-access-token.mjs +17 -2
- package/dist/oauth2/utils.d.mts +6 -1
- package/dist/oauth2/utils.mjs +24 -2
- package/dist/oauth2/verify-id-token.d.mts +6 -5
- package/dist/oauth2/verify-id-token.mjs +2 -2
- package/dist/social-providers/apple.d.mts +3 -5
- package/dist/social-providers/apple.mjs +5 -5
- package/dist/social-providers/atlassian.d.mts +3 -5
- package/dist/social-providers/atlassian.mjs +4 -4
- package/dist/social-providers/cognito.d.mts +3 -5
- package/dist/social-providers/cognito.mjs +11 -18
- package/dist/social-providers/discord.d.mts +3 -5
- package/dist/social-providers/discord.mjs +6 -7
- package/dist/social-providers/dropbox.d.mts +3 -5
- package/dist/social-providers/dropbox.mjs +5 -5
- package/dist/social-providers/facebook.d.mts +3 -5
- package/dist/social-providers/facebook.mjs +5 -5
- package/dist/social-providers/figma.d.mts +3 -5
- package/dist/social-providers/figma.mjs +5 -5
- package/dist/social-providers/github.d.mts +3 -5
- package/dist/social-providers/github.mjs +4 -4
- package/dist/social-providers/gitlab.d.mts +3 -5
- package/dist/social-providers/gitlab.mjs +6 -6
- package/dist/social-providers/google.d.mts +10 -10
- package/dist/social-providers/google.mjs +12 -13
- package/dist/social-providers/huggingface.d.mts +3 -5
- package/dist/social-providers/huggingface.mjs +8 -8
- package/dist/social-providers/index.d.mts +105 -177
- package/dist/social-providers/kakao.d.mts +3 -5
- package/dist/social-providers/kakao.mjs +8 -8
- package/dist/social-providers/kick.d.mts +3 -5
- package/dist/social-providers/kick.mjs +4 -4
- package/dist/social-providers/line.d.mts +3 -5
- package/dist/social-providers/line.mjs +10 -10
- package/dist/social-providers/linear.d.mts +3 -5
- package/dist/social-providers/linear.mjs +4 -4
- package/dist/social-providers/linkedin.d.mts +3 -5
- package/dist/social-providers/linkedin.mjs +10 -10
- package/dist/social-providers/microsoft-entra-id.d.mts +3 -5
- package/dist/social-providers/microsoft-entra-id.mjs +10 -11
- package/dist/social-providers/naver.d.mts +3 -5
- package/dist/social-providers/naver.mjs +4 -4
- package/dist/social-providers/notion.d.mts +3 -5
- package/dist/social-providers/notion.mjs +4 -4
- package/dist/social-providers/paybin.d.mts +3 -5
- package/dist/social-providers/paybin.mjs +10 -10
- package/dist/social-providers/paypal.d.mts +3 -5
- package/dist/social-providers/paypal.mjs +2 -8
- package/dist/social-providers/polar.d.mts +3 -5
- package/dist/social-providers/polar.mjs +8 -8
- package/dist/social-providers/railway.d.mts +3 -5
- package/dist/social-providers/railway.mjs +9 -9
- package/dist/social-providers/reddit.d.mts +3 -5
- package/dist/social-providers/reddit.mjs +5 -5
- package/dist/social-providers/roblox.d.mts +3 -5
- package/dist/social-providers/roblox.mjs +5 -5
- package/dist/social-providers/salesforce.d.mts +3 -5
- package/dist/social-providers/salesforce.mjs +8 -8
- package/dist/social-providers/slack.d.mts +3 -5
- package/dist/social-providers/slack.mjs +9 -9
- package/dist/social-providers/spotify.d.mts +3 -5
- package/dist/social-providers/spotify.mjs +5 -5
- package/dist/social-providers/tiktok.d.mts +3 -5
- package/dist/social-providers/tiktok.mjs +5 -9
- package/dist/social-providers/twitch.d.mts +3 -5
- package/dist/social-providers/twitch.mjs +4 -4
- package/dist/social-providers/twitter.d.mts +3 -5
- package/dist/social-providers/twitter.mjs +9 -9
- package/dist/social-providers/vercel.d.mts +3 -5
- package/dist/social-providers/vercel.mjs +7 -4
- package/dist/social-providers/vk.d.mts +3 -5
- package/dist/social-providers/vk.mjs +5 -5
- package/dist/social-providers/wechat.d.mts +3 -5
- package/dist/social-providers/wechat.mjs +5 -9
- package/dist/social-providers/zoom.d.mts +3 -6
- package/dist/social-providers/zoom.mjs +9 -15
- package/dist/types/context.d.mts +6 -2
- package/dist/utils/host.d.mts +1 -1
- package/dist/utils/host.mjs +3 -0
- package/package.json +1 -1
- package/src/db/get-tables.ts +3 -8
- package/src/db/schema/account.ts +5 -14
- package/src/error/codes.ts +0 -5
- package/src/oauth2/create-authorization-url.ts +5 -1
- package/src/oauth2/index.ts +3 -12
- package/src/oauth2/oauth-provider.ts +46 -53
- package/src/oauth2/refresh-access-token.ts +30 -5
- package/src/oauth2/utils.ts +39 -1
- package/src/oauth2/verify-id-token.ts +9 -5
- package/src/social-providers/apple.ts +8 -13
- package/src/social-providers/atlassian.ts +8 -12
- package/src/social-providers/cognito.ts +11 -18
- package/src/social-providers/discord.ts +8 -19
- package/src/social-providers/dropbox.ts +7 -13
- package/src/social-providers/facebook.ts +9 -13
- package/src/social-providers/figma.ts +9 -13
- package/src/social-providers/github.ts +8 -12
- package/src/social-providers/gitlab.ts +8 -14
- package/src/social-providers/google.ts +23 -29
- package/src/social-providers/huggingface.ts +8 -12
- package/src/social-providers/kakao.ts +8 -16
- package/src/social-providers/kick.ts +7 -12
- package/src/social-providers/line.ts +10 -14
- package/src/social-providers/linear.ts +6 -12
- package/src/social-providers/linkedin.ts +10 -14
- package/src/social-providers/microsoft-entra-id.ts +8 -18
- package/src/social-providers/naver.ts +6 -12
- package/src/social-providers/notion.ts +6 -12
- package/src/social-providers/paybin.ts +11 -14
- package/src/social-providers/paypal.ts +8 -6
- package/src/social-providers/polar.ts +8 -12
- package/src/social-providers/railway.ts +9 -13
- package/src/social-providers/reddit.ts +7 -18
- package/src/social-providers/roblox.ts +7 -18
- package/src/social-providers/salesforce.ts +8 -12
- package/src/social-providers/slack.ts +9 -18
- package/src/social-providers/spotify.ts +7 -13
- package/src/social-providers/tiktok.ts +7 -13
- package/src/social-providers/twitch.ts +8 -12
- package/src/social-providers/twitter.ts +8 -17
- package/src/social-providers/vercel.ts +10 -16
- package/src/social-providers/vk.ts +7 -13
- package/src/social-providers/wechat.ts +8 -20
- package/src/social-providers/zoom.ts +6 -19
- package/src/types/context.ts +8 -2
- package/src/utils/host.ts +10 -1
- package/dist/oauth2/scopes.d.mts +0 -76
- package/dist/oauth2/scopes.mjs +0 -96
- package/src/oauth2/scopes.ts +0 -118
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import { betterFetch } from "@better-fetch/fetch";
|
|
2
2
|
import { BetterAuthError } from "../error";
|
|
3
|
-
import type {
|
|
4
|
-
import {
|
|
5
|
-
createAuthorizationURL,
|
|
6
|
-
resolveRequestedScopes,
|
|
7
|
-
validateAuthorizationCode,
|
|
8
|
-
} from "../oauth2";
|
|
3
|
+
import type { OAuthProvider, ProviderOptions } from "../oauth2";
|
|
4
|
+
import { createAuthorizationURL, validateAuthorizationCode } from "../oauth2";
|
|
9
5
|
|
|
10
6
|
export interface VercelProfile {
|
|
11
7
|
sub: string;
|
|
@@ -20,13 +16,10 @@ export interface VercelOptions extends ProviderOptions<VercelProfile> {
|
|
|
20
16
|
clientId: string;
|
|
21
17
|
}
|
|
22
18
|
|
|
23
|
-
const VERCEL_DEFAULT_SCOPES: string[] = [];
|
|
24
|
-
|
|
25
19
|
export const vercel = (options: VercelOptions) => {
|
|
26
20
|
return {
|
|
27
21
|
id: "vercel",
|
|
28
22
|
name: "Vercel",
|
|
29
|
-
callbackPath: "/callback/vercel",
|
|
30
23
|
createAuthorizationURL({
|
|
31
24
|
state,
|
|
32
25
|
scopes,
|
|
@@ -38,17 +31,18 @@ export const vercel = (options: VercelOptions) => {
|
|
|
38
31
|
throw new BetterAuthError("codeVerifier is required for Vercel");
|
|
39
32
|
}
|
|
40
33
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
34
|
+
let _scopes: string[] | undefined = undefined;
|
|
35
|
+
if (options.scope !== undefined || scopes !== undefined) {
|
|
36
|
+
_scopes = [];
|
|
37
|
+
if (options.scope) _scopes.push(...options.scope);
|
|
38
|
+
if (scopes) _scopes.push(...scopes);
|
|
39
|
+
}
|
|
46
40
|
|
|
47
41
|
return createAuthorizationURL({
|
|
48
42
|
id: "vercel",
|
|
49
43
|
options,
|
|
50
44
|
authorizationEndpoint: "https://vercel.com/oauth/authorize",
|
|
51
|
-
scopes:
|
|
45
|
+
scopes: _scopes,
|
|
52
46
|
state,
|
|
53
47
|
codeVerifier,
|
|
54
48
|
redirectURI,
|
|
@@ -96,5 +90,5 @@ export const vercel = (options: VercelOptions) => {
|
|
|
96
90
|
};
|
|
97
91
|
},
|
|
98
92
|
options,
|
|
99
|
-
} satisfies
|
|
93
|
+
} satisfies OAuthProvider<VercelProfile>;
|
|
100
94
|
};
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { betterFetch } from "@better-fetch/fetch";
|
|
2
|
-
import type {
|
|
2
|
+
import type { OAuthProvider, ProviderOptions } from "../oauth2";
|
|
3
3
|
import {
|
|
4
4
|
createAuthorizationURL,
|
|
5
5
|
refreshAccessToken,
|
|
6
|
-
resolveRequestedScopes,
|
|
7
6
|
validateAuthorizationCode,
|
|
8
7
|
} from "../oauth2";
|
|
9
8
|
|
|
@@ -26,33 +25,28 @@ export interface VkOption extends ProviderOptions {
|
|
|
26
25
|
scheme?: ("light" | "dark") | undefined;
|
|
27
26
|
}
|
|
28
27
|
|
|
29
|
-
const VK_DEFAULT_SCOPES = ["email", "phone"];
|
|
30
|
-
|
|
31
28
|
export const vk = (options: VkOption) => {
|
|
32
29
|
const tokenEndpoint = "https://id.vk.com/oauth2/auth";
|
|
33
30
|
return {
|
|
34
31
|
id: "vk",
|
|
35
32
|
name: "VK",
|
|
36
|
-
|
|
37
|
-
createAuthorizationURL({
|
|
33
|
+
async createAuthorizationURL({
|
|
38
34
|
state,
|
|
39
35
|
scopes,
|
|
40
36
|
codeVerifier,
|
|
41
37
|
redirectURI,
|
|
42
38
|
additionalParams,
|
|
43
39
|
}) {
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
scopes,
|
|
48
|
-
);
|
|
40
|
+
const _scopes = options.disableDefaultScope ? [] : ["email", "phone"];
|
|
41
|
+
if (options.scope) _scopes.push(...options.scope);
|
|
42
|
+
if (scopes) _scopes.push(...scopes);
|
|
49
43
|
const authorizationEndpoint = "https://id.vk.com/authorize";
|
|
50
44
|
|
|
51
45
|
return createAuthorizationURL({
|
|
52
46
|
id: "vk",
|
|
53
47
|
options,
|
|
54
48
|
authorizationEndpoint,
|
|
55
|
-
scopes:
|
|
49
|
+
scopes: _scopes,
|
|
56
50
|
state,
|
|
57
51
|
redirectURI,
|
|
58
52
|
codeVerifier,
|
|
@@ -134,5 +128,5 @@ export const vk = (options: VkOption) => {
|
|
|
134
128
|
};
|
|
135
129
|
},
|
|
136
130
|
options,
|
|
137
|
-
} satisfies
|
|
131
|
+
} satisfies OAuthProvider<VkProfile>;
|
|
138
132
|
};
|
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
import { betterFetch } from "@better-fetch/fetch";
|
|
2
|
-
import type {
|
|
3
|
-
|
|
4
|
-
ProviderOptions,
|
|
5
|
-
UpstreamProvider,
|
|
6
|
-
} from "../oauth2";
|
|
7
|
-
import {
|
|
8
|
-
RESERVED_AUTHORIZATION_PARAMS_SET,
|
|
9
|
-
resolveRequestedScopes,
|
|
10
|
-
} from "../oauth2";
|
|
2
|
+
import type { OAuth2Tokens, OAuthProvider, ProviderOptions } from "../oauth2";
|
|
3
|
+
import { RESERVED_AUTHORIZATION_PARAMS_SET } from "../oauth2";
|
|
11
4
|
|
|
12
5
|
/**
|
|
13
6
|
* WeChat user profile information
|
|
@@ -62,24 +55,19 @@ export interface WeChatOptions extends ProviderOptions<WeChatProfile> {
|
|
|
62
55
|
lang?: "cn" | "en";
|
|
63
56
|
}
|
|
64
57
|
|
|
65
|
-
const WECHAT_DEFAULT_SCOPES = ["snsapi_login"];
|
|
66
|
-
|
|
67
58
|
export const wechat = (options: WeChatOptions) => {
|
|
68
59
|
return {
|
|
69
60
|
id: "wechat",
|
|
70
61
|
name: "WeChat",
|
|
71
|
-
callbackPath: "/callback/wechat",
|
|
72
62
|
createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) {
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
scopes,
|
|
77
|
-
);
|
|
63
|
+
const _scopes = options.disableDefaultScope ? [] : ["snsapi_login"];
|
|
64
|
+
options.scope && _scopes.push(...options.scope);
|
|
65
|
+
scopes && _scopes.push(...scopes);
|
|
78
66
|
|
|
79
67
|
// WeChat uses non-standard OAuth2 parameters (appid instead of client_id)
|
|
80
68
|
// and requires a fragment (#wechat_redirect), so we construct the URL manually.
|
|
81
69
|
const url = new URL("https://open.weixin.qq.com/connect/qrconnect");
|
|
82
|
-
url.searchParams.set("scope",
|
|
70
|
+
url.searchParams.set("scope", _scopes.join(","));
|
|
83
71
|
url.searchParams.set("response_type", "code");
|
|
84
72
|
url.searchParams.set("appid", options.clientId);
|
|
85
73
|
url.searchParams.set("redirect_uri", options.redirectURI || redirectURI);
|
|
@@ -94,7 +82,7 @@ export const wechat = (options: WeChatOptions) => {
|
|
|
94
82
|
}
|
|
95
83
|
url.hash = "wechat_redirect";
|
|
96
84
|
|
|
97
|
-
return
|
|
85
|
+
return url;
|
|
98
86
|
},
|
|
99
87
|
|
|
100
88
|
// WeChat uses non-standard token exchange (appid/secret instead of
|
|
@@ -236,5 +224,5 @@ export const wechat = (options: WeChatOptions) => {
|
|
|
236
224
|
};
|
|
237
225
|
},
|
|
238
226
|
options,
|
|
239
|
-
} satisfies
|
|
227
|
+
} satisfies OAuthProvider<WeChatProfile, WeChatOptions>;
|
|
240
228
|
};
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { betterFetch } from "@better-fetch/fetch";
|
|
2
|
-
import type {
|
|
2
|
+
import type { OAuthProvider, ProviderOptions } from "../oauth2";
|
|
3
3
|
import {
|
|
4
4
|
createAuthorizationURL,
|
|
5
5
|
refreshAccessToken,
|
|
6
|
-
resolveRequestedScopes,
|
|
7
6
|
validateAuthorizationCode,
|
|
8
7
|
} from "../oauth2";
|
|
9
8
|
|
|
@@ -144,8 +143,6 @@ export interface ZoomOptions extends ProviderOptions<ZoomProfile> {
|
|
|
144
143
|
pkce?: boolean | undefined;
|
|
145
144
|
}
|
|
146
145
|
|
|
147
|
-
const ZOOM_DEFAULT_SCOPES: string[] = [];
|
|
148
|
-
|
|
149
146
|
export const zoom = (userOptions: ZoomOptions) => {
|
|
150
147
|
const options = {
|
|
151
148
|
pkce: true,
|
|
@@ -155,31 +152,21 @@ export const zoom = (userOptions: ZoomOptions) => {
|
|
|
155
152
|
return {
|
|
156
153
|
id: "zoom",
|
|
157
154
|
name: "Zoom",
|
|
158
|
-
|
|
159
|
-
createAuthorizationURL: ({
|
|
155
|
+
createAuthorizationURL: async ({
|
|
160
156
|
state,
|
|
161
|
-
scopes,
|
|
162
157
|
redirectURI,
|
|
163
158
|
codeVerifier,
|
|
164
159
|
additionalParams,
|
|
165
|
-
}) =>
|
|
166
|
-
|
|
167
|
-
options,
|
|
168
|
-
ZOOM_DEFAULT_SCOPES,
|
|
169
|
-
scopes,
|
|
170
|
-
);
|
|
171
|
-
|
|
172
|
-
return createAuthorizationURL({
|
|
160
|
+
}) =>
|
|
161
|
+
createAuthorizationURL({
|
|
173
162
|
id: "zoom",
|
|
174
163
|
options,
|
|
175
164
|
authorizationEndpoint: "https://zoom.us/oauth/authorize",
|
|
176
|
-
scopes: requestedScopes,
|
|
177
165
|
state,
|
|
178
166
|
redirectURI,
|
|
179
167
|
codeVerifier: options.pkce ? codeVerifier : undefined,
|
|
180
168
|
additionalParams,
|
|
181
|
-
})
|
|
182
|
-
},
|
|
169
|
+
}),
|
|
183
170
|
validateAuthorizationCode: async ({ code, redirectURI, codeVerifier }) => {
|
|
184
171
|
return validateAuthorizationCode({
|
|
185
172
|
code,
|
|
@@ -235,5 +222,5 @@ export const zoom = (userOptions: ZoomOptions) => {
|
|
|
235
222
|
},
|
|
236
223
|
};
|
|
237
224
|
},
|
|
238
|
-
} satisfies
|
|
225
|
+
} satisfies OAuthProvider<ZoomProfile>;
|
|
239
226
|
};
|
package/src/types/context.ts
CHANGED
|
@@ -10,7 +10,7 @@ import type {
|
|
|
10
10
|
} from "../db";
|
|
11
11
|
import type { DBAdapter, Where } from "../db/adapter";
|
|
12
12
|
import type { createLogger } from "../env";
|
|
13
|
-
import type {
|
|
13
|
+
import type { OAuthProvider } from "../oauth2";
|
|
14
14
|
import type { BetterAuthCookie, BetterAuthCookies } from "./cookie";
|
|
15
15
|
import type { Awaitable, LiteralString } from "./helper";
|
|
16
16
|
import type {
|
|
@@ -88,6 +88,12 @@ export type GenericEndpointContext<
|
|
|
88
88
|
export interface InternalAdapter<
|
|
89
89
|
_Options extends BetterAuthOptions = BetterAuthOptions,
|
|
90
90
|
> {
|
|
91
|
+
createOAuthUser(
|
|
92
|
+
user: Omit<User, "id" | "createdAt" | "updatedAt">,
|
|
93
|
+
account: Omit<Account, "userId" | "id" | "createdAt" | "updatedAt"> &
|
|
94
|
+
Partial<Account>,
|
|
95
|
+
): Promise<{ user: User; account: Account }>;
|
|
96
|
+
|
|
91
97
|
createUser<T extends Record<string, any>>(
|
|
92
98
|
user: Omit<User, "id" | "createdAt" | "updatedAt" | "emailVerified"> &
|
|
93
99
|
Partial<User> &
|
|
@@ -369,7 +375,7 @@ export type AuthContext<Options extends BetterAuthOptions = BetterAuthOptions> =
|
|
|
369
375
|
user: User & Record<string, any>;
|
|
370
376
|
} | null,
|
|
371
377
|
) => void;
|
|
372
|
-
socialProviders:
|
|
378
|
+
socialProviders: OAuthProvider[];
|
|
373
379
|
authCookies: BetterAuthCookies;
|
|
374
380
|
logger: ReturnType<typeof createLogger>;
|
|
375
381
|
rateLimit: {
|
package/src/utils/host.ts
CHANGED
|
@@ -49,7 +49,7 @@ export type HostKind =
|
|
|
49
49
|
| "multicast"
|
|
50
50
|
/** IPv4 limited broadcast `255.255.255.255`. */
|
|
51
51
|
| "broadcast"
|
|
52
|
-
/** Other RFC 6890 special-purpose ranges (0/8, 192.0.0/24, 240/4, 2001::/32, etc.). */
|
|
52
|
+
/** Other RFC 6890 special-purpose ranges (0.0.0.0/8, 192.0.0.0/24, 192.88.99.0/24, 240.0.0.0/4, 2001::/32, etc.). */
|
|
53
53
|
| "reserved"
|
|
54
54
|
/** Cloud metadata service FQDN (e.g. `metadata.google.internal`). */
|
|
55
55
|
| "cloudMetadata"
|
|
@@ -183,6 +183,8 @@ function classifyIPv4(ip: string): HostKind {
|
|
|
183
183
|
if (inIPv4Range(n, ipv4ToUint32("224.0.0.0"), 4)) return "multicast";
|
|
184
184
|
if (inIPv4Range(n, ipv4ToUint32("0.0.0.0"), 8)) return "reserved";
|
|
185
185
|
if (inIPv4Range(n, ipv4ToUint32("192.0.0.0"), 24)) return "reserved";
|
|
186
|
+
// 6to4 relay anycast (RFC 7526, deprecated), not globally reachable.
|
|
187
|
+
if (inIPv4Range(n, ipv4ToUint32("192.88.99.0"), 24)) return "reserved";
|
|
186
188
|
if (inIPv4Range(n, ipv4ToUint32("240.0.0.0"), 4)) return "reserved";
|
|
187
189
|
|
|
188
190
|
return "public";
|
|
@@ -231,6 +233,8 @@ function classifyIPv6(expanded: string): HostKind {
|
|
|
231
233
|
|
|
232
234
|
if (firstByte === 0xff) return "multicast";
|
|
233
235
|
if (firstByte === 0xfe && (secondByte & 0xc0) === 0x80) return "linkLocal";
|
|
236
|
+
// fec0::/10 — deprecated site-local (RFC 3879), not globally reachable.
|
|
237
|
+
if (firstByte === 0xfe && (secondByte & 0xc0) === 0xc0) return "reserved";
|
|
234
238
|
if ((firstByte & 0xfe) === 0xfc) return "private";
|
|
235
239
|
|
|
236
240
|
if (expanded.startsWith("2001:0db8:")) return "documentation";
|
|
@@ -270,6 +274,11 @@ function classifyIPv6(expanded: string): HostKind {
|
|
|
270
274
|
// 5f00::/16 — SRv6 SIDs (RFC 9602), not globally reachable.
|
|
271
275
|
if (expanded.startsWith("5f00:")) return "reserved";
|
|
272
276
|
|
|
277
|
+
// ::/96 — deprecated IPv4-compatible IPv6 (RFC 4291 §2.5.5.1). `::` and
|
|
278
|
+
// `::1` are matched above; the rest of the block embeds an IPv4 (e.g.
|
|
279
|
+
// `::127.0.0.1`) and is never a valid public target.
|
|
280
|
+
if (expanded.startsWith("0000:0000:0000:0000:0000:0000:")) return "reserved";
|
|
281
|
+
|
|
273
282
|
return "public";
|
|
274
283
|
}
|
|
275
284
|
|
package/dist/oauth2/scopes.d.mts
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import { ProviderOptions } from "./oauth-provider.mjs";
|
|
2
|
-
|
|
3
|
-
//#region src/oauth2/scopes.d.ts
|
|
4
|
-
/**
|
|
5
|
-
* Parse a provider's `scope` token-response field into a string array.
|
|
6
|
-
*
|
|
7
|
-
* RFC 6749 §3.3 defines `scope` as a space-delimited string, but providers
|
|
8
|
-
* vary: some (e.g. Twitch) return an already-split array. Accept both, plus the
|
|
9
|
-
* omitted/empty case, without ever calling `.split` on a non-string. Returns
|
|
10
|
-
* `[]` when no scope is present.
|
|
11
|
-
*
|
|
12
|
-
* @see https://github.com/better-auth/better-auth/issues/9076
|
|
13
|
-
*/
|
|
14
|
-
declare function parseScopeField(scope: unknown): string[];
|
|
15
|
-
/**
|
|
16
|
-
* Normalize a scope set into a single deduped, sorted array.
|
|
17
|
-
*
|
|
18
|
-
* Scope order is insignificant per RFC 6749 §3.3, so normalize for idempotent
|
|
19
|
-
* writes and trivial comparisons: trim each token, drop empties, dedupe, and
|
|
20
|
-
* sort ascending. Returns `[]` when the union is empty.
|
|
21
|
-
*
|
|
22
|
-
* @see https://www.rfc-editor.org/rfc/rfc6749#section-3.3
|
|
23
|
-
*/
|
|
24
|
-
declare function normalizeScopes(stored: string[] | null | undefined, incoming?: string[] | undefined): string[];
|
|
25
|
-
/**
|
|
26
|
-
* Union the stored granted-scope set with the scopes observed on an
|
|
27
|
-
* authorization or token exchange.
|
|
28
|
-
*
|
|
29
|
-
* The provider's echoed `scope` is authoritative when present. RFC 6749 §3.3
|
|
30
|
-
* and §5.1 say an omitted or empty echo means the grant equals what was
|
|
31
|
-
* requested, so fall back to `requested` in that case. The result unions onto
|
|
32
|
-
* the stored grant (never narrows on a normal write) and is normalized per
|
|
33
|
-
* {@link normalizeScopes}.
|
|
34
|
-
*
|
|
35
|
-
* @see https://www.rfc-editor.org/rfc/rfc6749#section-3.3
|
|
36
|
-
* @see https://www.rfc-editor.org/rfc/rfc6749#section-5.1
|
|
37
|
-
*/
|
|
38
|
-
declare function unionGrantedScopes(stored: string[] | null | undefined, echoed: string[] | undefined, requested: string[] | undefined): string[];
|
|
39
|
-
/**
|
|
40
|
-
* Coerce a stored granted-scope value into a usable array.
|
|
41
|
-
*
|
|
42
|
-
* `account.grantedScopes` is nullable (legacy rows and non-OAuth accounts read
|
|
43
|
-
* as unset), and on dialects that store the array as a JSON string a malformed
|
|
44
|
-
* operator backfill could deserialize to a non-array. Both collapse to `[]`
|
|
45
|
-
* here so every reader works against a real `string[]` without re-deriving the
|
|
46
|
-
* guard.
|
|
47
|
-
*/
|
|
48
|
-
declare function readGrantedScopes(stored: string[] | null | undefined): string[];
|
|
49
|
-
/**
|
|
50
|
-
* Test whether a normalized granted-scope set contains a specific scope.
|
|
51
|
-
*
|
|
52
|
-
* Matching is exact and case-sensitive per RFC 6749 §3.3. The argument is the
|
|
53
|
-
* normalized `account.grantedScopes` array; a raw provider `scope` string must
|
|
54
|
-
* be run through {@link parseScopeField} first.
|
|
55
|
-
*
|
|
56
|
-
* @see https://www.rfc-editor.org/rfc/rfc6749#section-3.3
|
|
57
|
-
*/
|
|
58
|
-
declare function includesGrantedScope(granted: string[] | null | undefined, scope: string): boolean;
|
|
59
|
-
/**
|
|
60
|
-
* Compose the effective scope set to encode in a single authorization URL.
|
|
61
|
-
*
|
|
62
|
-
* Precedence: the provider's built-in defaults (unless `disableDefaultScope`),
|
|
63
|
-
* then the integrator's configured `options.scope`, then the per-request
|
|
64
|
-
* `scopes`. The result is the value persisted into OAuth state as the RFC 6749
|
|
65
|
-
* §5.1 fallback, so it is preserved verbatim (not normalized) to match what is
|
|
66
|
-
* sent to the provider.
|
|
67
|
-
*
|
|
68
|
-
* `defaultScopes` is a parameter rather than a provider-contract field so the
|
|
69
|
-
* runtime-synthesized generic OAuth provider, which has no static default set,
|
|
70
|
-
* can pass its configured scopes here.
|
|
71
|
-
*
|
|
72
|
-
* @see https://www.rfc-editor.org/rfc/rfc6749#section-5.1
|
|
73
|
-
*/
|
|
74
|
-
declare function resolveRequestedScopes(options: Pick<ProviderOptions, "scope" | "disableDefaultScope"> | undefined, defaultScopes: string[], perRequestScopes: string[] | undefined): string[];
|
|
75
|
-
//#endregion
|
|
76
|
-
export { includesGrantedScope, normalizeScopes, parseScopeField, readGrantedScopes, resolveRequestedScopes, unionGrantedScopes };
|
package/dist/oauth2/scopes.mjs
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
//#region src/oauth2/scopes.ts
|
|
2
|
-
/**
|
|
3
|
-
* Parse a provider's `scope` token-response field into a string array.
|
|
4
|
-
*
|
|
5
|
-
* RFC 6749 §3.3 defines `scope` as a space-delimited string, but providers
|
|
6
|
-
* vary: some (e.g. Twitch) return an already-split array. Accept both, plus the
|
|
7
|
-
* omitted/empty case, without ever calling `.split` on a non-string. Returns
|
|
8
|
-
* `[]` when no scope is present.
|
|
9
|
-
*
|
|
10
|
-
* @see https://github.com/better-auth/better-auth/issues/9076
|
|
11
|
-
*/
|
|
12
|
-
function parseScopeField(scope) {
|
|
13
|
-
if (Array.isArray(scope)) return scope.filter((s) => typeof s === "string" && s !== "");
|
|
14
|
-
if (typeof scope === "string") return scope.split(" ").filter(Boolean);
|
|
15
|
-
return [];
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Normalize a scope set into a single deduped, sorted array.
|
|
19
|
-
*
|
|
20
|
-
* Scope order is insignificant per RFC 6749 §3.3, so normalize for idempotent
|
|
21
|
-
* writes and trivial comparisons: trim each token, drop empties, dedupe, and
|
|
22
|
-
* sort ascending. Returns `[]` when the union is empty.
|
|
23
|
-
*
|
|
24
|
-
* @see https://www.rfc-editor.org/rfc/rfc6749#section-3.3
|
|
25
|
-
*/
|
|
26
|
-
function normalizeScopes(stored, incoming) {
|
|
27
|
-
const normalized = /* @__PURE__ */ new Set();
|
|
28
|
-
for (const scope of [...stored ?? [], ...incoming ?? []]) {
|
|
29
|
-
const trimmed = scope.trim();
|
|
30
|
-
if (trimmed) normalized.add(trimmed);
|
|
31
|
-
}
|
|
32
|
-
return [...normalized].sort();
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Union the stored granted-scope set with the scopes observed on an
|
|
36
|
-
* authorization or token exchange.
|
|
37
|
-
*
|
|
38
|
-
* The provider's echoed `scope` is authoritative when present. RFC 6749 §3.3
|
|
39
|
-
* and §5.1 say an omitted or empty echo means the grant equals what was
|
|
40
|
-
* requested, so fall back to `requested` in that case. The result unions onto
|
|
41
|
-
* the stored grant (never narrows on a normal write) and is normalized per
|
|
42
|
-
* {@link normalizeScopes}.
|
|
43
|
-
*
|
|
44
|
-
* @see https://www.rfc-editor.org/rfc/rfc6749#section-3.3
|
|
45
|
-
* @see https://www.rfc-editor.org/rfc/rfc6749#section-5.1
|
|
46
|
-
*/
|
|
47
|
-
function unionGrantedScopes(stored, echoed, requested) {
|
|
48
|
-
return normalizeScopes(stored, echoed?.length ? echoed : requested);
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Coerce a stored granted-scope value into a usable array.
|
|
52
|
-
*
|
|
53
|
-
* `account.grantedScopes` is nullable (legacy rows and non-OAuth accounts read
|
|
54
|
-
* as unset), and on dialects that store the array as a JSON string a malformed
|
|
55
|
-
* operator backfill could deserialize to a non-array. Both collapse to `[]`
|
|
56
|
-
* here so every reader works against a real `string[]` without re-deriving the
|
|
57
|
-
* guard.
|
|
58
|
-
*/
|
|
59
|
-
function readGrantedScopes(stored) {
|
|
60
|
-
return Array.isArray(stored) ? stored : [];
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Test whether a normalized granted-scope set contains a specific scope.
|
|
64
|
-
*
|
|
65
|
-
* Matching is exact and case-sensitive per RFC 6749 §3.3. The argument is the
|
|
66
|
-
* normalized `account.grantedScopes` array; a raw provider `scope` string must
|
|
67
|
-
* be run through {@link parseScopeField} first.
|
|
68
|
-
*
|
|
69
|
-
* @see https://www.rfc-editor.org/rfc/rfc6749#section-3.3
|
|
70
|
-
*/
|
|
71
|
-
function includesGrantedScope(granted, scope) {
|
|
72
|
-
return granted?.includes(scope) ?? false;
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Compose the effective scope set to encode in a single authorization URL.
|
|
76
|
-
*
|
|
77
|
-
* Precedence: the provider's built-in defaults (unless `disableDefaultScope`),
|
|
78
|
-
* then the integrator's configured `options.scope`, then the per-request
|
|
79
|
-
* `scopes`. The result is the value persisted into OAuth state as the RFC 6749
|
|
80
|
-
* §5.1 fallback, so it is preserved verbatim (not normalized) to match what is
|
|
81
|
-
* sent to the provider.
|
|
82
|
-
*
|
|
83
|
-
* `defaultScopes` is a parameter rather than a provider-contract field so the
|
|
84
|
-
* runtime-synthesized generic OAuth provider, which has no static default set,
|
|
85
|
-
* can pass its configured scopes here.
|
|
86
|
-
*
|
|
87
|
-
* @see https://www.rfc-editor.org/rfc/rfc6749#section-5.1
|
|
88
|
-
*/
|
|
89
|
-
function resolveRequestedScopes(options, defaultScopes, perRequestScopes) {
|
|
90
|
-
const scopes = options?.disableDefaultScope ? [] : [...defaultScopes];
|
|
91
|
-
if (options?.scope) scopes.push(...options.scope);
|
|
92
|
-
if (perRequestScopes) scopes.push(...perRequestScopes);
|
|
93
|
-
return scopes;
|
|
94
|
-
}
|
|
95
|
-
//#endregion
|
|
96
|
-
export { includesGrantedScope, normalizeScopes, parseScopeField, readGrantedScopes, resolveRequestedScopes, unionGrantedScopes };
|
package/src/oauth2/scopes.ts
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import type { ProviderOptions } from "./oauth-provider";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Parse a provider's `scope` token-response field into a string array.
|
|
5
|
-
*
|
|
6
|
-
* RFC 6749 §3.3 defines `scope` as a space-delimited string, but providers
|
|
7
|
-
* vary: some (e.g. Twitch) return an already-split array. Accept both, plus the
|
|
8
|
-
* omitted/empty case, without ever calling `.split` on a non-string. Returns
|
|
9
|
-
* `[]` when no scope is present.
|
|
10
|
-
*
|
|
11
|
-
* @see https://github.com/better-auth/better-auth/issues/9076
|
|
12
|
-
*/
|
|
13
|
-
export function parseScopeField(scope: unknown): string[] {
|
|
14
|
-
if (Array.isArray(scope))
|
|
15
|
-
return scope.filter((s): s is string => typeof s === "string" && s !== "");
|
|
16
|
-
if (typeof scope === "string") return scope.split(" ").filter(Boolean);
|
|
17
|
-
return [];
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Normalize a scope set into a single deduped, sorted array.
|
|
22
|
-
*
|
|
23
|
-
* Scope order is insignificant per RFC 6749 §3.3, so normalize for idempotent
|
|
24
|
-
* writes and trivial comparisons: trim each token, drop empties, dedupe, and
|
|
25
|
-
* sort ascending. Returns `[]` when the union is empty.
|
|
26
|
-
*
|
|
27
|
-
* @see https://www.rfc-editor.org/rfc/rfc6749#section-3.3
|
|
28
|
-
*/
|
|
29
|
-
export function normalizeScopes(
|
|
30
|
-
stored: string[] | null | undefined,
|
|
31
|
-
incoming?: string[] | undefined,
|
|
32
|
-
): string[] {
|
|
33
|
-
const normalized = new Set<string>();
|
|
34
|
-
for (const scope of [...(stored ?? []), ...(incoming ?? [])]) {
|
|
35
|
-
const trimmed = scope.trim();
|
|
36
|
-
if (trimmed) normalized.add(trimmed);
|
|
37
|
-
}
|
|
38
|
-
return [...normalized].sort();
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Union the stored granted-scope set with the scopes observed on an
|
|
43
|
-
* authorization or token exchange.
|
|
44
|
-
*
|
|
45
|
-
* The provider's echoed `scope` is authoritative when present. RFC 6749 §3.3
|
|
46
|
-
* and §5.1 say an omitted or empty echo means the grant equals what was
|
|
47
|
-
* requested, so fall back to `requested` in that case. The result unions onto
|
|
48
|
-
* the stored grant (never narrows on a normal write) and is normalized per
|
|
49
|
-
* {@link normalizeScopes}.
|
|
50
|
-
*
|
|
51
|
-
* @see https://www.rfc-editor.org/rfc/rfc6749#section-3.3
|
|
52
|
-
* @see https://www.rfc-editor.org/rfc/rfc6749#section-5.1
|
|
53
|
-
*/
|
|
54
|
-
export function unionGrantedScopes(
|
|
55
|
-
stored: string[] | null | undefined,
|
|
56
|
-
echoed: string[] | undefined,
|
|
57
|
-
requested: string[] | undefined,
|
|
58
|
-
): string[] {
|
|
59
|
-
const granted = echoed?.length ? echoed : requested;
|
|
60
|
-
return normalizeScopes(stored, granted);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Coerce a stored granted-scope value into a usable array.
|
|
65
|
-
*
|
|
66
|
-
* `account.grantedScopes` is nullable (legacy rows and non-OAuth accounts read
|
|
67
|
-
* as unset), and on dialects that store the array as a JSON string a malformed
|
|
68
|
-
* operator backfill could deserialize to a non-array. Both collapse to `[]`
|
|
69
|
-
* here so every reader works against a real `string[]` without re-deriving the
|
|
70
|
-
* guard.
|
|
71
|
-
*/
|
|
72
|
-
export function readGrantedScopes(
|
|
73
|
-
stored: string[] | null | undefined,
|
|
74
|
-
): string[] {
|
|
75
|
-
return Array.isArray(stored) ? stored : [];
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Test whether a normalized granted-scope set contains a specific scope.
|
|
80
|
-
*
|
|
81
|
-
* Matching is exact and case-sensitive per RFC 6749 §3.3. The argument is the
|
|
82
|
-
* normalized `account.grantedScopes` array; a raw provider `scope` string must
|
|
83
|
-
* be run through {@link parseScopeField} first.
|
|
84
|
-
*
|
|
85
|
-
* @see https://www.rfc-editor.org/rfc/rfc6749#section-3.3
|
|
86
|
-
*/
|
|
87
|
-
export function includesGrantedScope(
|
|
88
|
-
granted: string[] | null | undefined,
|
|
89
|
-
scope: string,
|
|
90
|
-
): boolean {
|
|
91
|
-
return granted?.includes(scope) ?? false;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Compose the effective scope set to encode in a single authorization URL.
|
|
96
|
-
*
|
|
97
|
-
* Precedence: the provider's built-in defaults (unless `disableDefaultScope`),
|
|
98
|
-
* then the integrator's configured `options.scope`, then the per-request
|
|
99
|
-
* `scopes`. The result is the value persisted into OAuth state as the RFC 6749
|
|
100
|
-
* §5.1 fallback, so it is preserved verbatim (not normalized) to match what is
|
|
101
|
-
* sent to the provider.
|
|
102
|
-
*
|
|
103
|
-
* `defaultScopes` is a parameter rather than a provider-contract field so the
|
|
104
|
-
* runtime-synthesized generic OAuth provider, which has no static default set,
|
|
105
|
-
* can pass its configured scopes here.
|
|
106
|
-
*
|
|
107
|
-
* @see https://www.rfc-editor.org/rfc/rfc6749#section-5.1
|
|
108
|
-
*/
|
|
109
|
-
export function resolveRequestedScopes(
|
|
110
|
-
options: Pick<ProviderOptions, "scope" | "disableDefaultScope"> | undefined,
|
|
111
|
-
defaultScopes: string[],
|
|
112
|
-
perRequestScopes: string[] | undefined,
|
|
113
|
-
): string[] {
|
|
114
|
-
const scopes = options?.disableDefaultScope ? [] : [...defaultScopes];
|
|
115
|
-
if (options?.scope) scopes.push(...options.scope);
|
|
116
|
-
if (perRequestScopes) scopes.push(...perRequestScopes);
|
|
117
|
-
return scopes;
|
|
118
|
-
}
|