@better-auth/core 1.7.0-beta.2 → 1.7.0-beta.4
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/context/global.mjs +1 -1
- package/dist/db/adapter/factory.mjs +64 -3
- package/dist/db/adapter/index.d.mts +35 -1
- package/dist/db/adapter/types.d.mts +1 -1
- package/dist/db/type.d.mts +12 -0
- package/dist/error/codes.d.mts +1 -0
- package/dist/error/codes.mjs +1 -0
- package/dist/instrumentation/tracer.mjs +1 -1
- package/dist/oauth2/authorization-params.d.mts +12 -0
- package/dist/oauth2/authorization-params.mjs +12 -0
- package/dist/oauth2/basic-credentials.d.mts +30 -0
- package/dist/oauth2/basic-credentials.mjs +64 -0
- package/dist/oauth2/client-assertion.d.mts +38 -22
- package/dist/oauth2/client-assertion.mjs +63 -28
- package/dist/oauth2/client-credentials-token.d.mts +19 -40
- package/dist/oauth2/client-credentials-token.mjs +18 -29
- package/dist/oauth2/create-authorization-url.d.mts +9 -1
- package/dist/oauth2/create-authorization-url.mjs +23 -5
- package/dist/oauth2/index.d.mts +10 -7
- package/dist/oauth2/index.mjs +9 -7
- package/dist/oauth2/oauth-provider.d.mts +21 -2
- package/dist/oauth2/refresh-access-token.d.mts +20 -40
- package/dist/oauth2/refresh-access-token.mjs +19 -32
- package/dist/oauth2/token-endpoint-auth.d.mts +17 -0
- package/dist/oauth2/token-endpoint-auth.mjs +89 -0
- package/dist/oauth2/utils.d.mts +9 -1
- package/dist/oauth2/utils.mjs +12 -1
- package/dist/oauth2/validate-authorization-code.d.mts +17 -52
- package/dist/oauth2/validate-authorization-code.mjs +17 -30
- package/dist/oauth2/verify.mjs +15 -5
- package/dist/social-providers/apple.d.mts +5 -12
- package/dist/social-providers/apple.mjs +14 -3
- package/dist/social-providers/atlassian.d.mts +3 -1
- package/dist/social-providers/atlassian.mjs +5 -2
- package/dist/social-providers/cognito.d.mts +16 -1
- package/dist/social-providers/cognito.mjs +6 -2
- package/dist/social-providers/discord.d.mts +5 -3
- package/dist/social-providers/discord.mjs +16 -3
- package/dist/social-providers/dropbox.d.mts +3 -1
- package/dist/social-providers/dropbox.mjs +5 -4
- package/dist/social-providers/facebook.d.mts +5 -3
- package/dist/social-providers/facebook.mjs +6 -3
- package/dist/social-providers/figma.d.mts +3 -1
- package/dist/social-providers/figma.mjs +3 -2
- package/dist/social-providers/github.d.mts +4 -2
- package/dist/social-providers/github.mjs +5 -4
- package/dist/social-providers/gitlab.d.mts +3 -1
- package/dist/social-providers/gitlab.mjs +3 -2
- package/dist/social-providers/google.d.mts +3 -1
- package/dist/social-providers/google.mjs +5 -2
- package/dist/social-providers/huggingface.d.mts +3 -1
- package/dist/social-providers/huggingface.mjs +3 -2
- package/dist/social-providers/index.d.mts +104 -36
- package/dist/social-providers/kakao.d.mts +3 -1
- package/dist/social-providers/kakao.mjs +3 -2
- package/dist/social-providers/kick.d.mts +3 -1
- package/dist/social-providers/kick.mjs +3 -2
- package/dist/social-providers/line.d.mts +3 -1
- package/dist/social-providers/line.mjs +3 -2
- package/dist/social-providers/linear.d.mts +3 -1
- package/dist/social-providers/linear.mjs +3 -2
- package/dist/social-providers/linkedin.d.mts +5 -3
- package/dist/social-providers/linkedin.mjs +4 -3
- package/dist/social-providers/microsoft-entra-id.d.mts +3 -2
- package/dist/social-providers/microsoft-entra-id.mjs +3 -2
- package/dist/social-providers/naver.d.mts +3 -1
- package/dist/social-providers/naver.mjs +3 -2
- package/dist/social-providers/notion.d.mts +3 -1
- package/dist/social-providers/notion.mjs +5 -2
- package/dist/social-providers/paybin.d.mts +3 -1
- package/dist/social-providers/paybin.mjs +3 -2
- package/dist/social-providers/paypal.d.mts +3 -1
- package/dist/social-providers/paypal.mjs +4 -3
- package/dist/social-providers/polar.d.mts +3 -1
- package/dist/social-providers/polar.mjs +3 -2
- package/dist/social-providers/railway.d.mts +3 -1
- package/dist/social-providers/railway.mjs +3 -2
- package/dist/social-providers/reddit.d.mts +3 -1
- package/dist/social-providers/reddit.mjs +3 -2
- package/dist/social-providers/roblox.d.mts +4 -2
- package/dist/social-providers/roblox.mjs +12 -2
- package/dist/social-providers/salesforce.d.mts +3 -1
- package/dist/social-providers/salesforce.mjs +3 -2
- package/dist/social-providers/slack.d.mts +4 -2
- package/dist/social-providers/slack.mjs +11 -8
- package/dist/social-providers/spotify.d.mts +3 -1
- package/dist/social-providers/spotify.mjs +3 -2
- package/dist/social-providers/tiktok.d.mts +3 -1
- package/dist/social-providers/tiktok.mjs +14 -2
- package/dist/social-providers/twitch.d.mts +3 -1
- package/dist/social-providers/twitch.mjs +3 -2
- package/dist/social-providers/twitter.d.mts +5 -2
- package/dist/social-providers/twitter.mjs +2 -1
- package/dist/social-providers/vercel.d.mts +3 -1
- package/dist/social-providers/vercel.mjs +3 -2
- package/dist/social-providers/vk.d.mts +3 -1
- package/dist/social-providers/vk.mjs +3 -2
- package/dist/social-providers/wechat.d.mts +3 -1
- package/dist/social-providers/wechat.mjs +7 -1
- package/dist/social-providers/zoom.d.mts +4 -2
- package/dist/social-providers/zoom.mjs +10 -17
- package/dist/types/context.d.mts +30 -4
- package/dist/types/init-options.d.mts +29 -5
- package/dist/utils/ip.d.mts +5 -4
- package/dist/utils/ip.mjs +3 -3
- package/dist/utils/redirect-uri.d.mts +20 -0
- package/dist/utils/redirect-uri.mjs +48 -0
- package/dist/utils/string.d.mts +5 -1
- package/dist/utils/string.mjs +20 -1
- package/dist/utils/url.d.mts +18 -1
- package/dist/utils/url.mjs +30 -1
- package/package.json +9 -8
- package/src/db/adapter/factory.ts +121 -3
- package/src/db/adapter/index.ts +32 -0
- package/src/db/adapter/types.ts +1 -0
- package/src/db/get-tables.ts +2 -0
- package/src/db/schema/user.ts +3 -0
- package/src/db/type.ts +12 -0
- package/src/error/codes.ts +1 -0
- package/src/oauth2/authorization-params.ts +28 -0
- package/src/oauth2/basic-credentials.ts +87 -0
- package/src/oauth2/client-assertion.ts +131 -58
- package/src/oauth2/client-credentials-token.ts +48 -72
- package/src/oauth2/create-authorization-url.ts +28 -6
- package/src/oauth2/index.ts +25 -9
- package/src/oauth2/oauth-provider.ts +21 -2
- package/src/oauth2/refresh-access-token.ts +50 -76
- package/src/oauth2/token-endpoint-auth.ts +221 -0
- package/src/oauth2/utils.ts +19 -0
- package/src/oauth2/validate-authorization-code.ts +55 -85
- package/src/oauth2/verify.ts +20 -4
- package/src/social-providers/apple.ts +27 -3
- package/src/social-providers/atlassian.ts +8 -1
- package/src/social-providers/cognito.ts +26 -1
- package/src/social-providers/discord.ts +22 -18
- package/src/social-providers/dropbox.ts +7 -5
- package/src/social-providers/facebook.ts +14 -9
- package/src/social-providers/figma.ts +8 -1
- package/src/social-providers/github.ts +5 -3
- package/src/social-providers/gitlab.ts +2 -0
- package/src/social-providers/google.ts +2 -0
- package/src/social-providers/huggingface.ts +8 -1
- package/src/social-providers/kakao.ts +2 -1
- package/src/social-providers/kick.ts +8 -1
- package/src/social-providers/line.ts +2 -0
- package/src/social-providers/linear.ts +8 -1
- package/src/social-providers/linkedin.ts +5 -3
- package/src/social-providers/microsoft-entra-id.ts +2 -1
- package/src/social-providers/naver.ts +2 -1
- package/src/social-providers/notion.ts +8 -1
- package/src/social-providers/paybin.ts +2 -0
- package/src/social-providers/paypal.ts +7 -1
- package/src/social-providers/polar.ts +8 -1
- package/src/social-providers/railway.ts +8 -1
- package/src/social-providers/reddit.ts +2 -1
- package/src/social-providers/roblox.ts +16 -11
- package/src/social-providers/salesforce.ts +8 -1
- package/src/social-providers/slack.ts +15 -9
- package/src/social-providers/spotify.ts +8 -1
- package/src/social-providers/tiktok.ts +22 -9
- package/src/social-providers/twitch.ts +2 -1
- package/src/social-providers/twitter.ts +1 -0
- package/src/social-providers/vercel.ts +8 -1
- package/src/social-providers/vk.ts +8 -1
- package/src/social-providers/wechat.ts +9 -1
- package/src/social-providers/zoom.ts +15 -19
- package/src/types/context.ts +33 -5
- package/src/types/init-options.ts +29 -5
- package/src/utils/ip.ts +12 -13
- package/src/utils/redirect-uri.ts +54 -0
- package/src/utils/string.ts +37 -0
- package/src/utils/url.ts +28 -0
|
@@ -1,72 +1,70 @@
|
|
|
1
|
-
import { base64 } from "@better-auth/utils/base64";
|
|
2
1
|
import { betterFetch } from "@better-fetch/fetch";
|
|
3
2
|
import type { AwaitableFunction } from "../types";
|
|
4
|
-
import type { ClientAssertionConfig } from "./client-assertion";
|
|
5
|
-
import { resolveAssertionParams } from "./client-assertion";
|
|
6
3
|
import type { OAuth2Tokens, ProviderOptions } from "./oauth-provider";
|
|
4
|
+
import type {
|
|
5
|
+
TokenEndpointAuth,
|
|
6
|
+
TokenEndpointSecretAuthentication,
|
|
7
|
+
} from "./token-endpoint-auth";
|
|
8
|
+
import { applyTokenEndpointAuth } from "./token-endpoint-auth";
|
|
9
|
+
|
|
10
|
+
interface ClientCredentialsTokenRequestInput {
|
|
11
|
+
options: AwaitableFunction<ProviderOptions>;
|
|
12
|
+
scope?: string | undefined;
|
|
13
|
+
authentication?: TokenEndpointSecretAuthentication | undefined;
|
|
14
|
+
tokenEndpointAuth?: TokenEndpointAuth | undefined;
|
|
15
|
+
tokenEndpoint?: string | undefined;
|
|
16
|
+
resource?: (string | string[]) | undefined;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface ClientCredentialsTokenRequestBaseInput {
|
|
20
|
+
options: ProviderOptions;
|
|
21
|
+
scope?: string | undefined;
|
|
22
|
+
resource?: (string | string[]) | undefined;
|
|
23
|
+
extraParams?: Record<string, string> | undefined;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface ClientCredentialsTokenInput
|
|
27
|
+
extends ClientCredentialsTokenRequestInput {
|
|
28
|
+
tokenEndpoint: string;
|
|
29
|
+
scope: string;
|
|
30
|
+
}
|
|
7
31
|
|
|
8
32
|
export async function clientCredentialsTokenRequest({
|
|
9
33
|
options,
|
|
10
34
|
scope,
|
|
11
35
|
authentication,
|
|
12
|
-
|
|
36
|
+
tokenEndpointAuth,
|
|
13
37
|
tokenEndpoint,
|
|
14
38
|
resource,
|
|
15
|
-
}: {
|
|
16
|
-
options: AwaitableFunction<ProviderOptions>;
|
|
17
|
-
scope?: string | undefined;
|
|
18
|
-
authentication?: ("basic" | "post" | "private_key_jwt") | undefined;
|
|
19
|
-
clientAssertion?: ClientAssertionConfig | undefined;
|
|
20
|
-
/** Token endpoint URL. Used as the JWT `aud` claim when signing assertions. */
|
|
21
|
-
tokenEndpoint?: string | undefined;
|
|
22
|
-
resource?: (string | string[]) | undefined;
|
|
23
|
-
}) {
|
|
39
|
+
}: ClientCredentialsTokenRequestInput) {
|
|
24
40
|
options = typeof options === "function" ? await options() : options;
|
|
25
|
-
|
|
26
|
-
let extraParams: Record<string, string> | undefined;
|
|
27
|
-
if (authentication === "private_key_jwt") {
|
|
28
|
-
if (!clientAssertion) {
|
|
29
|
-
throw new Error(
|
|
30
|
-
"private_key_jwt authentication requires a clientAssertion configuration",
|
|
31
|
-
);
|
|
32
|
-
}
|
|
33
|
-
const primaryClientId = Array.isArray(options.clientId)
|
|
34
|
-
? options.clientId[0]
|
|
35
|
-
: options.clientId;
|
|
36
|
-
extraParams = await resolveAssertionParams({
|
|
37
|
-
clientAssertion,
|
|
38
|
-
clientId: primaryClientId,
|
|
39
|
-
tokenEndpoint,
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return createClientCredentialsTokenRequest({
|
|
41
|
+
const request = buildClientCredentialsTokenRequest({
|
|
44
42
|
options,
|
|
45
43
|
scope,
|
|
46
|
-
authentication,
|
|
47
44
|
resource,
|
|
48
|
-
extraParams,
|
|
49
45
|
});
|
|
46
|
+
|
|
47
|
+
await applyTokenEndpointAuth({
|
|
48
|
+
body: request.body,
|
|
49
|
+
headers: request.headers,
|
|
50
|
+
options,
|
|
51
|
+
tokenEndpoint: tokenEndpoint ?? "",
|
|
52
|
+
grantType: "client_credentials",
|
|
53
|
+
tokenEndpointAuth,
|
|
54
|
+
authentication,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
return request;
|
|
50
58
|
}
|
|
51
59
|
|
|
52
|
-
|
|
53
|
-
* @deprecated use async'd clientCredentialsTokenRequest instead
|
|
54
|
-
*/
|
|
55
|
-
export function createClientCredentialsTokenRequest({
|
|
60
|
+
function buildClientCredentialsTokenRequest({
|
|
56
61
|
options,
|
|
57
62
|
scope,
|
|
58
|
-
authentication,
|
|
59
63
|
resource,
|
|
60
64
|
extraParams,
|
|
61
|
-
}: {
|
|
62
|
-
options: ProviderOptions;
|
|
63
|
-
scope?: string | undefined;
|
|
64
|
-
authentication?: ("basic" | "post" | "private_key_jwt") | undefined;
|
|
65
|
-
resource?: (string | string[]) | undefined;
|
|
66
|
-
extraParams?: Record<string, string> | undefined;
|
|
67
|
-
}) {
|
|
65
|
+
}: ClientCredentialsTokenRequestBaseInput) {
|
|
68
66
|
const body = new URLSearchParams();
|
|
69
|
-
const headers: Record<string,
|
|
67
|
+
const headers: Record<string, string> = {
|
|
70
68
|
"content-type": "application/x-www-form-urlencoded",
|
|
71
69
|
accept: "application/json",
|
|
72
70
|
};
|
|
@@ -82,21 +80,6 @@ export function createClientCredentialsTokenRequest({
|
|
|
82
80
|
}
|
|
83
81
|
}
|
|
84
82
|
}
|
|
85
|
-
const primaryClientId = Array.isArray(options.clientId)
|
|
86
|
-
? options.clientId[0]
|
|
87
|
-
: options.clientId;
|
|
88
|
-
if (authentication === "basic") {
|
|
89
|
-
const encodedCredentials = base64.encode(
|
|
90
|
-
`${primaryClientId}:${options.clientSecret ?? ""}`,
|
|
91
|
-
);
|
|
92
|
-
headers["authorization"] = `Basic ${encodedCredentials}`;
|
|
93
|
-
} else {
|
|
94
|
-
body.set("client_id", primaryClientId);
|
|
95
|
-
if (authentication !== "private_key_jwt" && options.clientSecret) {
|
|
96
|
-
body.set("client_secret", options.clientSecret);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
83
|
if (extraParams) {
|
|
101
84
|
for (const [key, value] of Object.entries(extraParams)) {
|
|
102
85
|
if (!body.has(key)) body.append(key, value);
|
|
@@ -114,21 +97,14 @@ export async function clientCredentialsToken({
|
|
|
114
97
|
tokenEndpoint,
|
|
115
98
|
scope,
|
|
116
99
|
authentication,
|
|
117
|
-
|
|
100
|
+
tokenEndpointAuth,
|
|
118
101
|
resource,
|
|
119
|
-
}: {
|
|
120
|
-
options: AwaitableFunction<ProviderOptions>;
|
|
121
|
-
tokenEndpoint: string;
|
|
122
|
-
scope: string;
|
|
123
|
-
authentication?: ("basic" | "post" | "private_key_jwt") | undefined;
|
|
124
|
-
clientAssertion?: ClientAssertionConfig | undefined;
|
|
125
|
-
resource?: (string | string[]) | undefined;
|
|
126
|
-
}): Promise<OAuth2Tokens> {
|
|
102
|
+
}: ClientCredentialsTokenInput): Promise<OAuth2Tokens> {
|
|
127
103
|
const { body, headers } = await clientCredentialsTokenRequest({
|
|
128
104
|
options,
|
|
129
105
|
scope,
|
|
130
106
|
authentication,
|
|
131
|
-
|
|
107
|
+
tokenEndpointAuth,
|
|
132
108
|
tokenEndpoint,
|
|
133
109
|
resource,
|
|
134
110
|
});
|
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
import type { AwaitableFunction } from "../types";
|
|
2
2
|
import type { ProviderOptions } from "./index";
|
|
3
|
-
import { generateCodeChallenge } from "./utils";
|
|
3
|
+
import { generateCodeChallenge, getPrimaryClientId } from "./utils";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Query-parameter names that are populated by the framework as part of the
|
|
7
|
+
* authorization request and must not be overridden by caller-supplied
|
|
8
|
+
* `additionalParams`. Overriding `state`, PKCE, or `redirect_uri` would
|
|
9
|
+
* break the callback correlation and session pinning guarantees.
|
|
10
|
+
*/
|
|
11
|
+
export const RESERVED_AUTHORIZATION_PARAMS = [
|
|
12
|
+
"state",
|
|
13
|
+
"client_id",
|
|
14
|
+
"redirect_uri",
|
|
15
|
+
"response_type",
|
|
16
|
+
"code_challenge",
|
|
17
|
+
"code_challenge_method",
|
|
18
|
+
"scope",
|
|
19
|
+
] as const;
|
|
20
|
+
|
|
21
|
+
export const RESERVED_AUTHORIZATION_PARAMS_SET: ReadonlySet<string> = new Set(
|
|
22
|
+
RESERVED_AUTHORIZATION_PARAMS,
|
|
23
|
+
);
|
|
4
24
|
|
|
5
25
|
export async function createAuthorizationURL({
|
|
6
26
|
id,
|
|
@@ -44,9 +64,10 @@ export async function createAuthorizationURL({
|
|
|
44
64
|
options = typeof options === "function" ? await options() : options;
|
|
45
65
|
const url = new URL(options.authorizationEndpoint || authorizationEndpoint);
|
|
46
66
|
url.searchParams.set("response_type", responseType || "code");
|
|
47
|
-
const primaryClientId =
|
|
48
|
-
|
|
49
|
-
|
|
67
|
+
const primaryClientId = getPrimaryClientId(options.clientId);
|
|
68
|
+
if (!primaryClientId) {
|
|
69
|
+
throw new Error("OAuth provider requires clientId");
|
|
70
|
+
}
|
|
50
71
|
url.searchParams.set("client_id", primaryClientId);
|
|
51
72
|
url.searchParams.set("state", state);
|
|
52
73
|
if (scopes) {
|
|
@@ -81,9 +102,10 @@ export async function createAuthorizationURL({
|
|
|
81
102
|
);
|
|
82
103
|
}
|
|
83
104
|
if (additionalParams) {
|
|
84
|
-
|
|
105
|
+
for (const [key, value] of Object.entries(additionalParams)) {
|
|
106
|
+
if (RESERVED_AUTHORIZATION_PARAMS_SET.has(key)) continue;
|
|
85
107
|
url.searchParams.set(key, value);
|
|
86
|
-
}
|
|
108
|
+
}
|
|
87
109
|
}
|
|
88
110
|
return url;
|
|
89
111
|
}
|
package/src/oauth2/index.ts
CHANGED
|
@@ -1,19 +1,31 @@
|
|
|
1
|
+
export { additionalAuthorizationParamsSchema } from "./authorization-params";
|
|
2
|
+
export {
|
|
3
|
+
decodeBasicCredentials,
|
|
4
|
+
encodeBasicCredentials,
|
|
5
|
+
} from "./basic-credentials";
|
|
1
6
|
export type {
|
|
2
|
-
|
|
3
|
-
|
|
7
|
+
ClientAssertionContext,
|
|
8
|
+
ClientAssertionGetter,
|
|
9
|
+
ClientAssertionGrantType,
|
|
10
|
+
PrivateKeyJwtClientAssertionGetterOptions,
|
|
11
|
+
PrivateKeyJwtSigningAlgorithm,
|
|
4
12
|
} from "./client-assertion";
|
|
5
13
|
export {
|
|
6
|
-
ASSERTION_SIGNING_ALGORITHMS,
|
|
7
14
|
CLIENT_ASSERTION_TYPE,
|
|
8
|
-
|
|
9
|
-
|
|
15
|
+
createPrivateKeyJwtClientAssertionGetter,
|
|
16
|
+
PRIVATE_KEY_JWT_SIGNING_ALGORITHMS,
|
|
17
|
+
resolveClientAssertionParams,
|
|
18
|
+
signPrivateKeyJwtClientAssertion,
|
|
10
19
|
} from "./client-assertion";
|
|
11
20
|
export {
|
|
12
21
|
clientCredentialsToken,
|
|
13
22
|
clientCredentialsTokenRequest,
|
|
14
|
-
createClientCredentialsTokenRequest,
|
|
15
23
|
} from "./client-credentials-token";
|
|
16
|
-
export {
|
|
24
|
+
export {
|
|
25
|
+
createAuthorizationURL,
|
|
26
|
+
RESERVED_AUTHORIZATION_PARAMS,
|
|
27
|
+
RESERVED_AUTHORIZATION_PARAMS_SET,
|
|
28
|
+
} from "./create-authorization-url";
|
|
17
29
|
export type {
|
|
18
30
|
OAuth2Tokens,
|
|
19
31
|
OAuth2UserInfo,
|
|
@@ -21,18 +33,22 @@ export type {
|
|
|
21
33
|
ProviderOptions,
|
|
22
34
|
} from "./oauth-provider";
|
|
23
35
|
export {
|
|
24
|
-
createRefreshAccessTokenRequest,
|
|
25
36
|
refreshAccessToken,
|
|
26
37
|
refreshAccessTokenRequest,
|
|
27
38
|
} from "./refresh-access-token";
|
|
39
|
+
export type {
|
|
40
|
+
TokenEndpointAuth,
|
|
41
|
+
TokenEndpointAuthMethod,
|
|
42
|
+
TokenEndpointSecretAuthentication,
|
|
43
|
+
} from "./token-endpoint-auth";
|
|
28
44
|
export {
|
|
45
|
+
applyDefaultAccessTokenExpiry,
|
|
29
46
|
generateCodeChallenge,
|
|
30
47
|
getOAuth2Tokens,
|
|
31
48
|
getPrimaryClientId,
|
|
32
49
|
} from "./utils";
|
|
33
50
|
export {
|
|
34
51
|
authorizationCodeRequest,
|
|
35
|
-
createAuthorizationCodeRequest,
|
|
36
52
|
validateAuthorizationCode,
|
|
37
53
|
validateToken,
|
|
38
54
|
} from "./validate-authorization-code";
|
|
@@ -35,6 +35,13 @@ export interface OAuthProvider<
|
|
|
35
35
|
redirectURI: string;
|
|
36
36
|
display?: string | undefined;
|
|
37
37
|
loginHint?: string | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Extra query parameters to append to the authorization URL.
|
|
40
|
+
* Providers forward these to the shared `createAuthorizationURL` helper,
|
|
41
|
+
* which drops any keys present in `RESERVED_AUTHORIZATION_PARAMS`
|
|
42
|
+
* before applying them.
|
|
43
|
+
*/
|
|
44
|
+
additionalParams?: Record<string, string> | undefined;
|
|
38
45
|
}) => Awaitable<URL>;
|
|
39
46
|
name: string;
|
|
40
47
|
validateAuthorizationCode: (data: {
|
|
@@ -94,6 +101,17 @@ export interface OAuthProvider<
|
|
|
94
101
|
* Disable sign up for new users.
|
|
95
102
|
*/
|
|
96
103
|
disableSignUp?: boolean | undefined;
|
|
104
|
+
/**
|
|
105
|
+
* Accept callbacks that arrive without a `state` parameter. When true,
|
|
106
|
+
* the shared OAuth callback handler restarts the flow server-side with
|
|
107
|
+
* fresh `state` and PKCE instead of rejecting the request. Intended for
|
|
108
|
+
* providers that initiate OAuth without RP-side flow kickoff (e.g.
|
|
109
|
+
* Clever). Leave unset for any provider that always initiates from the
|
|
110
|
+
* RP.
|
|
111
|
+
*
|
|
112
|
+
* @default false
|
|
113
|
+
*/
|
|
114
|
+
allowIdpInitiated?: boolean | undefined;
|
|
97
115
|
/**
|
|
98
116
|
* Options for the provider
|
|
99
117
|
*/
|
|
@@ -104,9 +122,10 @@ export type ProviderOptions<Profile extends Record<string, any> = any> = {
|
|
|
104
122
|
/**
|
|
105
123
|
* The client ID of your application.
|
|
106
124
|
*
|
|
107
|
-
*
|
|
125
|
+
* Some providers accept multiple platform client IDs. The first entry is the
|
|
126
|
+
* primary client ID used for token endpoint client authentication.
|
|
108
127
|
*/
|
|
109
|
-
clientId?:
|
|
128
|
+
clientId?: LiteralString | string[] | undefined;
|
|
110
129
|
/**
|
|
111
130
|
* The client secret of your application
|
|
112
131
|
*/
|
|
@@ -1,99 +1,78 @@
|
|
|
1
|
-
import { base64 } from "@better-auth/utils/base64";
|
|
2
1
|
import { betterFetch } from "@better-fetch/fetch";
|
|
3
2
|
import type { AwaitableFunction } from "../types";
|
|
4
|
-
import type { ClientAssertionConfig } from "./client-assertion";
|
|
5
|
-
import { resolveAssertionParams } from "./client-assertion";
|
|
6
3
|
import type { OAuth2Tokens, ProviderOptions } from "./oauth-provider";
|
|
4
|
+
import type {
|
|
5
|
+
TokenEndpointAuth,
|
|
6
|
+
TokenEndpointSecretAuthentication,
|
|
7
|
+
} from "./token-endpoint-auth";
|
|
8
|
+
import { applyTokenEndpointAuth } from "./token-endpoint-auth";
|
|
9
|
+
|
|
10
|
+
interface RefreshAccessTokenRequestInput {
|
|
11
|
+
refreshToken: string;
|
|
12
|
+
options: AwaitableFunction<Partial<ProviderOptions>>;
|
|
13
|
+
authentication?: TokenEndpointSecretAuthentication | undefined;
|
|
14
|
+
tokenEndpointAuth?: TokenEndpointAuth | undefined;
|
|
15
|
+
tokenEndpoint?: string | undefined;
|
|
16
|
+
extraParams?: Record<string, string> | undefined;
|
|
17
|
+
resource?: (string | string[]) | undefined;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface RefreshAccessTokenRequestBaseInput {
|
|
21
|
+
refreshToken: string;
|
|
22
|
+
options: ProviderOptions;
|
|
23
|
+
extraParams?: Record<string, string> | undefined;
|
|
24
|
+
resource?: (string | string[]) | undefined;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface RefreshAccessTokenInput extends RefreshAccessTokenRequestInput {
|
|
28
|
+
options: Partial<ProviderOptions>;
|
|
29
|
+
tokenEndpoint: string;
|
|
30
|
+
}
|
|
7
31
|
|
|
8
32
|
export async function refreshAccessTokenRequest({
|
|
9
33
|
refreshToken,
|
|
10
34
|
options,
|
|
11
35
|
authentication,
|
|
12
|
-
|
|
36
|
+
tokenEndpointAuth,
|
|
13
37
|
tokenEndpoint,
|
|
14
38
|
extraParams,
|
|
15
39
|
resource,
|
|
16
|
-
}: {
|
|
17
|
-
refreshToken: string;
|
|
18
|
-
options: AwaitableFunction<Partial<ProviderOptions>>;
|
|
19
|
-
authentication?: ("basic" | "post" | "private_key_jwt") | undefined;
|
|
20
|
-
clientAssertion?: ClientAssertionConfig | undefined;
|
|
21
|
-
/** Token endpoint URL. Used as the JWT `aud` claim when signing assertions. */
|
|
22
|
-
tokenEndpoint?: string | undefined;
|
|
23
|
-
extraParams?: Record<string, string> | undefined;
|
|
24
|
-
resource?: (string | string[]) | undefined;
|
|
25
|
-
}) {
|
|
40
|
+
}: RefreshAccessTokenRequestInput) {
|
|
26
41
|
options = typeof options === "function" ? await options() : options;
|
|
27
|
-
|
|
28
|
-
if (authentication === "private_key_jwt") {
|
|
29
|
-
if (!clientAssertion) {
|
|
30
|
-
throw new Error(
|
|
31
|
-
"private_key_jwt authentication requires a clientAssertion configuration",
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
const primaryClientId = Array.isArray(options.clientId)
|
|
35
|
-
? options.clientId[0]
|
|
36
|
-
: options.clientId;
|
|
37
|
-
const assertionParams = await resolveAssertionParams({
|
|
38
|
-
clientAssertion,
|
|
39
|
-
clientId: primaryClientId,
|
|
40
|
-
tokenEndpoint,
|
|
41
|
-
});
|
|
42
|
-
extraParams = { ...extraParams, ...assertionParams };
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return createRefreshAccessTokenRequest({
|
|
42
|
+
const request = buildRefreshAccessTokenRequest({
|
|
46
43
|
refreshToken,
|
|
47
44
|
options,
|
|
48
|
-
authentication,
|
|
49
45
|
extraParams,
|
|
50
46
|
resource,
|
|
51
47
|
});
|
|
48
|
+
|
|
49
|
+
await applyTokenEndpointAuth({
|
|
50
|
+
body: request.body,
|
|
51
|
+
headers: request.headers,
|
|
52
|
+
options,
|
|
53
|
+
tokenEndpoint: tokenEndpoint ?? "",
|
|
54
|
+
grantType: "refresh_token",
|
|
55
|
+
tokenEndpointAuth,
|
|
56
|
+
authentication,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
return request;
|
|
52
60
|
}
|
|
53
61
|
|
|
54
|
-
|
|
55
|
-
* @deprecated use async'd refreshAccessTokenRequest instead
|
|
56
|
-
*/
|
|
57
|
-
export function createRefreshAccessTokenRequest({
|
|
62
|
+
function buildRefreshAccessTokenRequest({
|
|
58
63
|
refreshToken,
|
|
59
64
|
options,
|
|
60
|
-
authentication,
|
|
61
65
|
extraParams,
|
|
62
66
|
resource,
|
|
63
|
-
}: {
|
|
64
|
-
refreshToken: string;
|
|
65
|
-
options: ProviderOptions;
|
|
66
|
-
authentication?: ("basic" | "post" | "private_key_jwt") | undefined;
|
|
67
|
-
extraParams?: Record<string, string> | undefined;
|
|
68
|
-
resource?: (string | string[]) | undefined;
|
|
69
|
-
}) {
|
|
67
|
+
}: RefreshAccessTokenRequestBaseInput) {
|
|
70
68
|
const body = new URLSearchParams();
|
|
71
|
-
const headers: Record<string,
|
|
69
|
+
const headers: Record<string, string> = {
|
|
72
70
|
"content-type": "application/x-www-form-urlencoded",
|
|
73
71
|
accept: "application/json",
|
|
74
72
|
};
|
|
75
73
|
|
|
76
74
|
body.set("grant_type", "refresh_token");
|
|
77
75
|
body.set("refresh_token", refreshToken);
|
|
78
|
-
const primaryClientId = Array.isArray(options.clientId)
|
|
79
|
-
? options.clientId[0]
|
|
80
|
-
: options.clientId;
|
|
81
|
-
if (authentication === "basic") {
|
|
82
|
-
if (primaryClientId) {
|
|
83
|
-
headers["authorization"] =
|
|
84
|
-
"Basic " +
|
|
85
|
-
base64.encode(`${primaryClientId}:${options.clientSecret ?? ""}`);
|
|
86
|
-
} else {
|
|
87
|
-
headers["authorization"] =
|
|
88
|
-
"Basic " + base64.encode(`:${options.clientSecret ?? ""}`);
|
|
89
|
-
}
|
|
90
|
-
} else {
|
|
91
|
-
body.set("client_id", primaryClientId);
|
|
92
|
-
if (authentication !== "private_key_jwt" && options.clientSecret) {
|
|
93
|
-
body.set("client_secret", options.clientSecret);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
76
|
if (resource) {
|
|
98
77
|
if (typeof resource === "string") {
|
|
99
78
|
body.append("resource", resource);
|
|
@@ -120,23 +99,18 @@ export async function refreshAccessToken({
|
|
|
120
99
|
options,
|
|
121
100
|
tokenEndpoint,
|
|
122
101
|
authentication,
|
|
123
|
-
|
|
102
|
+
tokenEndpointAuth,
|
|
124
103
|
extraParams,
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
options: Partial<ProviderOptions>;
|
|
128
|
-
tokenEndpoint: string;
|
|
129
|
-
authentication?: ("basic" | "post" | "private_key_jwt") | undefined;
|
|
130
|
-
clientAssertion?: ClientAssertionConfig | undefined;
|
|
131
|
-
extraParams?: Record<string, string> | undefined;
|
|
132
|
-
}): Promise<OAuth2Tokens> {
|
|
104
|
+
resource,
|
|
105
|
+
}: RefreshAccessTokenInput): Promise<OAuth2Tokens> {
|
|
133
106
|
const { body, headers } = await refreshAccessTokenRequest({
|
|
134
107
|
refreshToken,
|
|
135
108
|
options,
|
|
136
109
|
authentication,
|
|
137
|
-
|
|
110
|
+
tokenEndpointAuth,
|
|
138
111
|
tokenEndpoint,
|
|
139
112
|
extraParams,
|
|
113
|
+
resource,
|
|
140
114
|
});
|
|
141
115
|
|
|
142
116
|
const { data, error } = await betterFetch<{
|