@aura-stack/auth 0.4.0 → 0.5.0
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/@types/index.d.ts +6 -2
- package/dist/@types/router.d.d.ts +6 -2
- package/dist/actions/callback/access-token.cjs +103 -59
- package/dist/actions/callback/access-token.d.ts +7 -3
- package/dist/actions/callback/access-token.js +3 -3
- package/dist/actions/callback/callback.cjs +200 -134
- package/dist/actions/callback/callback.d.ts +32 -3
- package/dist/actions/callback/callback.js +11 -12
- package/dist/actions/callback/userinfo.cjs +103 -70
- package/dist/actions/callback/userinfo.d.ts +6 -2
- package/dist/actions/callback/userinfo.js +7 -8
- package/dist/actions/csrfToken/csrfToken.cjs +7 -15
- package/dist/actions/csrfToken/csrfToken.d.ts +3 -1
- package/dist/actions/csrfToken/csrfToken.js +7 -8
- package/dist/actions/index.cjs +502 -295
- package/dist/actions/index.d.ts +5 -2
- package/dist/actions/index.js +23 -20
- package/dist/actions/session/session.cjs +76 -24
- package/dist/actions/session/session.d.ts +3 -1
- package/dist/actions/session/session.js +6 -4
- package/dist/actions/signIn/authorization-url.cjs +288 -0
- package/dist/actions/signIn/authorization-url.d.ts +31 -0
- package/dist/actions/signIn/authorization-url.js +16 -0
- package/dist/actions/signIn/authorization.cjs +91 -132
- package/dist/actions/signIn/authorization.d.ts +17 -16
- package/dist/actions/signIn/authorization.js +8 -7
- package/dist/actions/signIn/signIn.cjs +319 -191
- package/dist/actions/signIn/signIn.d.ts +32 -3
- package/dist/actions/signIn/signIn.js +10 -9
- package/dist/actions/signOut/signOut.cjs +211 -212
- package/dist/actions/signOut/signOut.d.ts +9 -1
- package/dist/actions/signOut/signOut.js +9 -10
- package/dist/api/createApi.cjs +750 -0
- package/dist/api/createApi.d.ts +12 -0
- package/dist/api/createApi.js +19 -0
- package/dist/api/getSession.cjs +141 -0
- package/dist/api/getSession.d.ts +16 -0
- package/dist/api/getSession.js +10 -0
- package/dist/api/signIn.cjs +549 -0
- package/dist/api/signIn.d.ts +26 -0
- package/dist/api/signIn.js +15 -0
- package/dist/api/signOut.cjs +279 -0
- package/dist/api/signOut.d.ts +16 -0
- package/dist/api/signOut.js +13 -0
- package/dist/assert.cjs +42 -9
- package/dist/assert.d.ts +8 -4
- package/dist/assert.js +5 -5
- package/dist/{chunk-KJBAQZX2.js → chunk-2A5B7GWR.js} +44 -11
- package/dist/chunk-2GQLSIJ2.js +40 -0
- package/dist/chunk-2IR674WX.js +44 -0
- package/dist/chunk-3J5TUH2I.js +50 -0
- package/dist/chunk-4RWSYUKX.js +98 -0
- package/dist/chunk-5X7JZMEF.js +0 -0
- package/dist/{chunk-TZB6MUXN.js → chunk-7BE46WWS.js} +21 -11
- package/dist/chunk-7YYXFKLR.js +35 -0
- package/dist/chunk-C3A37LQC.js +33 -0
- package/dist/chunk-CITNGXDA.js +31 -0
- package/dist/chunk-CWX724AG.js +78 -0
- package/dist/chunk-D2CSIUKP.js +74 -0
- package/dist/{chunk-ICAZ4OVS.js → chunk-FPCVZUVG.js} +2 -2
- package/dist/{chunk-XGLBNXL4.js → chunk-GNNBM2WJ.js} +17 -9
- package/dist/chunk-JOCGX3RP.js +59 -0
- package/dist/chunk-KBXWTD6E.js +94 -0
- package/dist/{chunk-XUP6KKNG.js → chunk-LATR3NIV.js} +48 -37
- package/dist/chunk-LAYPUDQF.js +39 -0
- package/dist/chunk-LX3TJ2TJ.js +294 -0
- package/dist/{chunk-6MXFPFR3.js → chunk-NHZBQNRR.js} +19 -19
- package/dist/{chunk-TM5IPSNF.js → chunk-PDP3PHB3.js} +33 -19
- package/dist/chunk-PHYNROD4.js +47 -0
- package/dist/chunk-QQEKY4XP.js +29 -0
- package/dist/{chunk-VNCNJKS2.js → chunk-U4RK4LKJ.js} +82 -1
- package/dist/{chunk-RRLIF4PQ.js → chunk-U5663F2U.js} +16 -1
- package/dist/chunk-UN7X6SU5.js +53 -0
- package/dist/chunk-UZQJJD6A.js +100 -0
- package/dist/{chunk-NUDITUKX.js → chunk-V6LLEAR4.js} +22 -15
- package/dist/{chunk-4MYWAOLG.js → chunk-WHNDRO3N.js} +20 -1
- package/dist/{chunk-5W4BRQYG.js → chunk-XY5R3EHH.js} +6 -3
- package/dist/client/client.cjs +135 -0
- package/dist/client/client.d.ts +85 -0
- package/dist/client/client.js +9 -0
- package/dist/client/index.cjs +135 -0
- package/dist/client/index.d.ts +14 -0
- package/dist/client/index.js +10 -0
- package/dist/context.cjs +1237 -0
- package/dist/context.d.ts +16 -0
- package/dist/context.js +28 -0
- package/dist/cookie.cjs +33 -2
- package/dist/cookie.d.ts +9 -5
- package/dist/cookie.js +3 -2
- package/dist/createAuth.cjs +2320 -0
- package/dist/createAuth.d.ts +12 -0
- package/dist/createAuth.js +48 -0
- package/dist/env.cjs +24 -2
- package/dist/env.d.ts +4 -1
- package/dist/env.js +9 -3
- package/dist/errors.cjs +17 -0
- package/dist/errors.d.ts +13 -3
- package/dist/errors.js +5 -1
- package/dist/{index-CSyIJmCM.d.ts → index-_aXtxb_s.d.ts} +383 -13
- package/dist/index.cjs +2135 -1547
- package/dist/index.d.ts +9 -30
- package/dist/index.js +46 -119
- package/dist/jose.cjs +52 -14
- package/dist/jose.d.ts +12 -25
- package/dist/jose.js +11 -3
- package/dist/logger.cjs +132 -0
- package/dist/logger.d.ts +6 -2
- package/dist/logger.js +10 -1
- package/dist/oauth/atlassian.cjs +57 -0
- package/dist/oauth/atlassian.d.ts +12 -0
- package/dist/oauth/atlassian.js +6 -0
- package/dist/oauth/bitbucket.d.ts +6 -2
- package/dist/oauth/discord.d.ts +6 -2
- package/dist/oauth/dropbox.cjs +53 -0
- package/dist/oauth/dropbox.d.ts +12 -0
- package/dist/oauth/dropbox.js +6 -0
- package/dist/oauth/figma.d.ts +6 -2
- package/dist/oauth/github.d.ts +6 -2
- package/dist/oauth/gitlab.d.ts +6 -2
- package/dist/oauth/index.cjs +278 -88
- package/dist/oauth/index.d.ts +6 -2
- package/dist/oauth/index.js +27 -11
- package/dist/oauth/mailchimp.d.ts +6 -2
- package/dist/oauth/notion.cjs +131 -0
- package/dist/oauth/notion.d.ts +12 -0
- package/dist/oauth/notion.js +9 -0
- package/dist/oauth/pinterest.d.ts +6 -2
- package/dist/oauth/spotify.d.ts +6 -2
- package/dist/oauth/strava.d.ts +6 -2
- package/dist/oauth/twitch.cjs +95 -0
- package/dist/oauth/twitch.d.ts +12 -0
- package/dist/oauth/twitch.js +7 -0
- package/dist/oauth/x.d.ts +6 -2
- package/dist/schemas.cjs +84 -51
- package/dist/schemas.d.ts +103 -23
- package/dist/schemas.js +1 -1
- package/dist/secure.cjs +36 -36
- package/dist/secure.d.ts +10 -4
- package/dist/secure.js +7 -6
- package/dist/utils.cjs +109 -3
- package/dist/utils.d.ts +15 -4
- package/dist/utils.js +11 -4
- package/package.json +9 -5
- package/dist/chunk-4EKY7655.js +0 -123
- package/dist/chunk-7QF22LHP.js +0 -67
- package/dist/chunk-ALG3GIV4.js +0 -95
- package/dist/chunk-FRJFWTOY.js +0 -70
- package/dist/chunk-PHFH2MGS.js +0 -36
- package/dist/chunk-QQVSRXGX.js +0 -149
|
@@ -1,57 +1,56 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import {
|
|
2
|
+
equals,
|
|
3
|
+
extractPath,
|
|
5
4
|
isRelativeURL,
|
|
6
5
|
isSameOrigin,
|
|
7
6
|
isTrustedOrigin,
|
|
8
7
|
isValidURL,
|
|
9
8
|
patternToRegex
|
|
10
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-LX3TJ2TJ.js";
|
|
11
10
|
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
toCastCase
|
|
15
|
-
} from "./chunk-QQVSRXGX.js";
|
|
11
|
+
getEnv
|
|
12
|
+
} from "./chunk-WHNDRO3N.js";
|
|
16
13
|
import {
|
|
17
14
|
AuthInternalError
|
|
18
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-U5663F2U.js";
|
|
19
16
|
|
|
20
17
|
// src/actions/signIn/authorization.ts
|
|
21
|
-
var createAuthorizationURL = (oauthConfig, redirectURI, state, codeChallenge, codeChallengeMethod, logger) => {
|
|
22
|
-
const parsed = OAuthAuthorization.safeParse({ ...oauthConfig, redirectURI, state, codeChallenge, codeChallengeMethod });
|
|
23
|
-
if (!parsed.success) {
|
|
24
|
-
logger?.log("INVALID_OAUTH_CONFIGURATION", {
|
|
25
|
-
structuredData: {
|
|
26
|
-
scope: oauthConfig.scope,
|
|
27
|
-
redirect_uri: redirectURI,
|
|
28
|
-
has_state: Boolean(state),
|
|
29
|
-
has_code_challenge: Boolean(codeChallenge),
|
|
30
|
-
code_challenge_method: codeChallengeMethod
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
throw new AuthInternalError("INVALID_OAUTH_CONFIGURATION", "The OAuth provider configuration is invalid.");
|
|
34
|
-
}
|
|
35
|
-
const { authorizeURL, ...options } = parsed.data;
|
|
36
|
-
const { userInfo, accessToken, clientSecret, ...required } = options;
|
|
37
|
-
const searchParams = new URLSearchParams(toCastCase(required));
|
|
38
|
-
return `${authorizeURL}?${searchParams}`;
|
|
39
|
-
};
|
|
40
18
|
var getTrustedOrigins = async (request, trustedOrigins) => {
|
|
41
19
|
if (!trustedOrigins) return [];
|
|
42
20
|
const raw = typeof trustedOrigins === "function" ? await trustedOrigins(request) : trustedOrigins;
|
|
43
21
|
return Array.isArray(raw) ? raw : typeof raw === "string" ? [raw] : [];
|
|
44
22
|
};
|
|
23
|
+
var getBaseURL = async ({
|
|
24
|
+
ctx,
|
|
25
|
+
request,
|
|
26
|
+
headers: headersInit
|
|
27
|
+
}) => {
|
|
28
|
+
const origin = getEnv("BASE_URL") || ctx?.baseURL;
|
|
29
|
+
if (origin && origin !== "/") return origin;
|
|
30
|
+
if (ctx?.trustedProxyHeaders) {
|
|
31
|
+
const headers = headersInit && new Headers(headersInit) || request?.headers;
|
|
32
|
+
const protocol = headers?.get("Forwarded")?.match(/proto=([^;]+)/i)?.[1] ?? headers?.get("X-Forwarded-Proto") ?? "http";
|
|
33
|
+
const host = headers?.get("Host") ?? headers?.get("Forwarded")?.match(/host=([^;]+)/i)?.[1] ?? headers?.get("X-Forwarded-Host") ?? null;
|
|
34
|
+
if (host) return `${protocol}://${host}`;
|
|
35
|
+
throw new AuthInternalError(
|
|
36
|
+
"INVALID_OAUTH_CONFIGURATION",
|
|
37
|
+
"The URL cannot be constructed. Please set the BASE_URL environment variable or provide trusted proxy host headers."
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
return new URL(request?.url ?? "not-found").origin;
|
|
42
|
+
} catch (error) {
|
|
43
|
+
throw new AuthInternalError(
|
|
44
|
+
"INVALID_OAUTH_CONFIGURATION",
|
|
45
|
+
"The URL cannot be constructed. Please set the BASE_URL environment variable or enable trustedProxyHeaders.",
|
|
46
|
+
{ cause: error }
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
45
50
|
var getOriginURL = async (request, context) => {
|
|
46
|
-
const headers = request.headers;
|
|
47
|
-
let origin = new URL(request.url).origin;
|
|
48
51
|
const trustedOrigins = await getTrustedOrigins(request, context?.trustedOrigins);
|
|
49
|
-
trustedOrigins.push(origin);
|
|
50
|
-
|
|
51
|
-
const protocol = headers.get("Forwarded")?.match(/proto=([^;]+)/i)?.[1] ?? headers.get("X-Forwarded-Proto") ?? "http";
|
|
52
|
-
const host = headers.get("Host") ?? headers.get("Forwarded")?.match(/host=([^;]+)/i)?.[1] ?? headers.get("X-Forwarded-Host") ?? null;
|
|
53
|
-
origin = `${protocol}://${host}`;
|
|
54
|
-
}
|
|
52
|
+
trustedOrigins.push(new URL(request.url).origin);
|
|
53
|
+
const origin = await getBaseURL({ request, ctx: context });
|
|
55
54
|
if (!isTrustedOrigin(origin, trustedOrigins)) {
|
|
56
55
|
context?.logger?.log("UNTRUSTED_ORIGIN", { structuredData: { origin } });
|
|
57
56
|
throw new AuthInternalError("UNTRUSTED_ORIGIN", "The constructed origin URL is not trusted.");
|
|
@@ -62,6 +61,17 @@ var createRedirectURI = async (request, oauth, context) => {
|
|
|
62
61
|
const origin = await getOriginURL(request, context);
|
|
63
62
|
return `${origin}${context.basePath}/callback/${oauth}`;
|
|
64
63
|
};
|
|
64
|
+
var createSignInURL = async ({
|
|
65
|
+
request,
|
|
66
|
+
oauth,
|
|
67
|
+
ctx,
|
|
68
|
+
redirectTo
|
|
69
|
+
}) => {
|
|
70
|
+
const origin = await getOriginURL(request, ctx);
|
|
71
|
+
const searchParams = new URLSearchParams();
|
|
72
|
+
if (redirectTo !== void 0) searchParams.set("redirectTo", String(redirectTo));
|
|
73
|
+
return `${origin}${ctx.basePath}/signIn/${oauth}?${searchParams.toString()}`;
|
|
74
|
+
};
|
|
65
75
|
var createRedirectTo = async (request, redirectTo, context) => {
|
|
66
76
|
try {
|
|
67
77
|
const headers = request.headers;
|
|
@@ -98,9 +108,10 @@ var createRedirectTo = async (request, redirectTo, context) => {
|
|
|
98
108
|
};
|
|
99
109
|
|
|
100
110
|
export {
|
|
101
|
-
createAuthorizationURL,
|
|
102
111
|
getTrustedOrigins,
|
|
112
|
+
getBaseURL,
|
|
103
113
|
getOriginURL,
|
|
104
114
|
createRedirectURI,
|
|
115
|
+
createSignInURL,
|
|
105
116
|
createRedirectTo
|
|
106
117
|
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getSession
|
|
3
|
+
} from "./chunk-CITNGXDA.js";
|
|
4
|
+
import {
|
|
5
|
+
signIn
|
|
6
|
+
} from "./chunk-JOCGX3RP.js";
|
|
7
|
+
import {
|
|
8
|
+
signOut
|
|
9
|
+
} from "./chunk-KBXWTD6E.js";
|
|
10
|
+
import {
|
|
11
|
+
validateRedirectTo
|
|
12
|
+
} from "./chunk-LX3TJ2TJ.js";
|
|
13
|
+
|
|
14
|
+
// src/api/createApi.ts
|
|
15
|
+
var createAuthAPI = (ctx) => {
|
|
16
|
+
return {
|
|
17
|
+
getSession: async (options) => {
|
|
18
|
+
const session = await getSession({ ctx, headers: options.headers });
|
|
19
|
+
return session;
|
|
20
|
+
},
|
|
21
|
+
signIn: async (oauth, options) => {
|
|
22
|
+
return signIn(oauth, {
|
|
23
|
+
ctx,
|
|
24
|
+
headers: options?.headers,
|
|
25
|
+
request: options?.request,
|
|
26
|
+
redirect: options?.redirect,
|
|
27
|
+
redirectTo: options?.redirectTo
|
|
28
|
+
});
|
|
29
|
+
},
|
|
30
|
+
signOut: async (options) => {
|
|
31
|
+
const redirectTo = validateRedirectTo(options?.redirectTo ?? "/");
|
|
32
|
+
return signOut({ ctx, headers: options.headers, redirectTo, skipCSRFCheck: true });
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export {
|
|
38
|
+
createAuthAPI
|
|
39
|
+
};
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getEnv
|
|
3
|
+
} from "./chunk-WHNDRO3N.js";
|
|
4
|
+
import {
|
|
5
|
+
AuthInternalError,
|
|
6
|
+
isAuthInternalError,
|
|
7
|
+
isAuthSecurityError,
|
|
8
|
+
isOAuthProtocolError
|
|
9
|
+
} from "./chunk-U5663F2U.js";
|
|
10
|
+
|
|
11
|
+
// src/utils.ts
|
|
12
|
+
import { isInvalidZodSchemaError, isRouterError } from "@aura-stack/router";
|
|
13
|
+
|
|
14
|
+
// src/assert.ts
|
|
15
|
+
import { encoder } from "@aura-stack/jose/crypto";
|
|
16
|
+
var isFalsy = (value) => {
|
|
17
|
+
return value === false || value === 0 || value === "" || value === null || value === void 0 || Number.isNaN(value);
|
|
18
|
+
};
|
|
19
|
+
var isRequest = (value) => {
|
|
20
|
+
return typeof Request !== "undefined" && value instanceof Request;
|
|
21
|
+
};
|
|
22
|
+
var unsafeChars = [
|
|
23
|
+
"<",
|
|
24
|
+
">",
|
|
25
|
+
'"',
|
|
26
|
+
"`",
|
|
27
|
+
" ",
|
|
28
|
+
"\r",
|
|
29
|
+
"\n",
|
|
30
|
+
" ",
|
|
31
|
+
"\\",
|
|
32
|
+
"%2F",
|
|
33
|
+
"%5C",
|
|
34
|
+
"%2f",
|
|
35
|
+
"%5c",
|
|
36
|
+
"\r\n",
|
|
37
|
+
"%0A",
|
|
38
|
+
"%0D",
|
|
39
|
+
"%0a",
|
|
40
|
+
"%0d",
|
|
41
|
+
"..",
|
|
42
|
+
"//",
|
|
43
|
+
"///",
|
|
44
|
+
"...",
|
|
45
|
+
"%20",
|
|
46
|
+
"\0"
|
|
47
|
+
];
|
|
48
|
+
var isValidURL = (value) => {
|
|
49
|
+
if (!new RegExp(/^https?:\/\/[^/]/).test(value)) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
const match = value.match(/^(https?:\/\/)(.*)$/);
|
|
53
|
+
if (!match) return false;
|
|
54
|
+
const rest = match[2];
|
|
55
|
+
for (const char of unsafeChars) {
|
|
56
|
+
if (rest.includes(char)) return false;
|
|
57
|
+
}
|
|
58
|
+
const regex = /^https?:\/\/(?:[a-zA-Z0-9._-]+|localhost|\[[0-9a-fA-F:]+\])(?::\d{1,5})?(?:\/[a-zA-Z0-9._~!$&'()?#*+,;=:@-]*)*\/?$/;
|
|
59
|
+
return regex.test(match[0]);
|
|
60
|
+
};
|
|
61
|
+
var isJWTPayloadWithToken = (payload) => {
|
|
62
|
+
return typeof payload === "object" && payload !== null && "token" in payload && typeof payload?.token === "string";
|
|
63
|
+
};
|
|
64
|
+
var isRelativeURL = (value) => {
|
|
65
|
+
if (value.length > 100) return false;
|
|
66
|
+
for (const char of unsafeChars) {
|
|
67
|
+
if (value.includes(char)) return false;
|
|
68
|
+
}
|
|
69
|
+
const regex = /^\/[a-zA-Z0-9\-_\/.?&=#]*\/?$/;
|
|
70
|
+
return regex.test(value);
|
|
71
|
+
};
|
|
72
|
+
var isSameOrigin = (origin, expected) => {
|
|
73
|
+
const originURL = new URL(origin);
|
|
74
|
+
const expectedURL = new URL(expected);
|
|
75
|
+
return equals(originURL.origin, expectedURL.origin);
|
|
76
|
+
};
|
|
77
|
+
var patternToRegex = (pattern) => {
|
|
78
|
+
try {
|
|
79
|
+
if (pattern.length > 2048) return null;
|
|
80
|
+
pattern = pattern.replace(/\\/g, "");
|
|
81
|
+
const match = pattern.match(/^(https?):\/\/([a-zA-Z0-9.*-]{1,253})(?::(\d{1,5}|\*))?(?:\/.*)?$/);
|
|
82
|
+
if (!match) return null;
|
|
83
|
+
const [, protocol, host, port] = match;
|
|
84
|
+
const hasWildcard = host.includes("*");
|
|
85
|
+
if (hasWildcard && !host.startsWith("*.")) return null;
|
|
86
|
+
if (hasWildcard && host.slice(2).includes("*")) return null;
|
|
87
|
+
const domain = hasWildcard ? host.slice(2) : host;
|
|
88
|
+
const escapedDomain = domain.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
89
|
+
const hostRegex = hasWildcard ? `[^.]+\\.${escapedDomain}` : escapedDomain;
|
|
90
|
+
const portRegex = port === "*" ? ":\\d{1,5}" : port ? `:${port}` : "";
|
|
91
|
+
return new RegExp(`^${protocol}:\\/\\/${hostRegex}${portRegex}$`);
|
|
92
|
+
} catch {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
var isTrustedOrigin = (url, trustedOrigins) => {
|
|
97
|
+
if (!isValidURL(url) || trustedOrigins.length === 0) return false;
|
|
98
|
+
try {
|
|
99
|
+
const urlOrigin = new URL(url).origin;
|
|
100
|
+
for (const pattern of trustedOrigins) {
|
|
101
|
+
const regex = patternToRegex(pattern);
|
|
102
|
+
if (regex?.test(urlOrigin)) return true;
|
|
103
|
+
try {
|
|
104
|
+
if (isValidURL(pattern) && equals(new URL(pattern).origin, urlOrigin)) return true;
|
|
105
|
+
} catch {
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
} catch {
|
|
109
|
+
}
|
|
110
|
+
return false;
|
|
111
|
+
};
|
|
112
|
+
var timingSafeEqual = (a, b) => {
|
|
113
|
+
const bufferA = encoder.encode(a);
|
|
114
|
+
const bufferB = encoder.encode(b);
|
|
115
|
+
const len = Math.max(bufferA.length, bufferB.length);
|
|
116
|
+
let diff = 0;
|
|
117
|
+
for (let i = 0; i < len; i++) {
|
|
118
|
+
diff |= (bufferA[i] ?? 0) ^ (bufferB[i] ?? 0);
|
|
119
|
+
}
|
|
120
|
+
return diff === 0 && bufferA.length === bufferB.length;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// src/utils.ts
|
|
124
|
+
var AURA_AUTH_VERSION = "0.4.0";
|
|
125
|
+
var toSnakeCase = (str) => {
|
|
126
|
+
return str.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2").toLowerCase().replace(/^_+/, "");
|
|
127
|
+
};
|
|
128
|
+
var toUpperCase = (str) => {
|
|
129
|
+
return str.toUpperCase();
|
|
130
|
+
};
|
|
131
|
+
var toCastCase = (obj, type = "snake") => {
|
|
132
|
+
return Object.entries(obj).reduce((previous, [key, value]) => {
|
|
133
|
+
const newKey = type === "snake" ? toSnakeCase(key) : toUpperCase(key);
|
|
134
|
+
return { ...previous, [newKey]: value };
|
|
135
|
+
}, {});
|
|
136
|
+
};
|
|
137
|
+
var equals = (a, b) => {
|
|
138
|
+
if (a === null || b === null || a === void 0 || b === void 0) return false;
|
|
139
|
+
return a === b;
|
|
140
|
+
};
|
|
141
|
+
var createErrorHandler = (logger) => {
|
|
142
|
+
return (error) => {
|
|
143
|
+
if (isRouterError(error)) {
|
|
144
|
+
const { message, status, statusText } = error;
|
|
145
|
+
logger?.log("ROUTER_INTERNAL_ERROR");
|
|
146
|
+
return Response.json({ type: "ROUTER_ERROR", code: "ROUTER_INTERNAL_ERROR", message }, { status, statusText });
|
|
147
|
+
}
|
|
148
|
+
if (isInvalidZodSchemaError(error)) {
|
|
149
|
+
logger?.log("INVALID_REQUEST");
|
|
150
|
+
return Response.json({ type: "ROUTER_ERROR", code: "INVALID_REQUEST", message: error.errors }, { status: 422 });
|
|
151
|
+
}
|
|
152
|
+
if (isOAuthProtocolError(error)) {
|
|
153
|
+
const { error: errorCode, message, type, errorURI } = error;
|
|
154
|
+
logger?.log("OAUTH_PROTOCOL_ERROR", {
|
|
155
|
+
structuredData: {
|
|
156
|
+
error: errorCode,
|
|
157
|
+
error_description: message,
|
|
158
|
+
error_uri: errorURI ?? ""
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
return Response.json(
|
|
162
|
+
{
|
|
163
|
+
type,
|
|
164
|
+
message
|
|
165
|
+
},
|
|
166
|
+
{ status: 400 }
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
if (isAuthInternalError(error)) {
|
|
170
|
+
const { type, code, message } = error;
|
|
171
|
+
logger?.log("INVALID_OAUTH_CONFIGURATION", {
|
|
172
|
+
structuredData: {
|
|
173
|
+
error: code,
|
|
174
|
+
error_description: message
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
return Response.json(
|
|
178
|
+
{
|
|
179
|
+
type,
|
|
180
|
+
message
|
|
181
|
+
},
|
|
182
|
+
{ status: 400 }
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
if (isAuthSecurityError(error)) {
|
|
186
|
+
const { type, code, message } = error;
|
|
187
|
+
logger?.log("INVALID_OAUTH_CONFIGURATION", {
|
|
188
|
+
structuredData: {
|
|
189
|
+
error: code,
|
|
190
|
+
error_description: message
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
return Response.json(
|
|
194
|
+
{
|
|
195
|
+
type,
|
|
196
|
+
code,
|
|
197
|
+
message
|
|
198
|
+
},
|
|
199
|
+
{ status: 400 }
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
logger?.log("SERVER_ERROR");
|
|
203
|
+
return Response.json(
|
|
204
|
+
{ type: "SERVER_ERROR", code: "SERVER_ERROR", message: "An unexpected error occurred" },
|
|
205
|
+
{ status: 500 }
|
|
206
|
+
);
|
|
207
|
+
};
|
|
208
|
+
};
|
|
209
|
+
var getBaseURL = (request) => {
|
|
210
|
+
const url = new URL(request.url);
|
|
211
|
+
return `${url.origin}${url.pathname}`;
|
|
212
|
+
};
|
|
213
|
+
var toISOString = (date) => {
|
|
214
|
+
return new Date(date).toISOString();
|
|
215
|
+
};
|
|
216
|
+
var useSecureCookies = (request, trustedProxyHeaders) => {
|
|
217
|
+
const headers = request instanceof Headers ? request : request.headers;
|
|
218
|
+
const url = request instanceof Headers ? null : request.url;
|
|
219
|
+
return trustedProxyHeaders ? url?.startsWith("https://") || headers.get("X-Forwarded-Proto") === "https" || (headers.get("Forwarded")?.includes("proto=https") ?? false) : url?.startsWith("https://") ?? false;
|
|
220
|
+
};
|
|
221
|
+
var formatZodError = (error) => {
|
|
222
|
+
if (!error.issues || error.issues.length === 0) {
|
|
223
|
+
return {};
|
|
224
|
+
}
|
|
225
|
+
return error.issues.reduce((previous, issue) => {
|
|
226
|
+
const key = issue.path.join(".");
|
|
227
|
+
return {
|
|
228
|
+
...previous,
|
|
229
|
+
[key]: {
|
|
230
|
+
code: issue.code,
|
|
231
|
+
message: issue.message
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
}, {});
|
|
235
|
+
};
|
|
236
|
+
var extractPath = (url) => {
|
|
237
|
+
const pathRegex = /^https?:\/\/[a-zA-Z0-9_\-\.]+(:\d+)?(\/.*)$/;
|
|
238
|
+
const match = url.match(pathRegex);
|
|
239
|
+
return match && match[2] ? match[2] : "/";
|
|
240
|
+
};
|
|
241
|
+
var createStructuredData = (data, sdID = "metadata") => {
|
|
242
|
+
const entries = Object.entries(data);
|
|
243
|
+
if (entries.length === 0) return `[${sdID}]`;
|
|
244
|
+
const values = entries.map(([key, value]) => `${key}="${String(value).replace(/(["\\\]])/g, "\\$1")}"`).join(" ");
|
|
245
|
+
return `[${sdID} ${values}]`;
|
|
246
|
+
};
|
|
247
|
+
var getErrorName = (error) => {
|
|
248
|
+
if (error instanceof Error) {
|
|
249
|
+
return error.name;
|
|
250
|
+
}
|
|
251
|
+
return typeof error === "string" ? error : "UnknownError";
|
|
252
|
+
};
|
|
253
|
+
var createBasicAuthHeader = (username, password) => {
|
|
254
|
+
const getUsername = getEnv(username.toUpperCase()) ?? username;
|
|
255
|
+
const getPassword = getEnv(password.toUpperCase()) ?? password;
|
|
256
|
+
if (!getUsername || !getPassword) {
|
|
257
|
+
throw new AuthInternalError("INVALID_OAUTH_CONFIGURATION", "Missing client credentials for OAuth provider configuration.");
|
|
258
|
+
}
|
|
259
|
+
const credentials = `${getUsername}:${getPassword}`;
|
|
260
|
+
return `Basic ${btoa(credentials)}`;
|
|
261
|
+
};
|
|
262
|
+
var validateRedirectTo = (url) => {
|
|
263
|
+
if (!isRelativeURL(url) && !isValidURL(url)) return "/";
|
|
264
|
+
if (isRelativeURL(url)) return url;
|
|
265
|
+
return "/";
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
export {
|
|
269
|
+
AURA_AUTH_VERSION,
|
|
270
|
+
toSnakeCase,
|
|
271
|
+
toUpperCase,
|
|
272
|
+
toCastCase,
|
|
273
|
+
equals,
|
|
274
|
+
createErrorHandler,
|
|
275
|
+
getBaseURL,
|
|
276
|
+
toISOString,
|
|
277
|
+
useSecureCookies,
|
|
278
|
+
formatZodError,
|
|
279
|
+
extractPath,
|
|
280
|
+
createStructuredData,
|
|
281
|
+
getErrorName,
|
|
282
|
+
createBasicAuthHeader,
|
|
283
|
+
validateRedirectTo,
|
|
284
|
+
isFalsy,
|
|
285
|
+
isRequest,
|
|
286
|
+
unsafeChars,
|
|
287
|
+
isValidURL,
|
|
288
|
+
isJWTPayloadWithToken,
|
|
289
|
+
isRelativeURL,
|
|
290
|
+
isSameOrigin,
|
|
291
|
+
patternToRegex,
|
|
292
|
+
isTrustedOrigin,
|
|
293
|
+
timingSafeEqual
|
|
294
|
+
};
|
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createAccessToken
|
|
3
|
-
} from "./chunk-TZB6MUXN.js";
|
|
4
1
|
import {
|
|
5
2
|
getUserInfo
|
|
6
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-GNNBM2WJ.js";
|
|
4
|
+
import {
|
|
5
|
+
createAccessToken
|
|
6
|
+
} from "./chunk-7BE46WWS.js";
|
|
7
7
|
import {
|
|
8
8
|
getOriginURL,
|
|
9
9
|
getTrustedOrigins
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import {
|
|
12
|
-
OAuthAuthorizationErrorResponse
|
|
13
|
-
} from "./chunk-KJBAQZX2.js";
|
|
10
|
+
} from "./chunk-LATR3NIV.js";
|
|
14
11
|
import {
|
|
15
12
|
createCSRF
|
|
16
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-V6LLEAR4.js";
|
|
14
|
+
import {
|
|
15
|
+
OAuthAuthorizationErrorResponse
|
|
16
|
+
} from "./chunk-2A5B7GWR.js";
|
|
17
17
|
import {
|
|
18
18
|
isRelativeURL,
|
|
19
19
|
isSameOrigin,
|
|
20
20
|
isTrustedOrigin,
|
|
21
|
-
|
|
22
|
-
} from "./chunk-
|
|
21
|
+
timingSafeEqual
|
|
22
|
+
} from "./chunk-LX3TJ2TJ.js";
|
|
23
23
|
import {
|
|
24
24
|
createSessionCookie,
|
|
25
25
|
expiredCookieAttributes,
|
|
26
26
|
getCookie
|
|
27
|
-
} from "./chunk-
|
|
28
|
-
import {
|
|
29
|
-
cacheControl
|
|
30
|
-
} from "./chunk-EBAMFRB7.js";
|
|
27
|
+
} from "./chunk-XY5R3EHH.js";
|
|
31
28
|
import {
|
|
32
29
|
AuthSecurityError,
|
|
33
30
|
OAuthProtocolError
|
|
34
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-U5663F2U.js";
|
|
32
|
+
import {
|
|
33
|
+
cacheControl
|
|
34
|
+
} from "./chunk-EBAMFRB7.js";
|
|
35
35
|
|
|
36
36
|
// src/actions/callback/callback.ts
|
|
37
|
-
import { z } from "zod";
|
|
37
|
+
import { z } from "zod/v4";
|
|
38
38
|
import { createEndpoint, createEndpointConfig, HeadersBuilder } from "@aura-stack/router";
|
|
39
39
|
var callbackConfig = (oauth) => {
|
|
40
40
|
return createEndpointConfig("/callback/:oauth", {
|
|
@@ -50,7 +50,7 @@ var callbackConfig = (oauth) => {
|
|
|
50
50
|
state: z.string("Missing state parameter in the OAuth authorization response.")
|
|
51
51
|
})
|
|
52
52
|
},
|
|
53
|
-
|
|
53
|
+
use: [
|
|
54
54
|
(ctx) => {
|
|
55
55
|
const {
|
|
56
56
|
searchParams,
|
|
@@ -92,7 +92,7 @@ var callbackAction = (oauth) => {
|
|
|
92
92
|
const codeVerifier = getCookie(request, cookies.codeVerifier.name);
|
|
93
93
|
const cookieRedirectTo = getCookie(request, cookies.redirectTo.name);
|
|
94
94
|
const cookieRedirectURI = getCookie(request, cookies.redirectURI.name);
|
|
95
|
-
if (!
|
|
95
|
+
if (!timingSafeEqual(cookieState, state)) {
|
|
96
96
|
logger?.log("MISMATCHING_STATE", {
|
|
97
97
|
structuredData: {
|
|
98
98
|
oauth_provider: oauth2
|
|
@@ -1,18 +1,36 @@
|
|
|
1
|
+
import {
|
|
2
|
+
mailchimp
|
|
3
|
+
} from "./chunk-LDU7A2JE.js";
|
|
4
|
+
import {
|
|
5
|
+
notion
|
|
6
|
+
} from "./chunk-PHYNROD4.js";
|
|
7
|
+
import {
|
|
8
|
+
pinterest
|
|
9
|
+
} from "./chunk-E6G5YCI6.js";
|
|
1
10
|
import {
|
|
2
11
|
spotify
|
|
3
12
|
} from "./chunk-IPKO6UQN.js";
|
|
4
13
|
import {
|
|
5
14
|
strava
|
|
6
15
|
} from "./chunk-54CZPKR4.js";
|
|
16
|
+
import {
|
|
17
|
+
twitch
|
|
18
|
+
} from "./chunk-2GQLSIJ2.js";
|
|
7
19
|
import {
|
|
8
20
|
x
|
|
9
21
|
} from "./chunk-EEE7UM5T.js";
|
|
22
|
+
import {
|
|
23
|
+
atlassian
|
|
24
|
+
} from "./chunk-C3A37LQC.js";
|
|
10
25
|
import {
|
|
11
26
|
bitbucket
|
|
12
27
|
} from "./chunk-4YHJ4IEQ.js";
|
|
13
28
|
import {
|
|
14
29
|
discord
|
|
15
30
|
} from "./chunk-OVHNRULD.js";
|
|
31
|
+
import {
|
|
32
|
+
dropbox
|
|
33
|
+
} from "./chunk-QQEKY4XP.js";
|
|
16
34
|
import {
|
|
17
35
|
figma
|
|
18
36
|
} from "./chunk-KMMAZFSJ.js";
|
|
@@ -22,25 +40,19 @@ import {
|
|
|
22
40
|
import {
|
|
23
41
|
gitlab
|
|
24
42
|
} from "./chunk-5LZ7TOM3.js";
|
|
25
|
-
import {
|
|
26
|
-
mailchimp
|
|
27
|
-
} from "./chunk-LDU7A2JE.js";
|
|
28
|
-
import {
|
|
29
|
-
pinterest
|
|
30
|
-
} from "./chunk-E6G5YCI6.js";
|
|
31
43
|
import {
|
|
32
44
|
OAuthEnvSchema,
|
|
33
45
|
OAuthProviderCredentialsSchema
|
|
34
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-2A5B7GWR.js";
|
|
35
47
|
import {
|
|
36
48
|
formatZodError
|
|
37
|
-
} from "./chunk-
|
|
49
|
+
} from "./chunk-LX3TJ2TJ.js";
|
|
38
50
|
import {
|
|
39
|
-
|
|
40
|
-
} from "./chunk-
|
|
51
|
+
getEnv
|
|
52
|
+
} from "./chunk-WHNDRO3N.js";
|
|
41
53
|
import {
|
|
42
54
|
AuthInternalError
|
|
43
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-U5663F2U.js";
|
|
44
56
|
|
|
45
57
|
// src/oauth/index.ts
|
|
46
58
|
var builtInOAuthProviders = {
|
|
@@ -53,17 +65,19 @@ var builtInOAuthProviders = {
|
|
|
53
65
|
x,
|
|
54
66
|
strava,
|
|
55
67
|
mailchimp,
|
|
56
|
-
pinterest
|
|
68
|
+
pinterest,
|
|
69
|
+
twitch,
|
|
70
|
+
notion,
|
|
71
|
+
dropbox,
|
|
72
|
+
atlassian
|
|
57
73
|
};
|
|
58
74
|
var defineOAuthEnvironment = (oauth) => {
|
|
59
|
-
const clientIdSuffix = `${oauth.toUpperCase()}_CLIENT_ID`;
|
|
60
|
-
const clientSecretSuffix = `${oauth.toUpperCase()}_CLIENT_SECRET`;
|
|
61
75
|
const loadEnvs = OAuthEnvSchema.safeParse({
|
|
62
|
-
clientId:
|
|
63
|
-
clientSecret:
|
|
76
|
+
clientId: getEnv(`${oauth.toUpperCase()}_CLIENT_ID`),
|
|
77
|
+
clientSecret: getEnv(`${oauth.toUpperCase()}_CLIENT_SECRET`)
|
|
64
78
|
});
|
|
65
79
|
if (!loadEnvs.success) {
|
|
66
|
-
const msg = JSON.stringify(formatZodError(loadEnvs.error), null, 2);
|
|
80
|
+
const msg = JSON.stringify({ [oauth]: formatZodError(loadEnvs.error) }, null, 2);
|
|
67
81
|
throw new AuthInternalError("INVALID_ENVIRONMENT_CONFIGURATION", msg);
|
|
68
82
|
}
|
|
69
83
|
return loadEnvs.data;
|
|
@@ -74,7 +88,7 @@ var defineOAuthProviderConfig = (config) => {
|
|
|
74
88
|
const oauthConfig = builtInOAuthProviders[config]();
|
|
75
89
|
const parsed2 = OAuthProviderCredentialsSchema.safeParse({ ...oauthConfig, ...definition });
|
|
76
90
|
if (!parsed2.success) {
|
|
77
|
-
const details = JSON.stringify(formatZodError(parsed2.error), null, 2);
|
|
91
|
+
const details = JSON.stringify({ [config]: formatZodError(parsed2.error) }, null, 2);
|
|
78
92
|
throw new AuthInternalError(
|
|
79
93
|
"INVALID_OAUTH_PROVIDER_CONFIGURATION",
|
|
80
94
|
`Invalid configuration for OAuth provider "${config}": ${details}`
|
|
@@ -86,7 +100,7 @@ var defineOAuthProviderConfig = (config) => {
|
|
|
86
100
|
const envConfig = hasCredentials ? {} : defineOAuthEnvironment(config.id);
|
|
87
101
|
const parsed = OAuthProviderCredentialsSchema.safeParse({ ...envConfig, ...config });
|
|
88
102
|
if (!parsed.success) {
|
|
89
|
-
const details = JSON.stringify(formatZodError(parsed.error), null, 2);
|
|
103
|
+
const details = JSON.stringify({ [config.id]: formatZodError(parsed.error) }, null, 2);
|
|
90
104
|
throw new AuthInternalError(
|
|
91
105
|
"INVALID_OAUTH_PROVIDER_CONFIGURATION",
|
|
92
106
|
`Invalid configuration for OAuth provider "${config.id}": ${details}`
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createBasicAuthHeader
|
|
3
|
+
} from "./chunk-LX3TJ2TJ.js";
|
|
4
|
+
|
|
5
|
+
// src/oauth/notion.ts
|
|
6
|
+
var notion = (options) => {
|
|
7
|
+
return {
|
|
8
|
+
id: "notion",
|
|
9
|
+
name: "Notion",
|
|
10
|
+
authorize: {
|
|
11
|
+
url: "https://api.notion.com/v1/oauth/authorize",
|
|
12
|
+
params: {
|
|
13
|
+
owner: "user",
|
|
14
|
+
scope: "user:read",
|
|
15
|
+
responseType: "code"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
accessToken: {
|
|
19
|
+
url: "https://api.notion.com/v1/oauth/token",
|
|
20
|
+
headers: {
|
|
21
|
+
Authorization: createBasicAuthHeader(
|
|
22
|
+
options?.clientId ?? "NOTION_CLIENT_ID",
|
|
23
|
+
options?.clientSecret ?? "NOTION_CLIENT_SECRET"
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
userInfo: {
|
|
28
|
+
url: "https://api.notion.com/v1/users/me",
|
|
29
|
+
headers: {
|
|
30
|
+
"Notion-Version": "2022-06-28"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
profile(profile) {
|
|
34
|
+
return {
|
|
35
|
+
sub: profile.id,
|
|
36
|
+
name: profile.name,
|
|
37
|
+
image: profile.avatar_url ?? "",
|
|
38
|
+
email: profile?.bot?.owner?.user?.person?.email
|
|
39
|
+
};
|
|
40
|
+
},
|
|
41
|
+
...options
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export {
|
|
46
|
+
notion
|
|
47
|
+
};
|