@better-auth/core 1.7.0-beta.3 → 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 +63 -1
- 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 +4 -18
- 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 +4 -2
- 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 +3 -1
- package/dist/social-providers/facebook.mjs +5 -2
- package/dist/social-providers/figma.d.mts +3 -1
- package/dist/social-providers/figma.mjs +3 -2
- package/dist/social-providers/github.d.mts +3 -1
- 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 +3 -1
- package/dist/social-providers/linkedin.mjs +3 -2
- package/dist/social-providers/microsoft-entra-id.d.mts +2 -1
- 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 +23 -3
- 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 +118 -0
- package/src/db/adapter/index.ts +32 -0
- package/src/db/adapter/types.ts +1 -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 +26 -2
- package/src/social-providers/atlassian.ts +8 -1
- package/src/social-providers/cognito.ts +26 -1
- package/src/social-providers/discord.ts +21 -17
- package/src/social-providers/dropbox.ts +7 -5
- package/src/social-providers/facebook.ts +11 -6
- package/src/social-providers/figma.ts +8 -1
- package/src/social-providers/github.ts +4 -2
- 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 +2 -0
- package/src/social-providers/microsoft-entra-id.ts +1 -0
- 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 +25 -4
- 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,64 +1,41 @@
|
|
|
1
|
-
import { ClientAssertionConfig } from "./client-assertion.mjs";
|
|
2
1
|
import { AwaitableFunction } from "../types/helper.mjs";
|
|
3
2
|
import { OAuth2Tokens, ProviderOptions } from "./oauth-provider.mjs";
|
|
3
|
+
import { TokenEndpointAuth, TokenEndpointSecretAuthentication } from "./token-endpoint-auth.mjs";
|
|
4
4
|
import * as jose from "jose";
|
|
5
5
|
|
|
6
6
|
//#region src/oauth2/validate-authorization-code.d.ts
|
|
7
|
-
|
|
8
|
-
code,
|
|
9
|
-
codeVerifier,
|
|
10
|
-
redirectURI,
|
|
11
|
-
options,
|
|
12
|
-
authentication,
|
|
13
|
-
clientAssertion,
|
|
14
|
-
tokenEndpoint,
|
|
15
|
-
deviceId,
|
|
16
|
-
headers,
|
|
17
|
-
additionalParams,
|
|
18
|
-
resource
|
|
19
|
-
}: {
|
|
7
|
+
interface AuthorizationCodeRequestInput {
|
|
20
8
|
code: string;
|
|
21
9
|
redirectURI: string;
|
|
22
10
|
options: AwaitableFunction<Partial<ProviderOptions>>;
|
|
23
11
|
codeVerifier?: string | undefined;
|
|
24
12
|
deviceId?: string | undefined;
|
|
25
|
-
authentication?:
|
|
26
|
-
|
|
13
|
+
authentication?: TokenEndpointSecretAuthentication | undefined;
|
|
14
|
+
tokenEndpointAuth?: TokenEndpointAuth | undefined;
|
|
27
15
|
tokenEndpoint?: string | undefined;
|
|
28
16
|
headers?: Record<string, string> | undefined;
|
|
29
17
|
additionalParams?: Record<string, string> | undefined;
|
|
30
18
|
resource?: (string | string[]) | undefined;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
* @deprecated use async'd authorizationCodeRequest instead
|
|
37
|
-
*/
|
|
38
|
-
declare function createAuthorizationCodeRequest({
|
|
19
|
+
}
|
|
20
|
+
interface ValidateAuthorizationCodeInput extends AuthorizationCodeRequestInput {
|
|
21
|
+
tokenEndpoint: string;
|
|
22
|
+
}
|
|
23
|
+
declare function authorizationCodeRequest({
|
|
39
24
|
code,
|
|
40
25
|
codeVerifier,
|
|
41
26
|
redirectURI,
|
|
42
27
|
options,
|
|
43
28
|
authentication,
|
|
29
|
+
tokenEndpointAuth,
|
|
30
|
+
tokenEndpoint,
|
|
44
31
|
deviceId,
|
|
45
32
|
headers,
|
|
46
33
|
additionalParams,
|
|
47
34
|
resource
|
|
48
|
-
}: {
|
|
49
|
-
code: string;
|
|
50
|
-
redirectURI: string;
|
|
51
|
-
options: Partial<ProviderOptions>;
|
|
52
|
-
codeVerifier?: string | undefined;
|
|
53
|
-
deviceId?: string | undefined;
|
|
54
|
-
authentication?: ("basic" | "post" | "private_key_jwt") | undefined;
|
|
55
|
-
headers?: Record<string, string> | undefined;
|
|
56
|
-
additionalParams?: Record<string, string> | undefined;
|
|
57
|
-
resource?: (string | string[]) | undefined;
|
|
58
|
-
}): {
|
|
35
|
+
}: AuthorizationCodeRequestInput): Promise<{
|
|
59
36
|
body: URLSearchParams;
|
|
60
|
-
headers: Record<string,
|
|
61
|
-
}
|
|
37
|
+
headers: Record<string, string>;
|
|
38
|
+
}>;
|
|
62
39
|
declare function validateAuthorizationCode({
|
|
63
40
|
code,
|
|
64
41
|
codeVerifier,
|
|
@@ -66,27 +43,15 @@ declare function validateAuthorizationCode({
|
|
|
66
43
|
options,
|
|
67
44
|
tokenEndpoint,
|
|
68
45
|
authentication,
|
|
69
|
-
|
|
46
|
+
tokenEndpointAuth,
|
|
70
47
|
deviceId,
|
|
71
48
|
headers,
|
|
72
49
|
additionalParams,
|
|
73
50
|
resource
|
|
74
|
-
}:
|
|
75
|
-
code: string;
|
|
76
|
-
redirectURI: string;
|
|
77
|
-
options: AwaitableFunction<Partial<ProviderOptions>>;
|
|
78
|
-
codeVerifier?: string | undefined;
|
|
79
|
-
deviceId?: string | undefined;
|
|
80
|
-
tokenEndpoint: string;
|
|
81
|
-
authentication?: ("basic" | "post" | "private_key_jwt") | undefined;
|
|
82
|
-
clientAssertion?: ClientAssertionConfig | undefined;
|
|
83
|
-
headers?: Record<string, string> | undefined;
|
|
84
|
-
additionalParams?: Record<string, string> | undefined;
|
|
85
|
-
resource?: (string | string[]) | undefined;
|
|
86
|
-
}): Promise<OAuth2Tokens>;
|
|
51
|
+
}: ValidateAuthorizationCodeInput): Promise<OAuth2Tokens>;
|
|
87
52
|
declare function validateToken(token: string, jwksEndpoint: string, options?: {
|
|
88
53
|
audience?: string | string[];
|
|
89
54
|
issuer?: string | string[];
|
|
90
55
|
}): Promise<jose.JWTVerifyResult<jose.JWTPayload> & jose.ResolvedKey>;
|
|
91
56
|
//#endregion
|
|
92
|
-
export { authorizationCodeRequest,
|
|
57
|
+
export { authorizationCodeRequest, validateAuthorizationCode, validateToken };
|
|
@@ -1,39 +1,32 @@
|
|
|
1
|
-
import { resolveAssertionParams } from "./client-assertion.mjs";
|
|
2
1
|
import { getOAuth2Tokens } from "./utils.mjs";
|
|
2
|
+
import { applyTokenEndpointAuth } from "./token-endpoint-auth.mjs";
|
|
3
3
|
import { createRemoteJWKSet, jwtVerify } from "jose";
|
|
4
|
-
import { base64 } from "@better-auth/utils/base64";
|
|
5
4
|
import { betterFetch } from "@better-fetch/fetch";
|
|
6
5
|
//#region src/oauth2/validate-authorization-code.ts
|
|
7
|
-
async function authorizationCodeRequest({ code, codeVerifier, redirectURI, options, authentication,
|
|
6
|
+
async function authorizationCodeRequest({ code, codeVerifier, redirectURI, options, authentication, tokenEndpointAuth, tokenEndpoint, deviceId, headers, additionalParams = {}, resource }) {
|
|
8
7
|
options = typeof options === "function" ? await options() : options;
|
|
9
|
-
|
|
10
|
-
if (!clientAssertion) throw new Error("private_key_jwt authentication requires a clientAssertion configuration");
|
|
11
|
-
const assertionParams = await resolveAssertionParams({
|
|
12
|
-
clientAssertion,
|
|
13
|
-
clientId: Array.isArray(options.clientId) ? options.clientId[0] : options.clientId,
|
|
14
|
-
tokenEndpoint
|
|
15
|
-
});
|
|
16
|
-
additionalParams = {
|
|
17
|
-
...additionalParams,
|
|
18
|
-
...assertionParams
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
return createAuthorizationCodeRequest({
|
|
8
|
+
const request = buildAuthorizationCodeRequest({
|
|
22
9
|
code,
|
|
23
10
|
codeVerifier,
|
|
24
11
|
redirectURI,
|
|
25
12
|
options,
|
|
26
|
-
authentication,
|
|
27
13
|
deviceId,
|
|
28
14
|
headers,
|
|
29
15
|
additionalParams,
|
|
30
16
|
resource
|
|
31
17
|
});
|
|
18
|
+
await applyTokenEndpointAuth({
|
|
19
|
+
body: request.body,
|
|
20
|
+
headers: request.headers,
|
|
21
|
+
options,
|
|
22
|
+
tokenEndpoint: tokenEndpoint ?? "",
|
|
23
|
+
grantType: "authorization_code",
|
|
24
|
+
tokenEndpointAuth,
|
|
25
|
+
authentication
|
|
26
|
+
});
|
|
27
|
+
return request;
|
|
32
28
|
}
|
|
33
|
-
|
|
34
|
-
* @deprecated use async'd authorizationCodeRequest instead
|
|
35
|
-
*/
|
|
36
|
-
function createAuthorizationCodeRequest({ code, codeVerifier, redirectURI, options, authentication, deviceId, headers, additionalParams = {}, resource }) {
|
|
29
|
+
function buildAuthorizationCodeRequest({ code, codeVerifier, redirectURI, options, deviceId, headers, additionalParams = {}, resource }) {
|
|
37
30
|
const body = new URLSearchParams();
|
|
38
31
|
const requestHeaders = {
|
|
39
32
|
"content-type": "application/x-www-form-urlencoded",
|
|
@@ -48,26 +41,20 @@ function createAuthorizationCodeRequest({ code, codeVerifier, redirectURI, optio
|
|
|
48
41
|
body.set("redirect_uri", options.redirectURI || redirectURI);
|
|
49
42
|
if (resource) if (typeof resource === "string") body.append("resource", resource);
|
|
50
43
|
else for (const _resource of resource) body.append("resource", _resource);
|
|
51
|
-
const primaryClientId = Array.isArray(options.clientId) ? options.clientId[0] : options.clientId;
|
|
52
|
-
if (authentication === "basic") requestHeaders["authorization"] = `Basic ${base64.encode(`${primaryClientId}:${options.clientSecret ?? ""}`)}`;
|
|
53
|
-
else {
|
|
54
|
-
body.set("client_id", primaryClientId);
|
|
55
|
-
if (authentication !== "private_key_jwt" && options.clientSecret) body.set("client_secret", options.clientSecret);
|
|
56
|
-
}
|
|
57
44
|
for (const [key, value] of Object.entries(additionalParams)) if (!body.has(key)) body.append(key, value);
|
|
58
45
|
return {
|
|
59
46
|
body,
|
|
60
47
|
headers: requestHeaders
|
|
61
48
|
};
|
|
62
49
|
}
|
|
63
|
-
async function validateAuthorizationCode({ code, codeVerifier, redirectURI, options, tokenEndpoint, authentication,
|
|
50
|
+
async function validateAuthorizationCode({ code, codeVerifier, redirectURI, options, tokenEndpoint, authentication, tokenEndpointAuth, deviceId, headers, additionalParams = {}, resource }) {
|
|
64
51
|
const { body, headers: requestHeaders } = await authorizationCodeRequest({
|
|
65
52
|
code,
|
|
66
53
|
codeVerifier,
|
|
67
54
|
redirectURI,
|
|
68
55
|
options,
|
|
69
56
|
authentication,
|
|
70
|
-
|
|
57
|
+
tokenEndpointAuth,
|
|
71
58
|
tokenEndpoint,
|
|
72
59
|
deviceId,
|
|
73
60
|
headers,
|
|
@@ -89,4 +76,4 @@ async function validateToken(token, jwksEndpoint, options) {
|
|
|
89
76
|
});
|
|
90
77
|
}
|
|
91
78
|
//#endregion
|
|
92
|
-
export { authorizationCodeRequest,
|
|
79
|
+
export { authorizationCodeRequest, validateAuthorizationCode, validateToken };
|
package/dist/oauth2/verify.mjs
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import { logger } from "../env/logger.mjs";
|
|
2
2
|
import { APIError } from "better-call";
|
|
3
|
-
import { UnsecuredJWT, createLocalJWKSet, decodeProtectedHeader, jwtVerify } from "jose";
|
|
3
|
+
import { UnsecuredJWT, createLocalJWKSet, decodeProtectedHeader, errors, jwtVerify } from "jose";
|
|
4
4
|
import { betterFetch } from "@better-fetch/fetch";
|
|
5
5
|
//#region src/oauth2/verify.ts
|
|
6
|
+
const joseInfrastructureErrorCodes = new Set([
|
|
7
|
+
errors.JWKSTimeout.code,
|
|
8
|
+
errors.JWKSInvalid.code,
|
|
9
|
+
errors.JWKSMultipleMatchingKeys.code
|
|
10
|
+
]);
|
|
11
|
+
function isJoseInfrastructureError(error) {
|
|
12
|
+
return joseInfrastructureErrorCodes.has(error.code);
|
|
13
|
+
}
|
|
6
14
|
/** Last fetched jwks used locally in getJwks @internal */
|
|
7
15
|
let jwks;
|
|
8
16
|
/**
|
|
@@ -28,7 +36,7 @@ async function getJwks(token, opts) {
|
|
|
28
36
|
if (error instanceof Error) throw error;
|
|
29
37
|
throw new Error(error);
|
|
30
38
|
}
|
|
31
|
-
if (!jwtHeaders.kid) throw new
|
|
39
|
+
if (!jwtHeaders.kid) throw new APIError("UNAUTHORIZED", { message: "invalid access token" });
|
|
32
40
|
if (!jwks || !jwks.keys.find((jwk) => jwk.kid === jwtHeaders.kid)) {
|
|
33
41
|
jwks = typeof opts.jwksFetch === "string" ? await betterFetch(opts.jwksFetch, { headers: { Accept: "application/json" } }).then(async (res) => {
|
|
34
42
|
if (res.error) throw new Error(`Jwks failed: ${res.error.message ?? res.error.statusText}`);
|
|
@@ -51,9 +59,11 @@ async function verifyAccessToken(token, opts) {
|
|
|
51
59
|
verifyOptions: opts.verifyOptions
|
|
52
60
|
});
|
|
53
61
|
} catch (error) {
|
|
54
|
-
if (error instanceof Error) if (error.name === "TypeError" || error.name === "JWSInvalid") {} else if (error
|
|
55
|
-
else if (error
|
|
56
|
-
|
|
62
|
+
if (error instanceof Error) if (error.name === "TypeError" || error.name === "JWSInvalid") {} else if (error instanceof errors.JWTExpired) throw new APIError("UNAUTHORIZED", { message: "token expired" });
|
|
63
|
+
else if (error instanceof errors.JOSEError) {
|
|
64
|
+
if (isJoseInfrastructureError(error)) throw error;
|
|
65
|
+
throw new APIError("UNAUTHORIZED", { message: "invalid access token" });
|
|
66
|
+
} else throw error;
|
|
57
67
|
else throw new Error(error);
|
|
58
68
|
}
|
|
59
69
|
if (opts?.remoteVerify) {
|
|
@@ -70,7 +70,8 @@ declare const apple: (options: AppleOptions) => {
|
|
|
70
70
|
createAuthorizationURL({
|
|
71
71
|
state,
|
|
72
72
|
scopes,
|
|
73
|
-
redirectURI
|
|
73
|
+
redirectURI,
|
|
74
|
+
additionalParams
|
|
74
75
|
}: {
|
|
75
76
|
state: string;
|
|
76
77
|
codeVerifier: string;
|
|
@@ -78,6 +79,7 @@ declare const apple: (options: AppleOptions) => {
|
|
|
78
79
|
redirectURI: string;
|
|
79
80
|
display?: string | undefined;
|
|
80
81
|
loginHint?: string | undefined;
|
|
82
|
+
additionalParams?: Record<string, string> | undefined;
|
|
81
83
|
}): Promise<URL>;
|
|
82
84
|
validateAuthorizationCode: ({
|
|
83
85
|
code,
|
|
@@ -93,23 +95,7 @@ declare const apple: (options: AppleOptions) => {
|
|
|
93
95
|
refreshAccessToken: (refreshToken: string) => Promise<OAuth2Tokens>;
|
|
94
96
|
getUserInfo(token: OAuth2Tokens & {
|
|
95
97
|
user?: {
|
|
96
|
-
name
|
|
97
|
-
* An Integer value that indicates whether the user appears to be a real
|
|
98
|
-
* person. Use the value of this claim to mitigate fraud. The possible
|
|
99
|
-
* values are: 0 (or Unsupported), 1 (or Unknown), 2 (or LikelyReal). For
|
|
100
|
-
* more information, see ASUserDetectionStatus. This claim is present only
|
|
101
|
-
* in iOS 14 and later, macOS 11 and later, watchOS 7 and later, tvOS 14
|
|
102
|
-
* and later. The claim isn’t present or supported for web-based apps.
|
|
103
|
-
*/?
|
|
104
|
-
/**
|
|
105
|
-
* An Integer value that indicates whether the user appears to be a real
|
|
106
|
-
* person. Use the value of this claim to mitigate fraud. The possible
|
|
107
|
-
* values are: 0 (or Unsupported), 1 (or Unknown), 2 (or LikelyReal). For
|
|
108
|
-
* more information, see ASUserDetectionStatus. This claim is present only
|
|
109
|
-
* in iOS 14 and later, macOS 11 and later, watchOS 7 and later, tvOS 14
|
|
110
|
-
* and later. The claim isn’t present or supported for web-based apps.
|
|
111
|
-
*/
|
|
112
|
-
: {
|
|
98
|
+
name?: {
|
|
113
99
|
firstName?: string;
|
|
114
100
|
lastName?: string;
|
|
115
101
|
};
|
|
@@ -7,12 +7,22 @@ import { validateAuthorizationCode } from "../oauth2/validate-authorization-code
|
|
|
7
7
|
import { decodeJwt, decodeProtectedHeader, importJWK, jwtVerify } from "jose";
|
|
8
8
|
import { betterFetch } from "@better-fetch/fetch";
|
|
9
9
|
//#region src/social-providers/apple.ts
|
|
10
|
+
async function sha256Hex(value) {
|
|
11
|
+
const data = new TextEncoder().encode(value);
|
|
12
|
+
const digest = await crypto.subtle.digest("SHA-256", data);
|
|
13
|
+
return Array.from(new Uint8Array(digest)).map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
14
|
+
}
|
|
15
|
+
async function nonceMatches(jwtNonce, nonce) {
|
|
16
|
+
if (typeof jwtNonce !== "string") return false;
|
|
17
|
+
if (jwtNonce === nonce) return true;
|
|
18
|
+
return jwtNonce === await sha256Hex(nonce);
|
|
19
|
+
}
|
|
10
20
|
const apple = (options) => {
|
|
11
21
|
const tokenEndpoint = "https://appleid.apple.com/auth/token";
|
|
12
22
|
return {
|
|
13
23
|
id: "apple",
|
|
14
24
|
name: "Apple",
|
|
15
|
-
async createAuthorizationURL({ state, scopes, redirectURI }) {
|
|
25
|
+
async createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) {
|
|
16
26
|
if (!getPrimaryClientId(options.clientId) || !options.clientSecret) {
|
|
17
27
|
logger.error("Client ID and client secret are required for Apple. Make sure to provide them in the options.");
|
|
18
28
|
throw new BetterAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
|
|
@@ -28,7 +38,8 @@ const apple = (options) => {
|
|
|
28
38
|
state,
|
|
29
39
|
redirectURI,
|
|
30
40
|
responseMode: "form_post",
|
|
31
|
-
responseType: "code id_token"
|
|
41
|
+
responseType: "code id_token",
|
|
42
|
+
additionalParams
|
|
32
43
|
});
|
|
33
44
|
},
|
|
34
45
|
validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
|
|
@@ -55,7 +66,7 @@ const apple = (options) => {
|
|
|
55
66
|
["email_verified", "is_private_email"].forEach((field) => {
|
|
56
67
|
if (jwtClaims[field] !== void 0) jwtClaims[field] = Boolean(jwtClaims[field]);
|
|
57
68
|
});
|
|
58
|
-
if (nonce && jwtClaims.nonce
|
|
69
|
+
if (nonce && !await nonceMatches(jwtClaims.nonce, nonce)) return false;
|
|
59
70
|
return !!jwtClaims;
|
|
60
71
|
} catch {
|
|
61
72
|
return false;
|
|
@@ -25,7 +25,8 @@ declare const atlassian: (options: AtlassianOptions) => {
|
|
|
25
25
|
state,
|
|
26
26
|
scopes,
|
|
27
27
|
codeVerifier,
|
|
28
|
-
redirectURI
|
|
28
|
+
redirectURI,
|
|
29
|
+
additionalParams
|
|
29
30
|
}: {
|
|
30
31
|
state: string;
|
|
31
32
|
codeVerifier: string;
|
|
@@ -33,6 +34,7 @@ declare const atlassian: (options: AtlassianOptions) => {
|
|
|
33
34
|
redirectURI: string;
|
|
34
35
|
display?: string | undefined;
|
|
35
36
|
loginHint?: string | undefined;
|
|
37
|
+
additionalParams?: Record<string, string> | undefined;
|
|
36
38
|
}): Promise<URL>;
|
|
37
39
|
validateAuthorizationCode: ({
|
|
38
40
|
code,
|
|
@@ -10,7 +10,7 @@ const atlassian = (options) => {
|
|
|
10
10
|
return {
|
|
11
11
|
id: "atlassian",
|
|
12
12
|
name: "Atlassian",
|
|
13
|
-
async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {
|
|
13
|
+
async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI, additionalParams }) {
|
|
14
14
|
if (!options.clientId || !options.clientSecret) {
|
|
15
15
|
logger.error("Client Id and Secret are required for Atlassian");
|
|
16
16
|
throw new BetterAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
|
|
@@ -27,7 +27,10 @@ const atlassian = (options) => {
|
|
|
27
27
|
state,
|
|
28
28
|
codeVerifier,
|
|
29
29
|
redirectURI,
|
|
30
|
-
additionalParams: {
|
|
30
|
+
additionalParams: {
|
|
31
|
+
...additionalParams ?? {},
|
|
32
|
+
audience: "api.atlassian.com"
|
|
33
|
+
},
|
|
31
34
|
prompt: options.prompt
|
|
32
35
|
});
|
|
33
36
|
},
|
|
@@ -30,6 +30,19 @@ interface CognitoOptions extends ProviderOptions<CognitoProfile> {
|
|
|
30
30
|
region: string;
|
|
31
31
|
userPoolId: string;
|
|
32
32
|
requireClientSecret?: boolean | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Skip the Cognito hosted-UI identity-provider picker by preselecting an
|
|
35
|
+
* IdP (maps to the `identity_provider` query parameter on the authorize
|
|
36
|
+
* request). Accepts `"COGNITO"`, a SAML/OIDC provider name configured on
|
|
37
|
+
* the User Pool, or one of the social providers (`"Google"`, `"Facebook"`,
|
|
38
|
+
* `"LoginWithAmazon"`, `"SignInWithApple"`).
|
|
39
|
+
*
|
|
40
|
+
* Per-request overrides via `signIn.social({ additionalParams: { identity_provider } })`
|
|
41
|
+
* take precedence over this value.
|
|
42
|
+
*
|
|
43
|
+
* @see https://docs.aws.amazon.com/cognito/latest/developerguide/authorization-endpoint.html
|
|
44
|
+
*/
|
|
45
|
+
identityProvider?: string | undefined;
|
|
33
46
|
}
|
|
34
47
|
declare const cognito: (options: CognitoOptions) => {
|
|
35
48
|
id: "cognito";
|
|
@@ -38,7 +51,8 @@ declare const cognito: (options: CognitoOptions) => {
|
|
|
38
51
|
state,
|
|
39
52
|
scopes,
|
|
40
53
|
codeVerifier,
|
|
41
|
-
redirectURI
|
|
54
|
+
redirectURI,
|
|
55
|
+
additionalParams
|
|
42
56
|
}: {
|
|
43
57
|
state: string;
|
|
44
58
|
codeVerifier: string;
|
|
@@ -46,6 +60,7 @@ declare const cognito: (options: CognitoOptions) => {
|
|
|
46
60
|
redirectURI: string;
|
|
47
61
|
display?: string | undefined;
|
|
48
62
|
loginHint?: string | undefined;
|
|
63
|
+
additionalParams?: Record<string, string> | undefined;
|
|
49
64
|
}): Promise<URL>;
|
|
50
65
|
validateAuthorizationCode: ({
|
|
51
66
|
code,
|
|
@@ -19,7 +19,7 @@ const cognito = (options) => {
|
|
|
19
19
|
return {
|
|
20
20
|
id: "cognito",
|
|
21
21
|
name: "Cognito",
|
|
22
|
-
async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {
|
|
22
|
+
async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI, additionalParams }) {
|
|
23
23
|
if (!getPrimaryClientId(options.clientId)) {
|
|
24
24
|
logger.error("ClientId is required for Amazon Cognito. Make sure to provide them in the options.");
|
|
25
25
|
throw new BetterAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
|
|
@@ -43,7 +43,11 @@ const cognito = (options) => {
|
|
|
43
43
|
state,
|
|
44
44
|
codeVerifier,
|
|
45
45
|
redirectURI,
|
|
46
|
-
prompt: options.prompt
|
|
46
|
+
prompt: options.prompt,
|
|
47
|
+
additionalParams: {
|
|
48
|
+
...options.identityProvider ? { identity_provider: options.identityProvider } : {},
|
|
49
|
+
...additionalParams ?? {}
|
|
50
|
+
}
|
|
47
51
|
});
|
|
48
52
|
const scopeValue = url.searchParams.get("scope");
|
|
49
53
|
if (scopeValue) {
|
|
@@ -80,7 +80,8 @@ declare const discord: (options: DiscordOptions) => {
|
|
|
80
80
|
createAuthorizationURL({
|
|
81
81
|
state,
|
|
82
82
|
scopes,
|
|
83
|
-
redirectURI
|
|
83
|
+
redirectURI,
|
|
84
|
+
additionalParams
|
|
84
85
|
}: {
|
|
85
86
|
state: string;
|
|
86
87
|
codeVerifier: string;
|
|
@@ -88,7 +89,8 @@ declare const discord: (options: DiscordOptions) => {
|
|
|
88
89
|
redirectURI: string;
|
|
89
90
|
display?: string | undefined;
|
|
90
91
|
loginHint?: string | undefined;
|
|
91
|
-
|
|
92
|
+
additionalParams?: Record<string, string> | undefined;
|
|
93
|
+
}): Promise<URL>;
|
|
92
94
|
validateAuthorizationCode: ({
|
|
93
95
|
code,
|
|
94
96
|
redirectURI
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
|
|
1
2
|
import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
|
|
2
3
|
import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
|
|
3
4
|
import { betterFetch } from "@better-fetch/fetch";
|
|
@@ -7,12 +8,24 @@ const discord = (options) => {
|
|
|
7
8
|
return {
|
|
8
9
|
id: "discord",
|
|
9
10
|
name: "Discord",
|
|
10
|
-
createAuthorizationURL({ state, scopes, redirectURI }) {
|
|
11
|
+
createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) {
|
|
11
12
|
const _scopes = options.disableDefaultScope ? [] : ["identify", "email"];
|
|
12
13
|
if (scopes) _scopes.push(...scopes);
|
|
13
14
|
if (options.scope) _scopes.push(...options.scope);
|
|
14
|
-
const
|
|
15
|
-
return
|
|
15
|
+
const hasBotScope = _scopes.includes("bot");
|
|
16
|
+
return createAuthorizationURL({
|
|
17
|
+
id: "discord",
|
|
18
|
+
options,
|
|
19
|
+
authorizationEndpoint: "https://discord.com/api/oauth2/authorize",
|
|
20
|
+
scopes: _scopes,
|
|
21
|
+
state,
|
|
22
|
+
redirectURI,
|
|
23
|
+
prompt: options.prompt || "none",
|
|
24
|
+
additionalParams: {
|
|
25
|
+
...hasBotScope && options.permissions !== void 0 ? { permissions: String(options.permissions) } : {},
|
|
26
|
+
...additionalParams ?? {}
|
|
27
|
+
}
|
|
28
|
+
});
|
|
16
29
|
},
|
|
17
30
|
validateAuthorizationCode: async ({ code, redirectURI }) => {
|
|
18
31
|
return validateAuthorizationCode({
|
|
@@ -24,7 +24,8 @@ declare const dropbox: (options: DropboxOptions) => {
|
|
|
24
24
|
state,
|
|
25
25
|
scopes,
|
|
26
26
|
codeVerifier,
|
|
27
|
-
redirectURI
|
|
27
|
+
redirectURI,
|
|
28
|
+
additionalParams
|
|
28
29
|
}: {
|
|
29
30
|
state: string;
|
|
30
31
|
codeVerifier: string;
|
|
@@ -32,6 +33,7 @@ declare const dropbox: (options: DropboxOptions) => {
|
|
|
32
33
|
redirectURI: string;
|
|
33
34
|
display?: string | undefined;
|
|
34
35
|
loginHint?: string | undefined;
|
|
36
|
+
additionalParams?: Record<string, string> | undefined;
|
|
35
37
|
}) => Promise<URL>;
|
|
36
38
|
validateAuthorizationCode: ({
|
|
37
39
|
code,
|
|
@@ -8,12 +8,10 @@ const dropbox = (options) => {
|
|
|
8
8
|
return {
|
|
9
9
|
id: "dropbox",
|
|
10
10
|
name: "Dropbox",
|
|
11
|
-
createAuthorizationURL: async ({ state, scopes, codeVerifier, redirectURI }) => {
|
|
11
|
+
createAuthorizationURL: async ({ state, scopes, codeVerifier, redirectURI, additionalParams }) => {
|
|
12
12
|
const _scopes = options.disableDefaultScope ? [] : ["account_info.read"];
|
|
13
13
|
if (options.scope) _scopes.push(...options.scope);
|
|
14
14
|
if (scopes) _scopes.push(...scopes);
|
|
15
|
-
const additionalParams = {};
|
|
16
|
-
if (options.accessType) additionalParams.token_access_type = options.accessType;
|
|
17
15
|
return await createAuthorizationURL({
|
|
18
16
|
id: "dropbox",
|
|
19
17
|
options,
|
|
@@ -22,7 +20,10 @@ const dropbox = (options) => {
|
|
|
22
20
|
state,
|
|
23
21
|
redirectURI,
|
|
24
22
|
codeVerifier,
|
|
25
|
-
additionalParams
|
|
23
|
+
additionalParams: {
|
|
24
|
+
...options.accessType ? { token_access_type: options.accessType } : {},
|
|
25
|
+
...additionalParams ?? {}
|
|
26
|
+
}
|
|
26
27
|
});
|
|
27
28
|
},
|
|
28
29
|
validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
|
|
@@ -34,7 +34,8 @@ declare const facebook: (options: FacebookOptions) => {
|
|
|
34
34
|
state,
|
|
35
35
|
scopes,
|
|
36
36
|
redirectURI,
|
|
37
|
-
loginHint
|
|
37
|
+
loginHint,
|
|
38
|
+
additionalParams
|
|
38
39
|
}: {
|
|
39
40
|
state: string;
|
|
40
41
|
codeVerifier: string;
|
|
@@ -42,6 +43,7 @@ declare const facebook: (options: FacebookOptions) => {
|
|
|
42
43
|
redirectURI: string;
|
|
43
44
|
display?: string | undefined;
|
|
44
45
|
loginHint?: string | undefined;
|
|
46
|
+
additionalParams?: Record<string, string> | undefined;
|
|
45
47
|
}): Promise<URL>;
|
|
46
48
|
validateAuthorizationCode: ({
|
|
47
49
|
code,
|
|
@@ -11,7 +11,7 @@ const facebook = (options) => {
|
|
|
11
11
|
return {
|
|
12
12
|
id: "facebook",
|
|
13
13
|
name: "Facebook",
|
|
14
|
-
async createAuthorizationURL({ state, scopes, redirectURI, loginHint }) {
|
|
14
|
+
async createAuthorizationURL({ state, scopes, redirectURI, loginHint, additionalParams }) {
|
|
15
15
|
if (!getPrimaryClientId(options.clientId) || !options.clientSecret) {
|
|
16
16
|
logger.error("Client ID and client secret are required for Facebook. Make sure to provide them in the options.");
|
|
17
17
|
throw new BetterAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
|
|
@@ -27,7 +27,10 @@ const facebook = (options) => {
|
|
|
27
27
|
state,
|
|
28
28
|
redirectURI,
|
|
29
29
|
loginHint,
|
|
30
|
-
additionalParams:
|
|
30
|
+
additionalParams: {
|
|
31
|
+
...options.configId ? { config_id: options.configId } : {},
|
|
32
|
+
...additionalParams ?? {}
|
|
33
|
+
}
|
|
31
34
|
});
|
|
32
35
|
},
|
|
33
36
|
validateAuthorizationCode: async ({ code, redirectURI }) => {
|
|
@@ -16,7 +16,8 @@ declare const figma: (options: FigmaOptions) => {
|
|
|
16
16
|
state,
|
|
17
17
|
scopes,
|
|
18
18
|
codeVerifier,
|
|
19
|
-
redirectURI
|
|
19
|
+
redirectURI,
|
|
20
|
+
additionalParams
|
|
20
21
|
}: {
|
|
21
22
|
state: string;
|
|
22
23
|
codeVerifier: string;
|
|
@@ -24,6 +25,7 @@ declare const figma: (options: FigmaOptions) => {
|
|
|
24
25
|
redirectURI: string;
|
|
25
26
|
display?: string | undefined;
|
|
26
27
|
loginHint?: string | undefined;
|
|
28
|
+
additionalParams?: Record<string, string> | undefined;
|
|
27
29
|
}): Promise<URL>;
|
|
28
30
|
validateAuthorizationCode: ({
|
|
29
31
|
code,
|
|
@@ -10,7 +10,7 @@ const figma = (options) => {
|
|
|
10
10
|
return {
|
|
11
11
|
id: "figma",
|
|
12
12
|
name: "Figma",
|
|
13
|
-
async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {
|
|
13
|
+
async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI, additionalParams }) {
|
|
14
14
|
if (!options.clientId || !options.clientSecret) {
|
|
15
15
|
logger.error("Client Id and Client Secret are required for Figma. Make sure to provide them in the options.");
|
|
16
16
|
throw new BetterAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
|
|
@@ -26,7 +26,8 @@ const figma = (options) => {
|
|
|
26
26
|
scopes: _scopes,
|
|
27
27
|
state,
|
|
28
28
|
codeVerifier,
|
|
29
|
-
redirectURI
|
|
29
|
+
redirectURI,
|
|
30
|
+
additionalParams
|
|
30
31
|
});
|
|
31
32
|
},
|
|
32
33
|
validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
|
|
@@ -57,7 +57,8 @@ declare const github: (options: GithubOptions) => {
|
|
|
57
57
|
scopes,
|
|
58
58
|
loginHint,
|
|
59
59
|
codeVerifier,
|
|
60
|
-
redirectURI
|
|
60
|
+
redirectURI,
|
|
61
|
+
additionalParams
|
|
61
62
|
}: {
|
|
62
63
|
state: string;
|
|
63
64
|
codeVerifier: string;
|
|
@@ -65,6 +66,7 @@ declare const github: (options: GithubOptions) => {
|
|
|
65
66
|
redirectURI: string;
|
|
66
67
|
display?: string | undefined;
|
|
67
68
|
loginHint?: string | undefined;
|
|
69
|
+
additionalParams?: Record<string, string> | undefined;
|
|
68
70
|
}): Promise<URL>;
|
|
69
71
|
validateAuthorizationCode: ({
|
|
70
72
|
code,
|
|
@@ -2,7 +2,7 @@ import { logger } from "../env/logger.mjs";
|
|
|
2
2
|
import { getOAuth2Tokens } from "../oauth2/utils.mjs";
|
|
3
3
|
import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
|
|
4
4
|
import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
|
|
5
|
-
import {
|
|
5
|
+
import { authorizationCodeRequest } from "../oauth2/validate-authorization-code.mjs";
|
|
6
6
|
import { betterFetch } from "@better-fetch/fetch";
|
|
7
7
|
//#region src/social-providers/github.ts
|
|
8
8
|
const github = (options) => {
|
|
@@ -10,7 +10,7 @@ const github = (options) => {
|
|
|
10
10
|
return {
|
|
11
11
|
id: "github",
|
|
12
12
|
name: "GitHub",
|
|
13
|
-
createAuthorizationURL({ state, scopes, loginHint, codeVerifier, redirectURI }) {
|
|
13
|
+
createAuthorizationURL({ state, scopes, loginHint, codeVerifier, redirectURI, additionalParams }) {
|
|
14
14
|
const _scopes = options.disableDefaultScope ? [] : ["read:user", "user:email"];
|
|
15
15
|
if (options.scope) _scopes.push(...options.scope);
|
|
16
16
|
if (scopes) _scopes.push(...scopes);
|
|
@@ -23,11 +23,12 @@ const github = (options) => {
|
|
|
23
23
|
codeVerifier,
|
|
24
24
|
redirectURI,
|
|
25
25
|
loginHint,
|
|
26
|
-
prompt: options.prompt
|
|
26
|
+
prompt: options.prompt,
|
|
27
|
+
additionalParams
|
|
27
28
|
});
|
|
28
29
|
},
|
|
29
30
|
validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
|
|
30
|
-
const { body, headers: requestHeaders } =
|
|
31
|
+
const { body, headers: requestHeaders } = await authorizationCodeRequest({
|
|
31
32
|
code,
|
|
32
33
|
codeVerifier,
|
|
33
34
|
redirectURI,
|