@aura-stack/auth 0.4.0-rc.5 → 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 +8 -3
- package/dist/@types/router.d.cjs +0 -17
- package/dist/@types/router.d.d.ts +7 -2
- package/dist/@types/router.d.js +0 -1
- package/dist/actions/callback/access-token.cjs +130 -71
- package/dist/actions/callback/access-token.d.ts +9 -4
- package/dist/actions/callback/access-token.js +3 -4
- package/dist/actions/callback/callback.cjs +428 -152
- package/dist/actions/callback/callback.d.ts +11 -3
- package/dist/actions/callback/callback.js +12 -10
- package/dist/actions/callback/userinfo.cjs +159 -65
- package/dist/actions/callback/userinfo.d.ts +8 -3
- package/dist/actions/callback/userinfo.js +7 -6
- package/dist/actions/csrfToken/csrfToken.cjs +70 -19
- package/dist/actions/csrfToken/csrfToken.js +8 -7
- package/dist/actions/index.cjs +780 -348
- package/dist/actions/index.d.ts +6 -2
- package/dist/actions/index.js +23 -18
- package/dist/actions/session/session.cjs +107 -26
- package/dist/actions/session/session.js +7 -5
- 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 +209 -211
- package/dist/actions/signIn/authorization.d.ts +32 -21
- package/dist/actions/signIn/authorization.js +12 -9
- package/dist/actions/signIn/signIn.cjs +470 -235
- package/dist/actions/signIn/signIn.d.ts +12 -3
- package/dist/actions/signIn/signIn.js +11 -8
- package/dist/actions/signOut/signOut.cjs +376 -228
- package/dist/actions/signOut/signOut.d.ts +1 -1
- package/dist/actions/signOut/signOut.js +10 -9
- 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 +150 -5
- package/dist/assert.d.ts +26 -3
- package/dist/assert.js +17 -3
- package/dist/{chunk-YRCB5FLE.js → chunk-2A5B7GWR.js} +52 -6
- 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-4YHJ4IEQ.js +25 -0
- package/dist/chunk-54CZPKR4.js +25 -0
- package/dist/chunk-5LZ7TOM3.js +25 -0
- package/dist/chunk-7BE46WWS.js +88 -0
- 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-E6G5YCI6.js +25 -0
- package/dist/chunk-EBAMFRB7.js +34 -0
- package/dist/chunk-EEE7UM5T.js +25 -0
- package/dist/{chunk-HT4YLL7N.js → chunk-FPCVZUVG.js} +10 -8
- package/dist/chunk-FW4W3REU.js +25 -0
- package/dist/chunk-GNNBM2WJ.js +83 -0
- package/dist/chunk-IPKO6UQN.js +25 -0
- package/dist/chunk-JOCGX3RP.js +59 -0
- package/dist/chunk-KBXWTD6E.js +94 -0
- package/dist/chunk-KMMAZFSJ.js +25 -0
- package/dist/chunk-LATR3NIV.js +117 -0
- package/dist/chunk-LAYPUDQF.js +39 -0
- package/dist/chunk-LDU7A2JE.js +25 -0
- package/dist/chunk-LX3TJ2TJ.js +294 -0
- package/dist/chunk-NHZBQNRR.js +143 -0
- package/dist/chunk-OVHNRULD.js +33 -0
- package/dist/chunk-PDP3PHB3.js +127 -0
- package/dist/chunk-PHYNROD4.js +47 -0
- package/dist/chunk-QQEKY4XP.js +29 -0
- package/dist/chunk-U4RK4LKJ.js +348 -0
- 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-V6LLEAR4.js +80 -0
- package/dist/chunk-WHNDRO3N.js +50 -0
- package/dist/{chunk-W6LG7BFW.js → chunk-XY5R3EHH.js} +30 -23
- 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 +57 -22
- package/dist/cookie.d.ts +11 -6
- 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 +78 -0
- package/dist/env.d.ts +10 -0
- package/dist/env.js +12 -0
- package/dist/errors.cjs +17 -0
- package/dist/errors.d.ts +15 -4
- package/dist/errors.js +5 -1
- package/dist/headers.cjs +28 -2
- package/dist/headers.d.ts +25 -1
- package/dist/headers.js +9 -3
- package/dist/index-_aXtxb_s.d.ts +1377 -0
- package/dist/index.cjs +1843 -610
- package/dist/index.d.ts +11 -92
- package/dist/index.js +53 -85
- package/dist/jose.cjs +113 -38
- package/dist/jose.d.ts +12 -23
- package/dist/jose.js +17 -7
- package/dist/logger.cjs +424 -0
- package/dist/logger.d.ts +12 -0
- package/dist/logger.js +17 -0
- 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.cjs +19 -15
- package/dist/oauth/bitbucket.d.ts +7 -2
- package/dist/oauth/bitbucket.js +1 -1
- package/dist/oauth/discord.cjs +27 -24
- package/dist/oauth/discord.d.ts +7 -2
- package/dist/oauth/discord.js +1 -1
- 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.cjs +19 -16
- package/dist/oauth/figma.d.ts +7 -2
- package/dist/oauth/figma.js +1 -1
- package/dist/oauth/github.cjs +19 -8
- package/dist/oauth/github.d.ts +7 -2
- package/dist/oauth/github.js +1 -1
- package/dist/oauth/gitlab.cjs +19 -16
- package/dist/oauth/gitlab.d.ts +7 -2
- package/dist/oauth/gitlab.js +1 -1
- package/dist/oauth/index.cjs +529 -239
- package/dist/oauth/index.d.ts +7 -2
- package/dist/oauth/index.js +39 -22
- package/dist/oauth/mailchimp.cjs +19 -16
- package/dist/oauth/mailchimp.d.ts +7 -2
- package/dist/oauth/mailchimp.js +1 -1
- 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.cjs +19 -16
- package/dist/oauth/pinterest.d.ts +7 -2
- package/dist/oauth/pinterest.js +1 -1
- package/dist/oauth/spotify.cjs +19 -16
- package/dist/oauth/spotify.d.ts +7 -2
- package/dist/oauth/spotify.js +1 -1
- package/dist/oauth/strava.cjs +19 -16
- package/dist/oauth/strava.d.ts +7 -2
- package/dist/oauth/strava.js +1 -1
- 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.cjs +19 -16
- package/dist/oauth/x.d.ts +7 -2
- package/dist/oauth/x.js +1 -1
- package/dist/schemas.cjs +89 -42
- package/dist/schemas.d.ts +114 -18
- package/dist/schemas.js +5 -3
- package/dist/secure.cjs +73 -31
- package/dist/secure.d.ts +11 -11
- package/dist/secure.js +7 -6
- package/dist/utils.cjs +203 -90
- package/dist/utils.d.ts +21 -40
- package/dist/utils.js +21 -12
- package/package.json +9 -6
- package/dist/chunk-3EUWD5BB.js +0 -63
- package/dist/chunk-42XB3YCW.js +0 -22
- package/dist/chunk-6R2YZ4AC.js +0 -22
- package/dist/chunk-A3N4PVAT.js +0 -70
- package/dist/chunk-B737EUJV.js +0 -22
- package/dist/chunk-CXLATHS5.js +0 -143
- package/dist/chunk-E3OXBRYF.js +0 -22
- package/dist/chunk-EIL2FPSS.js +0 -22
- package/dist/chunk-EMKJA2GJ.js +0 -89
- package/dist/chunk-FIPU4MLT.js +0 -21
- package/dist/chunk-FKRDCWBF.js +0 -22
- package/dist/chunk-GA2SMTJO.js +0 -58
- package/dist/chunk-HP34YGGJ.js +0 -22
- package/dist/chunk-IKHPGFCW.js +0 -14
- package/dist/chunk-IUYZQTJV.js +0 -30
- package/dist/chunk-IVET23KF.js +0 -58
- package/dist/chunk-JVFTCTTE.js +0 -33
- package/dist/chunk-KRNOMBXQ.js +0 -22
- package/dist/chunk-KSWLO5ZU.js +0 -102
- package/dist/chunk-N2APGLXA.js +0 -71
- package/dist/chunk-N4SX7TZT.js +0 -96
- package/dist/chunk-STHEPPUZ.js +0 -11
- package/dist/chunk-TLE4PXY3.js +0 -39
- package/dist/index-B8jeIElf.d.ts +0 -679
- /package/dist/{chunk-DIVDFNAP.js → chunk-5X7JZMEF.js} +0 -0
|
@@ -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
|
+
};
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getUserInfo
|
|
3
|
+
} from "./chunk-GNNBM2WJ.js";
|
|
4
|
+
import {
|
|
5
|
+
createAccessToken
|
|
6
|
+
} from "./chunk-7BE46WWS.js";
|
|
7
|
+
import {
|
|
8
|
+
getOriginURL,
|
|
9
|
+
getTrustedOrigins
|
|
10
|
+
} from "./chunk-LATR3NIV.js";
|
|
11
|
+
import {
|
|
12
|
+
createCSRF
|
|
13
|
+
} from "./chunk-V6LLEAR4.js";
|
|
14
|
+
import {
|
|
15
|
+
OAuthAuthorizationErrorResponse
|
|
16
|
+
} from "./chunk-2A5B7GWR.js";
|
|
17
|
+
import {
|
|
18
|
+
isRelativeURL,
|
|
19
|
+
isSameOrigin,
|
|
20
|
+
isTrustedOrigin,
|
|
21
|
+
timingSafeEqual
|
|
22
|
+
} from "./chunk-LX3TJ2TJ.js";
|
|
23
|
+
import {
|
|
24
|
+
createSessionCookie,
|
|
25
|
+
expiredCookieAttributes,
|
|
26
|
+
getCookie
|
|
27
|
+
} from "./chunk-XY5R3EHH.js";
|
|
28
|
+
import {
|
|
29
|
+
AuthSecurityError,
|
|
30
|
+
OAuthProtocolError
|
|
31
|
+
} from "./chunk-U5663F2U.js";
|
|
32
|
+
import {
|
|
33
|
+
cacheControl
|
|
34
|
+
} from "./chunk-EBAMFRB7.js";
|
|
35
|
+
|
|
36
|
+
// src/actions/callback/callback.ts
|
|
37
|
+
import { z } from "zod/v4";
|
|
38
|
+
import { createEndpoint, createEndpointConfig, HeadersBuilder } from "@aura-stack/router";
|
|
39
|
+
var callbackConfig = (oauth) => {
|
|
40
|
+
return createEndpointConfig("/callback/:oauth", {
|
|
41
|
+
schemas: {
|
|
42
|
+
params: z.object({
|
|
43
|
+
oauth: z.enum(
|
|
44
|
+
Object.keys(oauth),
|
|
45
|
+
"The OAuth provider is not supported or invalid."
|
|
46
|
+
)
|
|
47
|
+
}),
|
|
48
|
+
searchParams: z.object({
|
|
49
|
+
code: z.string("Missing code parameter in the OAuth authorization response."),
|
|
50
|
+
state: z.string("Missing state parameter in the OAuth authorization response.")
|
|
51
|
+
})
|
|
52
|
+
},
|
|
53
|
+
use: [
|
|
54
|
+
(ctx) => {
|
|
55
|
+
const {
|
|
56
|
+
searchParams,
|
|
57
|
+
context: { logger }
|
|
58
|
+
} = ctx;
|
|
59
|
+
const response = OAuthAuthorizationErrorResponse.safeParse(searchParams);
|
|
60
|
+
if (response.success) {
|
|
61
|
+
const { error, error_description } = response.data;
|
|
62
|
+
const criticalAuthErrors = ["access_denied", "server_error"];
|
|
63
|
+
const severity = criticalAuthErrors.includes(error.toLowerCase()) ? "critical" : "warning";
|
|
64
|
+
logger?.log("OAUTH_AUTHORIZATION_ERROR", {
|
|
65
|
+
severity,
|
|
66
|
+
structuredData: {
|
|
67
|
+
error,
|
|
68
|
+
error_description: error_description ?? ""
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
throw new OAuthProtocolError(error, error_description || "OAuth Authorization Error");
|
|
72
|
+
}
|
|
73
|
+
return ctx;
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
var callbackAction = (oauth) => {
|
|
79
|
+
return createEndpoint(
|
|
80
|
+
"GET",
|
|
81
|
+
"/callback/:oauth",
|
|
82
|
+
async (ctx) => {
|
|
83
|
+
const {
|
|
84
|
+
request,
|
|
85
|
+
params: { oauth: oauth2 },
|
|
86
|
+
searchParams: { code, state },
|
|
87
|
+
context
|
|
88
|
+
} = ctx;
|
|
89
|
+
const { oauth: providers, cookies, jose, logger, trustedOrigins } = context;
|
|
90
|
+
const oauthConfig = providers[oauth2];
|
|
91
|
+
const cookieState = getCookie(request, cookies.state.name);
|
|
92
|
+
const codeVerifier = getCookie(request, cookies.codeVerifier.name);
|
|
93
|
+
const cookieRedirectTo = getCookie(request, cookies.redirectTo.name);
|
|
94
|
+
const cookieRedirectURI = getCookie(request, cookies.redirectURI.name);
|
|
95
|
+
if (!timingSafeEqual(cookieState, state)) {
|
|
96
|
+
logger?.log("MISMATCHING_STATE", {
|
|
97
|
+
structuredData: {
|
|
98
|
+
oauth_provider: oauth2
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
throw new AuthSecurityError(
|
|
102
|
+
"MISMATCHING_STATE",
|
|
103
|
+
"The provided state passed in the OAuth response does not match the stored state."
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
const accessToken = await createAccessToken(oauthConfig, cookieRedirectURI, code, codeVerifier, logger);
|
|
107
|
+
const origins = await getTrustedOrigins(request, trustedOrigins);
|
|
108
|
+
const requestOrigin = await getOriginURL(request, context);
|
|
109
|
+
if (!isRelativeURL(cookieRedirectTo)) {
|
|
110
|
+
const isValid = origins.length > 0 ? isTrustedOrigin(cookieRedirectTo, origins) : isSameOrigin(cookieRedirectTo, requestOrigin);
|
|
111
|
+
if (!isValid) {
|
|
112
|
+
logger?.log("POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED", {
|
|
113
|
+
structuredData: {
|
|
114
|
+
redirect_path: cookieRedirectTo,
|
|
115
|
+
provider: oauth2,
|
|
116
|
+
has_trusted_origins: origins.length > 0,
|
|
117
|
+
request_origin: requestOrigin
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
throw new AuthSecurityError(
|
|
121
|
+
"POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED",
|
|
122
|
+
"Invalid redirect path. Potential open redirect attack detected."
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const userInfo = await getUserInfo(oauthConfig, accessToken.access_token, logger);
|
|
127
|
+
const sessionCookie = await createSessionCookie(jose, userInfo);
|
|
128
|
+
const csrfToken = await createCSRF(jose);
|
|
129
|
+
logger?.log("OAUTH_CALLBACK_SUCCESS", {
|
|
130
|
+
structuredData: {
|
|
131
|
+
provider: oauth2
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
const headers = new HeadersBuilder(cacheControl).setHeader("Location", cookieRedirectTo).setCookie(cookies.sessionToken.name, sessionCookie, cookies.sessionToken.attributes).setCookie(cookies.csrfToken.name, csrfToken, cookies.csrfToken.attributes).setCookie(cookies.state.name, "", expiredCookieAttributes).setCookie(cookies.redirectURI.name, "", expiredCookieAttributes).setCookie(cookies.redirectTo.name, "", expiredCookieAttributes).setCookie(cookies.codeVerifier.name, "", expiredCookieAttributes).toHeaders();
|
|
135
|
+
return Response.json({ oauth: oauth2 }, { status: 302, headers });
|
|
136
|
+
},
|
|
137
|
+
callbackConfig(oauth)
|
|
138
|
+
);
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
export {
|
|
142
|
+
callbackAction
|
|
143
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// src/oauth/discord.ts
|
|
2
|
+
var discord = (options) => {
|
|
3
|
+
return {
|
|
4
|
+
id: "discord",
|
|
5
|
+
name: "Discord",
|
|
6
|
+
authorizeURL: "https://discord.com/oauth2/authorize",
|
|
7
|
+
accessToken: "https://discord.com/api/oauth2/token",
|
|
8
|
+
userInfo: "https://discord.com/api/users/@me",
|
|
9
|
+
scope: "identify email",
|
|
10
|
+
responseType: "code",
|
|
11
|
+
profile(profile) {
|
|
12
|
+
let image = "";
|
|
13
|
+
if (profile.avatar === null) {
|
|
14
|
+
const index = profile.discriminator === "0" ? (BigInt(profile.id) >> 22n) % 6n : Number(profile.discriminator) % 5;
|
|
15
|
+
image = `https://cdn.discordapp.com/embed/avatars/${index}.png`;
|
|
16
|
+
} else {
|
|
17
|
+
const format = profile.avatar.startsWith("a_") ? "gif" : "png";
|
|
18
|
+
image = `https://cdn.discordapp.com/avatars/${profile.id}/${profile.avatar}.${format}`;
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
sub: profile.id,
|
|
22
|
+
name: profile.global_name ?? profile.username,
|
|
23
|
+
email: profile.email ?? "",
|
|
24
|
+
image
|
|
25
|
+
};
|
|
26
|
+
},
|
|
27
|
+
...options
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export {
|
|
32
|
+
discord
|
|
33
|
+
};
|
|
@@ -0,0 +1,127 @@
|
|
|
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";
|
|
10
|
+
import {
|
|
11
|
+
spotify
|
|
12
|
+
} from "./chunk-IPKO6UQN.js";
|
|
13
|
+
import {
|
|
14
|
+
strava
|
|
15
|
+
} from "./chunk-54CZPKR4.js";
|
|
16
|
+
import {
|
|
17
|
+
twitch
|
|
18
|
+
} from "./chunk-2GQLSIJ2.js";
|
|
19
|
+
import {
|
|
20
|
+
x
|
|
21
|
+
} from "./chunk-EEE7UM5T.js";
|
|
22
|
+
import {
|
|
23
|
+
atlassian
|
|
24
|
+
} from "./chunk-C3A37LQC.js";
|
|
25
|
+
import {
|
|
26
|
+
bitbucket
|
|
27
|
+
} from "./chunk-4YHJ4IEQ.js";
|
|
28
|
+
import {
|
|
29
|
+
discord
|
|
30
|
+
} from "./chunk-OVHNRULD.js";
|
|
31
|
+
import {
|
|
32
|
+
dropbox
|
|
33
|
+
} from "./chunk-QQEKY4XP.js";
|
|
34
|
+
import {
|
|
35
|
+
figma
|
|
36
|
+
} from "./chunk-KMMAZFSJ.js";
|
|
37
|
+
import {
|
|
38
|
+
github
|
|
39
|
+
} from "./chunk-FW4W3REU.js";
|
|
40
|
+
import {
|
|
41
|
+
gitlab
|
|
42
|
+
} from "./chunk-5LZ7TOM3.js";
|
|
43
|
+
import {
|
|
44
|
+
OAuthEnvSchema,
|
|
45
|
+
OAuthProviderCredentialsSchema
|
|
46
|
+
} from "./chunk-2A5B7GWR.js";
|
|
47
|
+
import {
|
|
48
|
+
formatZodError
|
|
49
|
+
} from "./chunk-LX3TJ2TJ.js";
|
|
50
|
+
import {
|
|
51
|
+
getEnv
|
|
52
|
+
} from "./chunk-WHNDRO3N.js";
|
|
53
|
+
import {
|
|
54
|
+
AuthInternalError
|
|
55
|
+
} from "./chunk-U5663F2U.js";
|
|
56
|
+
|
|
57
|
+
// src/oauth/index.ts
|
|
58
|
+
var builtInOAuthProviders = {
|
|
59
|
+
github,
|
|
60
|
+
bitbucket,
|
|
61
|
+
figma,
|
|
62
|
+
discord,
|
|
63
|
+
gitlab,
|
|
64
|
+
spotify,
|
|
65
|
+
x,
|
|
66
|
+
strava,
|
|
67
|
+
mailchimp,
|
|
68
|
+
pinterest,
|
|
69
|
+
twitch,
|
|
70
|
+
notion,
|
|
71
|
+
dropbox,
|
|
72
|
+
atlassian
|
|
73
|
+
};
|
|
74
|
+
var defineOAuthEnvironment = (oauth) => {
|
|
75
|
+
const loadEnvs = OAuthEnvSchema.safeParse({
|
|
76
|
+
clientId: getEnv(`${oauth.toUpperCase()}_CLIENT_ID`),
|
|
77
|
+
clientSecret: getEnv(`${oauth.toUpperCase()}_CLIENT_SECRET`)
|
|
78
|
+
});
|
|
79
|
+
if (!loadEnvs.success) {
|
|
80
|
+
const msg = JSON.stringify({ [oauth]: formatZodError(loadEnvs.error) }, null, 2);
|
|
81
|
+
throw new AuthInternalError("INVALID_ENVIRONMENT_CONFIGURATION", msg);
|
|
82
|
+
}
|
|
83
|
+
return loadEnvs.data;
|
|
84
|
+
};
|
|
85
|
+
var defineOAuthProviderConfig = (config) => {
|
|
86
|
+
if (typeof config === "string") {
|
|
87
|
+
const definition = defineOAuthEnvironment(config);
|
|
88
|
+
const oauthConfig = builtInOAuthProviders[config]();
|
|
89
|
+
const parsed2 = OAuthProviderCredentialsSchema.safeParse({ ...oauthConfig, ...definition });
|
|
90
|
+
if (!parsed2.success) {
|
|
91
|
+
const details = JSON.stringify({ [config]: formatZodError(parsed2.error) }, null, 2);
|
|
92
|
+
throw new AuthInternalError(
|
|
93
|
+
"INVALID_OAUTH_PROVIDER_CONFIGURATION",
|
|
94
|
+
`Invalid configuration for OAuth provider "${config}": ${details}`
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
return parsed2.data;
|
|
98
|
+
}
|
|
99
|
+
const hasCredentials = config.clientId && config.clientSecret;
|
|
100
|
+
const envConfig = hasCredentials ? {} : defineOAuthEnvironment(config.id);
|
|
101
|
+
const parsed = OAuthProviderCredentialsSchema.safeParse({ ...envConfig, ...config });
|
|
102
|
+
if (!parsed.success) {
|
|
103
|
+
const details = JSON.stringify({ [config.id]: formatZodError(parsed.error) }, null, 2);
|
|
104
|
+
throw new AuthInternalError(
|
|
105
|
+
"INVALID_OAUTH_PROVIDER_CONFIGURATION",
|
|
106
|
+
`Invalid configuration for OAuth provider "${config.id}": ${details}`
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
return parsed.data;
|
|
110
|
+
};
|
|
111
|
+
var createBuiltInOAuthProviders = (oauth = []) => {
|
|
112
|
+
return oauth.reduce((previous, config) => {
|
|
113
|
+
const oauthConfig = defineOAuthProviderConfig(config);
|
|
114
|
+
if (oauthConfig.id in previous) {
|
|
115
|
+
throw new AuthInternalError(
|
|
116
|
+
"DUPLICATED_OAUTH_PROVIDER_ID",
|
|
117
|
+
`Duplicate OAuth provider id "${oauthConfig.id}" found. Each provider must have a unique id.`
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
return { ...previous, [oauthConfig.id]: oauthConfig };
|
|
121
|
+
}, {});
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export {
|
|
125
|
+
builtInOAuthProviders,
|
|
126
|
+
createBuiltInOAuthProviders
|
|
127
|
+
};
|
|
@@ -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
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// src/oauth/dropbox.ts
|
|
2
|
+
var dropbox = (options) => {
|
|
3
|
+
return {
|
|
4
|
+
id: "dropbox",
|
|
5
|
+
name: "Dropbox",
|
|
6
|
+
authorize: {
|
|
7
|
+
url: "https://www.dropbox.com/oauth2/authorize",
|
|
8
|
+
params: { scope: "account_info.read" }
|
|
9
|
+
},
|
|
10
|
+
accessToken: "https://api.dropboxapi.com/oauth2/token",
|
|
11
|
+
userInfo: {
|
|
12
|
+
method: "POST",
|
|
13
|
+
url: "https://api.dropboxapi.com/2/users/get_current_account"
|
|
14
|
+
},
|
|
15
|
+
profile(profile) {
|
|
16
|
+
return {
|
|
17
|
+
sub: profile.account_id,
|
|
18
|
+
name: profile.name.display_name,
|
|
19
|
+
email: profile.email,
|
|
20
|
+
image: profile.profile_photo_url
|
|
21
|
+
};
|
|
22
|
+
},
|
|
23
|
+
...options
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export {
|
|
28
|
+
dropbox
|
|
29
|
+
};
|