@aura-stack/auth 0.1.0 → 0.2.0-rc.1
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 +5 -5
- package/dist/@types/router.d.d.ts +5 -5
- package/dist/@types/utility.d.ts +1 -5
- package/dist/actions/callback/access-token.cjs +95 -74
- package/dist/actions/callback/access-token.d.ts +7 -7
- package/dist/actions/callback/access-token.js +5 -3
- package/dist/actions/callback/callback.cjs +171 -249
- package/dist/actions/callback/callback.d.ts +6 -6
- package/dist/actions/callback/callback.js +10 -10
- package/dist/actions/callback/userinfo.cjs +81 -57
- package/dist/actions/callback/userinfo.d.ts +5 -5
- package/dist/actions/callback/userinfo.js +7 -5
- package/dist/actions/csrfToken/csrfToken.cjs +36 -105
- package/dist/actions/csrfToken/csrfToken.js +6 -6
- package/dist/actions/index.cjs +309 -444
- package/dist/actions/index.d.ts +5 -5
- package/dist/actions/index.js +19 -19
- package/dist/actions/session/session.cjs +25 -109
- package/dist/actions/session/session.js +4 -5
- package/dist/actions/signIn/authorization.cjs +96 -87
- package/dist/actions/signIn/authorization.d.ts +5 -5
- package/dist/actions/signIn/authorization.js +5 -5
- package/dist/actions/signIn/signIn.cjs +133 -242
- package/dist/actions/signIn/signIn.d.ts +6 -6
- package/dist/actions/signIn/signIn.js +8 -9
- package/dist/actions/signOut/signOut.cjs +136 -282
- package/dist/actions/signOut/signOut.js +8 -9
- package/dist/assert.cjs +5 -0
- package/dist/assert.d.ts +10 -1
- package/dist/assert.js +3 -1
- package/dist/chunk-3EUWD5BB.js +63 -0
- package/dist/chunk-6R2YZ4AC.js +22 -0
- package/dist/chunk-A3N4PVAT.js +70 -0
- package/dist/chunk-B737EUJV.js +22 -0
- package/dist/{chunk-256KIVJL.js → chunk-CXLATHS5.js} +53 -9
- package/dist/{chunk-6SM22VVJ.js → chunk-EIL2FPSS.js} +5 -1
- package/dist/{chunk-VFTYH33W.js → chunk-EMKJA2GJ.js} +36 -8
- package/dist/{chunk-UJJ7R56J.js → chunk-GA2SMTJO.js} +16 -10
- package/dist/chunk-HP34YGGJ.js +22 -0
- package/dist/chunk-HT4YLL7N.js +35 -0
- package/dist/{chunk-EBPE35JT.js → chunk-IUYZQTJV.js} +0 -1
- package/dist/{chunk-RLT4RFKV.js → chunk-IVET23KF.js} +21 -8
- package/dist/{chunk-XXJKNKGQ.js → chunk-JVFTCTTE.js} +9 -13
- package/dist/chunk-KSWLO5ZU.js +102 -0
- package/dist/{chunk-GZU3RBTB.js → chunk-N2APGLXA.js} +19 -10
- package/dist/{chunk-CAKJT3KS.js → chunk-N4SX7TZT.js} +21 -17
- package/dist/chunk-RRLIF4PQ.js +55 -0
- package/dist/chunk-TLE4PXY3.js +39 -0
- package/dist/chunk-W6LG7BFW.js +197 -0
- package/dist/{chunk-HMRKN75I.js → chunk-YRCB5FLE.js} +14 -9
- package/dist/chunk-ZNCZVF6U.js +14 -0
- package/dist/cookie.cjs +140 -99
- package/dist/cookie.d.ts +35 -44
- package/dist/cookie.js +10 -17
- package/dist/errors.cjs +85 -0
- package/dist/errors.d.ts +49 -0
- package/dist/errors.js +18 -0
- package/dist/{index-DpfbvTZ_.d.ts → index-DkaLJFn8.d.ts} +192 -61
- package/dist/index.cjs +543 -443
- package/dist/index.d.ts +6 -6
- package/dist/index.js +42 -28
- package/dist/jose.cjs +25 -14
- package/dist/jose.d.ts +4 -1
- package/dist/jose.js +5 -4
- package/dist/oauth/bitbucket.d.ts +5 -5
- package/dist/oauth/discord.cjs +0 -1
- package/dist/oauth/discord.d.ts +5 -5
- package/dist/oauth/discord.js +1 -1
- package/dist/oauth/figma.d.ts +5 -5
- package/dist/oauth/github.d.ts +5 -5
- package/dist/oauth/gitlab.d.ts +5 -5
- package/dist/oauth/index.cjs +176 -6
- package/dist/oauth/index.d.ts +5 -5
- package/dist/oauth/index.js +19 -4
- package/dist/oauth/mailchimp.cjs +46 -0
- package/dist/oauth/mailchimp.d.ts +7 -0
- package/dist/oauth/mailchimp.js +6 -0
- package/dist/oauth/pinterest.cjs +46 -0
- package/dist/oauth/pinterest.d.ts +7 -0
- package/dist/oauth/pinterest.js +6 -0
- package/dist/oauth/spotify.d.ts +5 -5
- package/dist/oauth/strava.cjs +46 -0
- package/dist/oauth/strava.d.ts +7 -0
- package/dist/oauth/strava.js +6 -0
- package/dist/oauth/x.d.ts +5 -5
- package/dist/{response.cjs → request.cjs} +14 -10
- package/dist/request.d.ts +13 -0
- package/dist/request.js +6 -0
- package/dist/schemas.cjs +43 -37
- package/dist/schemas.d.ts +67 -64
- package/dist/schemas.js +3 -1
- package/dist/secure.cjs +32 -24
- package/dist/secure.d.ts +5 -5
- package/dist/secure.js +4 -3
- package/dist/utils.cjs +90 -15
- package/dist/utils.d.ts +11 -2
- package/dist/utils.js +8 -4
- package/package.json +8 -7
- package/dist/chunk-FJUDBLCP.js +0 -59
- package/dist/chunk-HGJ4TXY4.js +0 -137
- package/dist/chunk-JAPMIE6S.js +0 -10
- package/dist/chunk-LLR722CL.js +0 -96
- package/dist/chunk-SJPDVKUS.js +0 -112
- package/dist/chunk-SMQO5WD7.js +0 -30
- package/dist/chunk-UTDLUEEG.js +0 -31
- package/dist/chunk-ZV4BH47P.js +0 -154
- package/dist/error.cjs +0 -88
- package/dist/error.d.ts +0 -62
- package/dist/error.js +0 -16
- package/dist/response.d.ts +0 -10
- package/dist/response.js +0 -6
package/dist/index.cjs
CHANGED
|
@@ -36,58 +36,60 @@ module.exports = __toCommonJS(index_exports);
|
|
|
36
36
|
var import_config2 = require("dotenv/config");
|
|
37
37
|
var import_router7 = require("@aura-stack/router");
|
|
38
38
|
|
|
39
|
+
// src/jose.ts
|
|
40
|
+
var import_config = require("dotenv/config");
|
|
41
|
+
var import_jose = require("@aura-stack/jose");
|
|
42
|
+
|
|
43
|
+
// src/secure.ts
|
|
44
|
+
var import_crypto = __toESM(require("crypto"), 1);
|
|
45
|
+
|
|
39
46
|
// src/utils.ts
|
|
40
47
|
var import_router = require("@aura-stack/router");
|
|
41
48
|
|
|
42
|
-
// src/
|
|
43
|
-
var
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
49
|
+
// src/errors.ts
|
|
50
|
+
var OAuthProtocolError = class extends Error {
|
|
51
|
+
type = "OAUTH_PROTOCOL_ERROR";
|
|
52
|
+
error;
|
|
53
|
+
errorURI;
|
|
54
|
+
constructor(error, description, errorURI, options2) {
|
|
55
|
+
super(description, options2);
|
|
56
|
+
this.error = error;
|
|
57
|
+
this.errorURI = errorURI;
|
|
58
|
+
this.name = new.target.name;
|
|
59
|
+
Error.captureStackTrace(this, new.target);
|
|
48
60
|
}
|
|
49
61
|
};
|
|
50
|
-
var
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
62
|
+
var AuthInternalError = class extends Error {
|
|
63
|
+
type = "AUTH_INTERNAL_ERROR";
|
|
64
|
+
code;
|
|
65
|
+
constructor(code, message, options2) {
|
|
66
|
+
super(message, options2);
|
|
67
|
+
this.code = code;
|
|
68
|
+
this.name = new.target.name;
|
|
69
|
+
Error.captureStackTrace(this, new.target);
|
|
54
70
|
}
|
|
55
71
|
};
|
|
56
|
-
var
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
72
|
+
var AuthSecurityError = class extends Error {
|
|
73
|
+
type = "AUTH_SECURITY_ERROR";
|
|
74
|
+
code;
|
|
75
|
+
constructor(code, message, options2) {
|
|
76
|
+
super(message, options2);
|
|
77
|
+
this.code = code;
|
|
78
|
+
this.name = new.target.name;
|
|
79
|
+
Error.captureStackTrace(this, new.target);
|
|
60
80
|
}
|
|
61
81
|
};
|
|
62
|
-
var
|
|
63
|
-
return error instanceof
|
|
82
|
+
var isNativeError = (error) => {
|
|
83
|
+
return error instanceof Error;
|
|
64
84
|
};
|
|
65
|
-
var
|
|
66
|
-
|
|
67
|
-
if (isAuthError(error)) {
|
|
68
|
-
throw error;
|
|
69
|
-
}
|
|
70
|
-
throw new AuthError("invalid_request", error.message ?? message);
|
|
71
|
-
}
|
|
85
|
+
var isOAuthProtocolError = (error) => {
|
|
86
|
+
return error instanceof OAuthProtocolError;
|
|
72
87
|
};
|
|
73
|
-
var
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
UNSUPPORTED_RESPONSE_TYPE: "unsupported_response_type",
|
|
79
|
-
INVALID_SCOPE: "invalid_scope",
|
|
80
|
-
SERVER_ERROR: "server_error",
|
|
81
|
-
TEMPORARILY_UNAVAILABLE: "temporarily_unavailable"
|
|
82
|
-
},
|
|
83
|
-
ACCESS_TOKEN: {
|
|
84
|
-
INVALID_REQUEST: "invalid_request",
|
|
85
|
-
INVALID_CLIENT: "invalid_client",
|
|
86
|
-
INVALID_GRANT: "invalid_grant",
|
|
87
|
-
UNAUTHORIZED_CLIENT: "unauthorized_client",
|
|
88
|
-
UNSUPPORTED_GRANT_TYPE: "unsupported_grant_type",
|
|
89
|
-
INVALID_SCOPE: "invalid_scope"
|
|
90
|
-
}
|
|
88
|
+
var isAuthInternalError = (error) => {
|
|
89
|
+
return error instanceof AuthInternalError;
|
|
90
|
+
};
|
|
91
|
+
var isAuthSecurityError = (error) => {
|
|
92
|
+
return error instanceof AuthSecurityError;
|
|
91
93
|
};
|
|
92
94
|
|
|
93
95
|
// src/utils.ts
|
|
@@ -107,9 +109,9 @@ var equals = (a, b) => {
|
|
|
107
109
|
if (a === null || b === null || a === void 0 || b === void 0) return false;
|
|
108
110
|
return a === b;
|
|
109
111
|
};
|
|
110
|
-
var sanitizeURL = (
|
|
112
|
+
var sanitizeURL = (url) => {
|
|
111
113
|
try {
|
|
112
|
-
let decodedURL = decodeURIComponent(
|
|
114
|
+
let decodedURL = decodeURIComponent(url).trim();
|
|
113
115
|
const protocolMatch = decodedURL.match(/^([a-zA-Z][a-zA-Z0-9+.-]*:\/\/)/);
|
|
114
116
|
let protocol = "";
|
|
115
117
|
let rest = decodedURL;
|
|
@@ -137,7 +139,7 @@ var sanitizeURL = (url2) => {
|
|
|
137
139
|
}
|
|
138
140
|
return sanitized;
|
|
139
141
|
} catch {
|
|
140
|
-
return
|
|
142
|
+
return url.trim();
|
|
141
143
|
}
|
|
142
144
|
};
|
|
143
145
|
var isValidRelativePath = (path) => {
|
|
@@ -151,20 +153,42 @@ var isValidRelativePath = (path) => {
|
|
|
151
153
|
var onErrorHandler = (error) => {
|
|
152
154
|
if ((0, import_router.isRouterError)(error)) {
|
|
153
155
|
const { message, status, statusText } = error;
|
|
154
|
-
return Response.json({
|
|
156
|
+
return Response.json({ type: "ROUTER_ERROR", code: "ROUTER_INTERNAL_ERROR", message }, { status, statusText });
|
|
155
157
|
}
|
|
156
|
-
if (
|
|
157
|
-
|
|
158
|
-
|
|
158
|
+
if ((0, import_router.isInvalidZodSchemaError)(error)) {
|
|
159
|
+
return Response.json({ type: "ROUTER_ERROR", code: "INVALID_REQUEST", message: error.errors }, { status: 422 });
|
|
160
|
+
}
|
|
161
|
+
if (isOAuthProtocolError(error)) {
|
|
162
|
+
const { error: errorCode, message, type, errorURI } = error;
|
|
163
|
+
return Response.json(
|
|
164
|
+
{
|
|
165
|
+
type,
|
|
166
|
+
error: errorCode,
|
|
167
|
+
error_description: message,
|
|
168
|
+
error_uri: errorURI
|
|
169
|
+
},
|
|
170
|
+
{ status: 400 }
|
|
171
|
+
);
|
|
159
172
|
}
|
|
160
|
-
|
|
173
|
+
if (isAuthInternalError(error) || isAuthSecurityError(error)) {
|
|
174
|
+
const { type, code, message } = error;
|
|
175
|
+
return Response.json(
|
|
176
|
+
{
|
|
177
|
+
type,
|
|
178
|
+
code,
|
|
179
|
+
message
|
|
180
|
+
},
|
|
181
|
+
{ status: 400 }
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
return Response.json({ type: "SERVER_ERROR", code: "server_error", message: "An unexpected error occurred" }, { status: 500 });
|
|
161
185
|
};
|
|
162
186
|
var getNormalizedOriginPath = (path) => {
|
|
163
187
|
try {
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
return `${
|
|
188
|
+
const url = new URL(path);
|
|
189
|
+
url.hash = "";
|
|
190
|
+
url.search = "";
|
|
191
|
+
return `${url.origin}${url.pathname}`;
|
|
168
192
|
} catch {
|
|
169
193
|
return sanitizeURL(path);
|
|
170
194
|
}
|
|
@@ -172,18 +196,41 @@ var getNormalizedOriginPath = (path) => {
|
|
|
172
196
|
var toISOString = (date) => {
|
|
173
197
|
return new Date(date).toISOString();
|
|
174
198
|
};
|
|
199
|
+
var useSecureCookies = (request, trustedProxyHeaders) => {
|
|
200
|
+
return trustedProxyHeaders ? request.url.startsWith("https://") || request.headers.get("X-Forwarded-Proto") === "https" || (request.headers.get("Forwarded")?.includes("proto=https") ?? false) : request.url.startsWith("https://");
|
|
201
|
+
};
|
|
202
|
+
var formatZodError = (error) => {
|
|
203
|
+
if (!error.issues || error.issues.length === 0) {
|
|
204
|
+
return {};
|
|
205
|
+
}
|
|
206
|
+
return error.issues.reduce((previous, issue) => {
|
|
207
|
+
const key = issue.path.join(".");
|
|
208
|
+
return {
|
|
209
|
+
...previous,
|
|
210
|
+
[key]: {
|
|
211
|
+
code: issue.code,
|
|
212
|
+
message: issue.message
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
}, {});
|
|
216
|
+
};
|
|
175
217
|
|
|
176
|
-
// src/
|
|
177
|
-
var
|
|
178
|
-
|
|
218
|
+
// src/assert.ts
|
|
219
|
+
var isValidURL = (value) => {
|
|
220
|
+
if (value.includes("\r\n") || value.includes("\n") || value.includes("\r")) return false;
|
|
221
|
+
const regex = /^https?:\/\/(?:[a-zA-Z0-9._-]+|localhost|\[[0-9a-fA-F:]+\])(?::\d{1,5})?(?:\/[a-zA-Z0-9._~!$&'()*+,;=:@-]*)*\/?$/;
|
|
222
|
+
return regex.test(value);
|
|
223
|
+
};
|
|
224
|
+
var isJWTPayloadWithToken = (payload) => {
|
|
225
|
+
return typeof payload === "object" && payload !== null && "token" in payload && typeof payload?.token === "string";
|
|
226
|
+
};
|
|
179
227
|
|
|
180
228
|
// src/secure.ts
|
|
181
|
-
var import_node_crypto = __toESM(require("crypto"), 1);
|
|
182
229
|
var generateSecure = (length = 32) => {
|
|
183
|
-
return
|
|
230
|
+
return import_crypto.default.randomBytes(length).toString("base64url");
|
|
184
231
|
};
|
|
185
232
|
var createHash = (data, base = "hex") => {
|
|
186
|
-
return
|
|
233
|
+
return import_crypto.default.createHash("sha256").update(data).digest().toString(base);
|
|
187
234
|
};
|
|
188
235
|
var createPKCE = async (verifier) => {
|
|
189
236
|
const codeVerifier = verifier ?? generateSecure(86);
|
|
@@ -205,59 +252,60 @@ var createCSRF = async (jose, csrfCookie) => {
|
|
|
205
252
|
};
|
|
206
253
|
var verifyCSRF = async (jose, cookie, header) => {
|
|
207
254
|
try {
|
|
208
|
-
const
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
|
|
255
|
+
const cookiePayload = await jose.verifyJWS(cookie);
|
|
256
|
+
const headerPayload = await jose.verifyJWS(header);
|
|
257
|
+
if (!isJWTPayloadWithToken(cookiePayload)) {
|
|
258
|
+
throw new AuthSecurityError("CSRF_TOKEN_INVALID", "Cookie payload missing token field.");
|
|
259
|
+
}
|
|
260
|
+
if (!isJWTPayloadWithToken(headerPayload)) {
|
|
261
|
+
throw new AuthSecurityError("CSRF_TOKEN_INVALID", "Header payload missing token field.");
|
|
262
|
+
}
|
|
263
|
+
const cookieBuffer = Buffer.from(cookiePayload.token);
|
|
264
|
+
const headerBuffer = Buffer.from(headerPayload.token);
|
|
212
265
|
if (!equals(headerBuffer.length, cookieBuffer.length)) {
|
|
213
|
-
throw new
|
|
266
|
+
throw new AuthSecurityError("CSRF_TOKEN_INVALID", "The CSRF tokens do not match.");
|
|
214
267
|
}
|
|
215
|
-
if (!
|
|
216
|
-
throw new
|
|
268
|
+
if (!import_crypto.default.timingSafeEqual(cookieBuffer, headerBuffer)) {
|
|
269
|
+
throw new AuthSecurityError("CSRF_TOKEN_INVALID", "The CSRF tokens do not match.");
|
|
217
270
|
}
|
|
218
271
|
return true;
|
|
219
272
|
} catch {
|
|
220
|
-
throw new
|
|
273
|
+
throw new AuthSecurityError("CSRF_TOKEN_INVALID", "The CSRF tokens do not match.");
|
|
221
274
|
}
|
|
222
275
|
};
|
|
223
276
|
var createDerivedSalt = (secret) => {
|
|
224
|
-
return
|
|
277
|
+
return import_crypto.default.createHash("sha256").update(secret).update("aura-auth-salt").digest("hex");
|
|
225
278
|
};
|
|
226
279
|
|
|
227
280
|
// src/jose.ts
|
|
228
281
|
var createJoseInstance = (secret) => {
|
|
229
|
-
|
|
282
|
+
const env = process.env;
|
|
283
|
+
secret ??= env.AURA_AUTH_SECRET ?? env.AUTH_SECRET;
|
|
230
284
|
if (!secret) {
|
|
231
|
-
throw new
|
|
285
|
+
throw new AuthInternalError(
|
|
286
|
+
"JOSE_INITIALIZATION_FAILED",
|
|
287
|
+
"AURA_AUTH_SECRET environment variable is not set and no secret was provided."
|
|
288
|
+
);
|
|
232
289
|
}
|
|
233
|
-
const salt =
|
|
234
|
-
const { derivedKey:
|
|
290
|
+
const salt = env.AURA_AUTH_SALT ?? env.AUTH_SALT ?? createDerivedSalt(secret);
|
|
291
|
+
const { derivedKey: derivedSigningKey } = (0, import_jose.createDeriveKey)(secret, salt, "signing");
|
|
292
|
+
const { derivedKey: derivedEncryptionKey } = (0, import_jose.createDeriveKey)(secret, salt, "encryption");
|
|
235
293
|
const { derivedKey: derivedCsrfTokenKey } = (0, import_jose.createDeriveKey)(secret, salt, "csrfToken");
|
|
236
|
-
const { decodeJWT, encodeJWT } = (0, import_jose.createJWT)(
|
|
294
|
+
const { decodeJWT, encodeJWT } = (0, import_jose.createJWT)({ jws: derivedSigningKey, jwe: derivedEncryptionKey });
|
|
237
295
|
const { signJWS, verifyJWS } = (0, import_jose.createJWS)(derivedCsrfTokenKey);
|
|
296
|
+
const { encryptJWE, decryptJWE } = (0, import_jose.createJWE)(derivedEncryptionKey);
|
|
238
297
|
return {
|
|
239
298
|
decodeJWT,
|
|
240
299
|
encodeJWT,
|
|
241
300
|
signJWS,
|
|
242
|
-
verifyJWS
|
|
301
|
+
verifyJWS,
|
|
302
|
+
encryptJWE,
|
|
303
|
+
decryptJWE
|
|
243
304
|
};
|
|
244
305
|
};
|
|
245
306
|
|
|
246
307
|
// src/cookie.ts
|
|
247
|
-
var import_cookie = require("cookie");
|
|
248
|
-
|
|
249
|
-
// src/assert.ts
|
|
250
|
-
var isRequest = (value) => {
|
|
251
|
-
return typeof Request !== "undefined" && value instanceof Request;
|
|
252
|
-
};
|
|
253
|
-
var isValidURL = (value) => {
|
|
254
|
-
if (value.includes("\r\n") || value.includes("\n") || value.includes("\r")) return false;
|
|
255
|
-
const regex = /^https?:\/\/(?:[a-zA-Z0-9._-]+|localhost|\[[0-9a-fA-F:]+\])(?::\d{1,5})?(?:\/[a-zA-Z0-9._~!$&'()*+,;=:@-]*)*\/?$/;
|
|
256
|
-
return regex.test(value);
|
|
257
|
-
};
|
|
258
|
-
|
|
259
|
-
// src/cookie.ts
|
|
260
|
-
var import_cookie2 = require("cookie");
|
|
308
|
+
var import_cookie = require("@aura-stack/router/cookie");
|
|
261
309
|
var COOKIE_NAME = "aura-auth";
|
|
262
310
|
var defaultCookieOptions = {
|
|
263
311
|
httpOnly: true,
|
|
@@ -265,123 +313,162 @@ var defaultCookieOptions = {
|
|
|
265
313
|
path: "/",
|
|
266
314
|
maxAge: 60 * 60 * 24 * 15
|
|
267
315
|
};
|
|
268
|
-
var defaultCookieConfig = {
|
|
269
|
-
strategy: "standard",
|
|
270
|
-
name: COOKIE_NAME,
|
|
271
|
-
options: defaultCookieOptions
|
|
272
|
-
};
|
|
273
316
|
var defaultStandardCookieConfig = {
|
|
274
317
|
secure: false,
|
|
275
|
-
httpOnly: true
|
|
276
|
-
prefix: ""
|
|
318
|
+
httpOnly: true
|
|
277
319
|
};
|
|
278
320
|
var defaultSecureCookieConfig = {
|
|
279
321
|
secure: true,
|
|
280
|
-
|
|
322
|
+
httpOnly: true
|
|
281
323
|
};
|
|
282
324
|
var defaultHostCookieConfig = {
|
|
283
325
|
secure: true,
|
|
284
|
-
|
|
326
|
+
httpOnly: true,
|
|
285
327
|
path: "/",
|
|
286
328
|
domain: void 0
|
|
287
329
|
};
|
|
288
|
-
var
|
|
330
|
+
var oauthCookieOptions = {
|
|
331
|
+
httpOnly: true,
|
|
332
|
+
maxAge: 5 * 60,
|
|
333
|
+
sameSite: "lax",
|
|
334
|
+
expires: new Date(Date.now() + 5 * 60 * 1e3)
|
|
335
|
+
};
|
|
336
|
+
var setCookie = (cookieName, value, options2) => {
|
|
337
|
+
return (0, import_cookie.serialize)(cookieName, value, options2);
|
|
338
|
+
};
|
|
339
|
+
var expiredCookieAttributes = {
|
|
289
340
|
...defaultCookieOptions,
|
|
290
341
|
expires: /* @__PURE__ */ new Date(0),
|
|
291
342
|
maxAge: 0
|
|
292
343
|
};
|
|
293
|
-
var
|
|
294
|
-
|
|
295
|
-
name: options2?.name ?? COOKIE_NAME,
|
|
296
|
-
prefix: options2?.prefix ?? (options2?.secure ? "__Secure-" : ""),
|
|
297
|
-
...defaultCookieOptions,
|
|
298
|
-
...options2
|
|
299
|
-
};
|
|
300
|
-
};
|
|
301
|
-
var setCookie = (cookieName, value, options2) => {
|
|
302
|
-
const { prefix, name } = defineDefaultCookieOptions(options2);
|
|
303
|
-
const cookieNameWithPrefix = `${prefix}${name}.${cookieName}`;
|
|
304
|
-
return (0, import_cookie.serialize)(cookieNameWithPrefix, value, {
|
|
305
|
-
...defaultCookieOptions,
|
|
306
|
-
...options2
|
|
307
|
-
});
|
|
308
|
-
};
|
|
309
|
-
var getCookie = (petition, cookie, options2, optional = false) => {
|
|
310
|
-
const cookies = isRequest(petition) ? petition.headers.get("Cookie") : petition.headers.getSetCookie().join("; ");
|
|
344
|
+
var getCookie = (request, cookieName) => {
|
|
345
|
+
const cookies = request.headers.get("Cookie");
|
|
311
346
|
if (!cookies) {
|
|
312
|
-
|
|
313
|
-
return "";
|
|
314
|
-
}
|
|
315
|
-
throw new AuthError("invalid_request", "No cookies found. There is no active session");
|
|
347
|
+
throw new AuthInternalError("COOKIE_NOT_FOUND", "No cookies found. There is no active session");
|
|
316
348
|
}
|
|
317
|
-
const
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
if (value === void 0) {
|
|
321
|
-
if (optional) {
|
|
322
|
-
return "";
|
|
323
|
-
}
|
|
324
|
-
throw new AuthError("invalid_request", `Cookie "${cookie}" not found. There is no active session`);
|
|
349
|
+
const value = (0, import_cookie.parse)(cookies)[cookieName];
|
|
350
|
+
if (!value) {
|
|
351
|
+
throw new AuthInternalError("COOKIE_NOT_FOUND", `Cookie "${cookieName}" not found. There is no active session`);
|
|
325
352
|
}
|
|
326
353
|
return value;
|
|
327
354
|
};
|
|
328
|
-
var createSessionCookie = async (
|
|
355
|
+
var createSessionCookie = async (jose, session) => {
|
|
329
356
|
try {
|
|
330
357
|
const encoded = await jose.encodeJWT(session);
|
|
331
|
-
return
|
|
358
|
+
return encoded;
|
|
332
359
|
} catch (error) {
|
|
333
|
-
throw new
|
|
360
|
+
throw new AuthInternalError("INVALID_JWT_TOKEN", "Failed to create session cookie", { cause: error });
|
|
334
361
|
}
|
|
335
362
|
};
|
|
336
|
-
var
|
|
337
|
-
|
|
338
|
-
const isSecure = trustedProxyHeaders ? request.url.startsWith("https://") || request.headers.get("X-Forwarded-Proto") === "https" || request.headers.get("Forwarded")?.includes("proto=https") : request.url.startsWith("https://");
|
|
339
|
-
if (!cookieOptions.options?.httpOnly) {
|
|
363
|
+
var defineSecureCookieOptions = (useSecure, attributes, strategy) => {
|
|
364
|
+
if (!attributes.httpOnly) {
|
|
340
365
|
console.warn(
|
|
341
366
|
"[WARNING]: Cookie is configured without HttpOnly. This allows JavaScript access via document.cookie and increases XSS risk."
|
|
342
367
|
);
|
|
343
368
|
}
|
|
344
|
-
if (
|
|
369
|
+
if (attributes.domain === "*") {
|
|
370
|
+
attributes.domain = void 0;
|
|
345
371
|
console.warn("[WARNING]: Cookie 'Domain' is set to '*', which is insecure. Avoid wildcard domains.");
|
|
346
372
|
}
|
|
347
|
-
if (!
|
|
348
|
-
|
|
349
|
-
if (options2?.secure) {
|
|
373
|
+
if (!useSecure) {
|
|
374
|
+
if (attributes.secure) {
|
|
350
375
|
console.warn(
|
|
351
376
|
"[WARNING]: The 'Secure' attribute will be disabled for this cookie. Serve over HTTPS to enforce Secure cookies."
|
|
352
377
|
);
|
|
353
378
|
}
|
|
354
|
-
if (
|
|
355
|
-
|
|
379
|
+
if (attributes.sameSite == "none") {
|
|
380
|
+
attributes.sameSite = "lax";
|
|
381
|
+
console.warn("[WARNING]: SameSite=None requires Secure attribute. Changing SameSite to 'Lax'.");
|
|
356
382
|
}
|
|
357
383
|
if (process.env.NODE_ENV === "production") {
|
|
358
384
|
console.warn("[WARNING]: In production, ensure cookies are served over HTTPS to maintain security.");
|
|
359
385
|
}
|
|
386
|
+
if (strategy === "host") {
|
|
387
|
+
console.warn("[WARNING]: __Host- cookies require a secure context. Falling back to standard cookie settings.");
|
|
388
|
+
}
|
|
360
389
|
return {
|
|
361
390
|
...defaultCookieOptions,
|
|
362
|
-
...
|
|
363
|
-
|
|
364
|
-
...defaultStandardCookieConfig,
|
|
365
|
-
name
|
|
391
|
+
...attributes,
|
|
392
|
+
...defaultStandardCookieConfig
|
|
366
393
|
};
|
|
367
394
|
}
|
|
368
|
-
return
|
|
395
|
+
return strategy === "host" ? {
|
|
369
396
|
...defaultCookieOptions,
|
|
370
|
-
...
|
|
371
|
-
...defaultHostCookieConfig
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
var oauthCookie = (options2) => {
|
|
397
|
+
...attributes,
|
|
398
|
+
...defaultHostCookieConfig
|
|
399
|
+
} : { ...defaultCookieOptions, ...attributes, ...defaultSecureCookieConfig };
|
|
400
|
+
};
|
|
401
|
+
var createCookieStore = (useSecure, prefix, overrides) => {
|
|
402
|
+
prefix ??= COOKIE_NAME;
|
|
403
|
+
const securePrefix = useSecure ? "__Secure-" : "";
|
|
404
|
+
const hostPrefix = useSecure ? "__Host-" : "";
|
|
379
405
|
return {
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
406
|
+
sessionToken: {
|
|
407
|
+
name: `${securePrefix}${prefix}.${overrides?.sessionToken?.name ?? "session_token"}`,
|
|
408
|
+
attributes: defineSecureCookieOptions(
|
|
409
|
+
useSecure,
|
|
410
|
+
{
|
|
411
|
+
...defaultCookieOptions,
|
|
412
|
+
...overrides?.sessionToken?.attributes
|
|
413
|
+
},
|
|
414
|
+
overrides?.sessionToken?.attributes?.strategy ?? "secure"
|
|
415
|
+
)
|
|
416
|
+
},
|
|
417
|
+
state: {
|
|
418
|
+
name: `${securePrefix}${prefix}.${overrides?.state?.name ?? "state"}`,
|
|
419
|
+
attributes: defineSecureCookieOptions(
|
|
420
|
+
useSecure,
|
|
421
|
+
{
|
|
422
|
+
...oauthCookieOptions,
|
|
423
|
+
...overrides?.state?.attributes
|
|
424
|
+
},
|
|
425
|
+
overrides?.state?.attributes?.strategy ?? "secure"
|
|
426
|
+
)
|
|
427
|
+
},
|
|
428
|
+
csrfToken: {
|
|
429
|
+
name: `${hostPrefix}${prefix}.${overrides?.csrfToken?.name ?? "csrf_token"}`,
|
|
430
|
+
attributes: defineSecureCookieOptions(
|
|
431
|
+
useSecure,
|
|
432
|
+
{
|
|
433
|
+
...overrides?.csrfToken?.attributes,
|
|
434
|
+
...defaultHostCookieConfig
|
|
435
|
+
},
|
|
436
|
+
overrides?.csrfToken?.attributes?.strategy ?? "host"
|
|
437
|
+
)
|
|
438
|
+
},
|
|
439
|
+
redirectTo: {
|
|
440
|
+
name: `${securePrefix}${prefix}.${overrides?.redirectTo?.name ?? "redirect_to"}`,
|
|
441
|
+
attributes: defineSecureCookieOptions(
|
|
442
|
+
useSecure,
|
|
443
|
+
{
|
|
444
|
+
...oauthCookieOptions,
|
|
445
|
+
...overrides?.redirectTo?.attributes
|
|
446
|
+
},
|
|
447
|
+
overrides?.redirectTo?.attributes?.strategy ?? "secure"
|
|
448
|
+
)
|
|
449
|
+
},
|
|
450
|
+
redirectURI: {
|
|
451
|
+
name: `${securePrefix}${prefix}.${overrides?.redirectURI?.name ?? "redirect_uri"}`,
|
|
452
|
+
attributes: defineSecureCookieOptions(
|
|
453
|
+
useSecure,
|
|
454
|
+
{
|
|
455
|
+
...oauthCookieOptions,
|
|
456
|
+
...overrides?.redirectURI?.attributes
|
|
457
|
+
},
|
|
458
|
+
overrides?.redirectURI?.attributes?.strategy ?? "secure"
|
|
459
|
+
)
|
|
460
|
+
},
|
|
461
|
+
codeVerifier: {
|
|
462
|
+
name: `${securePrefix}${prefix}.${overrides?.codeVerifier?.name ?? "code_verifier"}`,
|
|
463
|
+
attributes: defineSecureCookieOptions(
|
|
464
|
+
useSecure,
|
|
465
|
+
{
|
|
466
|
+
...oauthCookieOptions,
|
|
467
|
+
...overrides?.codeVerifier?.attributes
|
|
468
|
+
},
|
|
469
|
+
overrides?.codeVerifier?.attributes?.strategy ?? "secure"
|
|
470
|
+
)
|
|
471
|
+
}
|
|
385
472
|
};
|
|
386
473
|
};
|
|
387
474
|
|
|
@@ -453,7 +540,6 @@ var discord = {
|
|
|
453
540
|
}
|
|
454
541
|
return {
|
|
455
542
|
sub: profile.id,
|
|
456
|
-
// https://discord.com/developers/docs/change-log#display-names
|
|
457
543
|
name: profile.global_name ?? profile.username,
|
|
458
544
|
email: profile.email ?? "",
|
|
459
545
|
image
|
|
@@ -518,75 +604,86 @@ var x = {
|
|
|
518
604
|
}
|
|
519
605
|
};
|
|
520
606
|
|
|
521
|
-
// src/oauth/
|
|
522
|
-
var
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
var defineOAuthEnvironment = (oauth) => {
|
|
532
|
-
const env = process.env;
|
|
533
|
-
return {
|
|
534
|
-
clientId: env[`AURA_AUTH_${oauth.toUpperCase()}_CLIENT_ID`],
|
|
535
|
-
clientSecret: env[`AURA_AUTH_${oauth.toUpperCase()}_CLIENT_SECRET`]
|
|
536
|
-
};
|
|
537
|
-
};
|
|
538
|
-
var defineOAuthProviderConfig = (config2) => {
|
|
539
|
-
if (typeof config2 === "string") {
|
|
540
|
-
const definition = defineOAuthEnvironment(config2);
|
|
541
|
-
const oauthConfig = builtInOAuthProviders[config2];
|
|
607
|
+
// src/oauth/strava.ts
|
|
608
|
+
var strava = {
|
|
609
|
+
id: "strava",
|
|
610
|
+
name: "Strava",
|
|
611
|
+
authorizeURL: "https://www.strava.com/oauth/authorize",
|
|
612
|
+
accessToken: "https://www.strava.com/oauth/token",
|
|
613
|
+
userInfo: "https://www.strava.com/api/v3/athlete",
|
|
614
|
+
scope: "read",
|
|
615
|
+
responseType: "code",
|
|
616
|
+
profile(profile) {
|
|
542
617
|
return {
|
|
543
|
-
|
|
544
|
-
|
|
618
|
+
sub: profile.id.toString(),
|
|
619
|
+
name: `${profile.firstname} ${profile.lastname}`,
|
|
620
|
+
image: profile.profile,
|
|
621
|
+
email: ""
|
|
545
622
|
};
|
|
546
623
|
}
|
|
547
|
-
return config2;
|
|
548
|
-
};
|
|
549
|
-
var createBuiltInOAuthProviders = (oauth = []) => {
|
|
550
|
-
return oauth.reduce((previous, config2) => {
|
|
551
|
-
const oauthConfig = defineOAuthProviderConfig(config2);
|
|
552
|
-
return { ...previous, [oauthConfig.id]: oauthConfig };
|
|
553
|
-
}, {});
|
|
554
624
|
};
|
|
555
625
|
|
|
556
|
-
// src/
|
|
557
|
-
var
|
|
558
|
-
|
|
626
|
+
// src/oauth/mailchimp.ts
|
|
627
|
+
var mailchimp = {
|
|
628
|
+
id: "mailchimp",
|
|
629
|
+
name: "Mailchimp",
|
|
630
|
+
authorizeURL: "https://login.mailchimp.com/oauth2/authorize",
|
|
631
|
+
accessToken: "https://login.mailchimp.com/oauth2/token",
|
|
632
|
+
userInfo: "https://login.mailchimp.com/oauth2/metadata",
|
|
633
|
+
scope: "",
|
|
634
|
+
responseType: "code",
|
|
635
|
+
profile(profile) {
|
|
636
|
+
return {
|
|
637
|
+
sub: profile.user_id,
|
|
638
|
+
name: profile.accountname,
|
|
639
|
+
email: profile.login.login_email,
|
|
640
|
+
image: null
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
};
|
|
559
644
|
|
|
560
|
-
// src/
|
|
561
|
-
var
|
|
562
|
-
|
|
563
|
-
|
|
645
|
+
// src/oauth/pinterest.ts
|
|
646
|
+
var pinterest = {
|
|
647
|
+
id: "pinterest",
|
|
648
|
+
name: "Pinterest",
|
|
649
|
+
authorizeURL: "https://api.pinterest.com/oauth/",
|
|
650
|
+
accessToken: "https://api.pinterest.com/v5/oauth/token",
|
|
651
|
+
userInfo: "https://api.pinterest.com/v5/user_account",
|
|
652
|
+
scope: "user_accounts:read",
|
|
653
|
+
responseType: "code",
|
|
654
|
+
profile(profile) {
|
|
655
|
+
return {
|
|
656
|
+
sub: profile.id,
|
|
657
|
+
name: profile.username,
|
|
658
|
+
email: null,
|
|
659
|
+
image: profile.profile_image
|
|
660
|
+
};
|
|
564
661
|
}
|
|
565
662
|
};
|
|
566
663
|
|
|
567
664
|
// src/schemas.ts
|
|
568
|
-
var
|
|
569
|
-
var OAuthProviderConfigSchema = (0,
|
|
570
|
-
authorizeURL: (0,
|
|
571
|
-
accessToken: (0,
|
|
572
|
-
scope: (0,
|
|
573
|
-
userInfo: (0,
|
|
574
|
-
responseType: (0,
|
|
575
|
-
clientId: (0,
|
|
576
|
-
clientSecret: (0,
|
|
665
|
+
var import_zod = require("zod");
|
|
666
|
+
var OAuthProviderConfigSchema = (0, import_zod.object)({
|
|
667
|
+
authorizeURL: (0, import_zod.string)().url(),
|
|
668
|
+
accessToken: (0, import_zod.string)().url(),
|
|
669
|
+
scope: (0, import_zod.string)().optional(),
|
|
670
|
+
userInfo: (0, import_zod.string)().url(),
|
|
671
|
+
responseType: (0, import_zod.enum)(["code", "token", "id_token"]),
|
|
672
|
+
clientId: (0, import_zod.string)(),
|
|
673
|
+
clientSecret: (0, import_zod.string)()
|
|
577
674
|
});
|
|
578
675
|
var OAuthAuthorization = OAuthProviderConfigSchema.extend({
|
|
579
|
-
redirectURI: (0,
|
|
580
|
-
state: (0,
|
|
581
|
-
codeChallenge: (0,
|
|
582
|
-
codeChallengeMethod: (0,
|
|
676
|
+
redirectURI: (0, import_zod.string)(),
|
|
677
|
+
state: (0, import_zod.string)(),
|
|
678
|
+
codeChallenge: (0, import_zod.string)(),
|
|
679
|
+
codeChallengeMethod: (0, import_zod.enum)(["plain", "S256"])
|
|
583
680
|
});
|
|
584
|
-
var OAuthAuthorizationResponse = (0,
|
|
585
|
-
state: (0,
|
|
586
|
-
code: (0,
|
|
681
|
+
var OAuthAuthorizationResponse = (0, import_zod.object)({
|
|
682
|
+
state: (0, import_zod.string)({ message: "Missing state parameter in the OAuth authorization response." }),
|
|
683
|
+
code: (0, import_zod.string)({ message: "Missing code parameter in the OAuth authorization response." })
|
|
587
684
|
});
|
|
588
|
-
var OAuthAuthorizationErrorResponse = (0,
|
|
589
|
-
error: (0,
|
|
685
|
+
var OAuthAuthorizationErrorResponse = (0, import_zod.object)({
|
|
686
|
+
error: (0, import_zod.enum)([
|
|
590
687
|
"invalid_request",
|
|
591
688
|
"unauthorized_client",
|
|
592
689
|
"access_denied",
|
|
@@ -595,24 +692,24 @@ var OAuthAuthorizationErrorResponse = (0, import_v4.object)({
|
|
|
595
692
|
"server_error",
|
|
596
693
|
"temporarily_unavailable"
|
|
597
694
|
]),
|
|
598
|
-
error_description: (0,
|
|
599
|
-
error_uri: (0,
|
|
600
|
-
state: (0,
|
|
695
|
+
error_description: (0, import_zod.string)().optional(),
|
|
696
|
+
error_uri: (0, import_zod.string)().optional(),
|
|
697
|
+
state: (0, import_zod.string)()
|
|
601
698
|
});
|
|
602
699
|
var OAuthAccessToken = OAuthProviderConfigSchema.extend({
|
|
603
|
-
redirectURI: (0,
|
|
604
|
-
code: (0,
|
|
605
|
-
codeVerifier: (0,
|
|
700
|
+
redirectURI: (0, import_zod.string)(),
|
|
701
|
+
code: (0, import_zod.string)(),
|
|
702
|
+
codeVerifier: (0, import_zod.string)().min(43).max(128)
|
|
606
703
|
});
|
|
607
|
-
var OAuthAccessTokenResponse = (0,
|
|
608
|
-
access_token: (0,
|
|
609
|
-
token_type: (0,
|
|
610
|
-
expires_in: (0,
|
|
611
|
-
refresh_token: (0,
|
|
612
|
-
scope: (0,
|
|
704
|
+
var OAuthAccessTokenResponse = (0, import_zod.object)({
|
|
705
|
+
access_token: (0, import_zod.string)(),
|
|
706
|
+
token_type: (0, import_zod.string)().optional(),
|
|
707
|
+
expires_in: (0, import_zod.number)().optional(),
|
|
708
|
+
refresh_token: (0, import_zod.string)().optional(),
|
|
709
|
+
scope: (0, import_zod.string)().optional().or((0, import_zod.null)())
|
|
613
710
|
});
|
|
614
|
-
var OAuthAccessTokenErrorResponse = (0,
|
|
615
|
-
error: (0,
|
|
711
|
+
var OAuthAccessTokenErrorResponse = (0, import_zod.object)({
|
|
712
|
+
error: (0, import_zod.enum)([
|
|
616
713
|
"invalid_request",
|
|
617
714
|
"invalid_client",
|
|
618
715
|
"invalid_grant",
|
|
@@ -620,19 +717,81 @@ var OAuthAccessTokenErrorResponse = (0, import_v4.object)({
|
|
|
620
717
|
"unsupported_grant_type",
|
|
621
718
|
"invalid_scope"
|
|
622
719
|
]),
|
|
623
|
-
error_description: (0,
|
|
624
|
-
error_uri: (0,
|
|
720
|
+
error_description: (0, import_zod.string)().optional(),
|
|
721
|
+
error_uri: (0, import_zod.string)().optional()
|
|
625
722
|
});
|
|
626
|
-
var OAuthErrorResponse = (0,
|
|
627
|
-
error: (0,
|
|
628
|
-
error_description: (0,
|
|
723
|
+
var OAuthErrorResponse = (0, import_zod.object)({
|
|
724
|
+
error: (0, import_zod.string)(),
|
|
725
|
+
error_description: (0, import_zod.string)().optional()
|
|
629
726
|
});
|
|
727
|
+
var OAuthEnvSchema = (0, import_zod.object)({
|
|
728
|
+
clientId: import_zod.z.string().min(1, "OAuth Client ID is required in the environment variables."),
|
|
729
|
+
clientSecret: import_zod.z.string().min(1, "OAuth Client Secret is required in the environment variables.")
|
|
730
|
+
});
|
|
731
|
+
|
|
732
|
+
// src/oauth/index.ts
|
|
733
|
+
var builtInOAuthProviders = {
|
|
734
|
+
github,
|
|
735
|
+
bitbucket,
|
|
736
|
+
figma,
|
|
737
|
+
discord,
|
|
738
|
+
gitlab,
|
|
739
|
+
spotify,
|
|
740
|
+
x,
|
|
741
|
+
strava,
|
|
742
|
+
mailchimp,
|
|
743
|
+
pinterest
|
|
744
|
+
};
|
|
745
|
+
var defineOAuthEnvironment = (oauth) => {
|
|
746
|
+
const env = process.env;
|
|
747
|
+
const clientIdSuffix = `${oauth.toUpperCase()}_CLIENT_ID`;
|
|
748
|
+
const clientSecretSuffix = `${oauth.toUpperCase()}_CLIENT_SECRET`;
|
|
749
|
+
const loadEnvs = OAuthEnvSchema.safeParse({
|
|
750
|
+
clientId: env[`AURA_AUTH_${clientIdSuffix}`] ?? env[`AUTH_${clientIdSuffix}`] ?? env[`${clientIdSuffix}`],
|
|
751
|
+
clientSecret: env[`AURA_AUTH_${clientSecretSuffix}`] ?? env[`AUTH_${clientSecretSuffix}`] ?? env[`${clientSecretSuffix}`]
|
|
752
|
+
});
|
|
753
|
+
if (!loadEnvs.success) {
|
|
754
|
+
const msg = JSON.stringify(formatZodError(loadEnvs.error), null, 2);
|
|
755
|
+
throw new AuthInternalError("INVALID_ENVIRONMENT_CONFIGURATION", msg);
|
|
756
|
+
}
|
|
757
|
+
return loadEnvs.data;
|
|
758
|
+
};
|
|
759
|
+
var defineOAuthProviderConfig = (config2) => {
|
|
760
|
+
if (typeof config2 === "string") {
|
|
761
|
+
const definition = defineOAuthEnvironment(config2);
|
|
762
|
+
const oauthConfig = builtInOAuthProviders[config2];
|
|
763
|
+
return {
|
|
764
|
+
...oauthConfig,
|
|
765
|
+
...definition
|
|
766
|
+
};
|
|
767
|
+
}
|
|
768
|
+
return config2;
|
|
769
|
+
};
|
|
770
|
+
var createBuiltInOAuthProviders = (oauth = []) => {
|
|
771
|
+
return oauth.reduce((previous, config2) => {
|
|
772
|
+
const oauthConfig = defineOAuthProviderConfig(config2);
|
|
773
|
+
return { ...previous, [oauthConfig.id]: oauthConfig };
|
|
774
|
+
}, {});
|
|
775
|
+
};
|
|
776
|
+
|
|
777
|
+
// src/actions/signIn/signIn.ts
|
|
778
|
+
var import_zod2 = require("zod");
|
|
779
|
+
var import_router2 = require("@aura-stack/router");
|
|
780
|
+
|
|
781
|
+
// src/headers.ts
|
|
782
|
+
var cacheControl = {
|
|
783
|
+
"Cache-Control": "no-store",
|
|
784
|
+
Pragma: "no-cache",
|
|
785
|
+
Expires: "0",
|
|
786
|
+
Vary: "Cookie"
|
|
787
|
+
};
|
|
630
788
|
|
|
631
789
|
// src/actions/signIn/authorization.ts
|
|
632
790
|
var createAuthorizationURL = (oauthConfig, redirectURI, state, codeChallenge, codeChallengeMethod) => {
|
|
633
791
|
const parsed = OAuthAuthorization.safeParse({ ...oauthConfig, redirectURI, state, codeChallenge, codeChallengeMethod });
|
|
634
792
|
if (!parsed.success) {
|
|
635
|
-
|
|
793
|
+
const msg = JSON.stringify(formatZodError(parsed.error), null, 2);
|
|
794
|
+
throw new AuthInternalError("INVALID_OAUTH_CONFIGURATION", msg);
|
|
636
795
|
}
|
|
637
796
|
const { authorizeURL, ...options2 } = parsed.data;
|
|
638
797
|
const { userInfo, accessToken, clientSecret, ...required } = options2;
|
|
@@ -650,8 +809,8 @@ var getOriginURL = (request, trustedProxyHeaders) => {
|
|
|
650
809
|
}
|
|
651
810
|
};
|
|
652
811
|
var createRedirectURI = (request, oauth, basePath, trustedProxyHeaders) => {
|
|
653
|
-
const
|
|
654
|
-
return `${
|
|
812
|
+
const url = getOriginURL(request, trustedProxyHeaders);
|
|
813
|
+
return `${url.origin}${basePath}/callback/${oauth}`;
|
|
655
814
|
};
|
|
656
815
|
var createRedirectTo = (request, redirectTo, trustedProxyHeaders) => {
|
|
657
816
|
try {
|
|
@@ -665,15 +824,18 @@ var createRedirectTo = (request, redirectTo, trustedProxyHeaders) => {
|
|
|
665
824
|
}
|
|
666
825
|
const redirectToURL = new URL(sanitizeURL(getNormalizedOriginPath(redirectTo)));
|
|
667
826
|
if (!isValidURL(redirectTo) || !equals(redirectToURL.origin, hostedURL.origin)) {
|
|
668
|
-
throw new
|
|
827
|
+
throw new AuthSecurityError(
|
|
828
|
+
"POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED",
|
|
829
|
+
"The redirectTo parameter does not match the hosted origin."
|
|
830
|
+
);
|
|
669
831
|
}
|
|
670
832
|
return sanitizeURL(redirectToURL.pathname);
|
|
671
833
|
}
|
|
672
834
|
if (referer) {
|
|
673
835
|
const refererURL = new URL(sanitizeURL(referer));
|
|
674
836
|
if (!isValidURL(referer) || !equals(refererURL.origin, hostedURL.origin)) {
|
|
675
|
-
throw new
|
|
676
|
-
|
|
837
|
+
throw new AuthSecurityError(
|
|
838
|
+
"POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED",
|
|
677
839
|
"The referer of the request does not match the hosted origin."
|
|
678
840
|
);
|
|
679
841
|
}
|
|
@@ -682,16 +844,16 @@ var createRedirectTo = (request, redirectTo, trustedProxyHeaders) => {
|
|
|
682
844
|
if (origin) {
|
|
683
845
|
const originURL = new URL(sanitizeURL(getNormalizedOriginPath(origin)));
|
|
684
846
|
if (!isValidURL(origin) || !equals(originURL.origin, hostedURL.origin)) {
|
|
685
|
-
throw new
|
|
847
|
+
throw new AuthSecurityError("POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED", "Invalid origin (potential CSRF).");
|
|
686
848
|
}
|
|
687
849
|
return sanitizeURL(originURL.pathname);
|
|
688
850
|
}
|
|
689
851
|
return "/";
|
|
690
852
|
} catch (error) {
|
|
691
|
-
if (
|
|
853
|
+
if (isAuthSecurityError(error)) {
|
|
692
854
|
throw error;
|
|
693
855
|
}
|
|
694
|
-
throw new
|
|
856
|
+
throw new AuthSecurityError("POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED", "Invalid origin (potential CSRF).");
|
|
695
857
|
}
|
|
696
858
|
};
|
|
697
859
|
|
|
@@ -699,9 +861,14 @@ var createRedirectTo = (request, redirectTo, trustedProxyHeaders) => {
|
|
|
699
861
|
var signInConfig = (oauth) => {
|
|
700
862
|
return (0, import_router2.createEndpointConfig)("/signIn/:oauth", {
|
|
701
863
|
schemas: {
|
|
702
|
-
params:
|
|
703
|
-
oauth:
|
|
704
|
-
|
|
864
|
+
params: import_zod2.z.object({
|
|
865
|
+
oauth: import_zod2.z.enum(
|
|
866
|
+
Object.keys(oauth),
|
|
867
|
+
"The OAuth provider is not supported or invalid."
|
|
868
|
+
)
|
|
869
|
+
}),
|
|
870
|
+
searchParams: import_zod2.z.object({
|
|
871
|
+
redirectTo: import_zod2.z.string().optional()
|
|
705
872
|
})
|
|
706
873
|
}
|
|
707
874
|
});
|
|
@@ -713,67 +880,41 @@ var signInAction = (oauth) => {
|
|
|
713
880
|
async (ctx) => {
|
|
714
881
|
const {
|
|
715
882
|
request,
|
|
716
|
-
params: { oauth: oauth2
|
|
883
|
+
params: { oauth: oauth2 },
|
|
884
|
+
searchParams: { redirectTo },
|
|
717
885
|
context: { oauth: providers, cookies, trustedProxyHeaders, basePath }
|
|
718
886
|
} = ctx;
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
const { codeVerifier, codeChallenge, method } = await createPKCE();
|
|
731
|
-
const codeVerifierCookie = setCookie("code_verifier", codeVerifier, oauthCookie(cookieOptions));
|
|
732
|
-
const authorization = createAuthorizationURL(providers[oauth2], redirectURI, state, codeChallenge, method);
|
|
733
|
-
const headers = new Headers();
|
|
734
|
-
headers.set("Location", authorization);
|
|
735
|
-
headers.append("Set-Cookie", stateCookie);
|
|
736
|
-
headers.append("Set-Cookie", redirectURICookie);
|
|
737
|
-
headers.append("Set-Cookie", redirectToCookie);
|
|
738
|
-
headers.append("Set-Cookie", codeVerifierCookie);
|
|
739
|
-
return Response.json(
|
|
740
|
-
{ oauth: oauth2 },
|
|
741
|
-
{
|
|
742
|
-
status: 302,
|
|
743
|
-
headers
|
|
744
|
-
}
|
|
745
|
-
);
|
|
746
|
-
} catch (error) {
|
|
747
|
-
if (isAuthError(error)) {
|
|
748
|
-
const { type, message } = error;
|
|
749
|
-
return AuraResponse.json(
|
|
750
|
-
{ error: type, error_description: message },
|
|
751
|
-
{ status: import_router2.statusCode.BAD_REQUEST }
|
|
752
|
-
);
|
|
887
|
+
const state = generateSecure();
|
|
888
|
+
const redirectURI = createRedirectURI(request, oauth2, basePath, trustedProxyHeaders);
|
|
889
|
+
const redirectToValue = createRedirectTo(request, redirectTo, trustedProxyHeaders);
|
|
890
|
+
const { codeVerifier, codeChallenge, method } = await createPKCE();
|
|
891
|
+
const authorization = createAuthorizationURL(providers[oauth2], redirectURI, state, codeChallenge, method);
|
|
892
|
+
const headers = new import_router2.HeadersBuilder(cacheControl).setHeader("Location", authorization).setCookie(cookies.state.name, state, cookies.state.attributes).setCookie(cookies.redirectURI.name, redirectURI, cookies.redirectURI.attributes).setCookie(cookies.redirectTo.name, redirectToValue, cookies.redirectTo.attributes).setCookie(cookies.codeVerifier.name, codeVerifier, cookies.codeVerifier.attributes).toHeaders();
|
|
893
|
+
return Response.json(
|
|
894
|
+
{ oauth: oauth2 },
|
|
895
|
+
{
|
|
896
|
+
status: 302,
|
|
897
|
+
headers
|
|
753
898
|
}
|
|
754
|
-
|
|
755
|
-
{
|
|
756
|
-
error: ERROR_RESPONSE.AUTHORIZATION.SERVER_ERROR,
|
|
757
|
-
error_description: "An unexpected error occurred"
|
|
758
|
-
},
|
|
759
|
-
{ status: import_router2.statusCode.INTERNAL_SERVER_ERROR }
|
|
760
|
-
);
|
|
761
|
-
}
|
|
899
|
+
);
|
|
762
900
|
},
|
|
763
901
|
signInConfig(oauth)
|
|
764
902
|
);
|
|
765
903
|
};
|
|
766
904
|
|
|
767
905
|
// src/actions/callback/callback.ts
|
|
768
|
-
var
|
|
906
|
+
var import_zod3 = require("zod");
|
|
769
907
|
var import_router3 = require("@aura-stack/router");
|
|
770
908
|
|
|
771
|
-
// src/
|
|
772
|
-
var
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
909
|
+
// src/request.ts
|
|
910
|
+
var fetchAsync = async (url, options2 = {}, timeout = 5e3) => {
|
|
911
|
+
const controller = new AbortController();
|
|
912
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
913
|
+
const response = await fetch(url, {
|
|
914
|
+
...options2,
|
|
915
|
+
signal: controller.signal
|
|
916
|
+
}).finally(() => clearTimeout(timeoutId));
|
|
917
|
+
return response;
|
|
777
918
|
};
|
|
778
919
|
|
|
779
920
|
// src/actions/callback/userinfo.ts
|
|
@@ -789,7 +930,7 @@ var getDefaultUserInfo = (profile) => {
|
|
|
789
930
|
var getUserInfo = async (oauthConfig, accessToken) => {
|
|
790
931
|
const userinfoEndpoint = oauthConfig.userInfo;
|
|
791
932
|
try {
|
|
792
|
-
const response = await
|
|
933
|
+
const response = await fetchAsync(userinfoEndpoint, {
|
|
793
934
|
method: "GET",
|
|
794
935
|
headers: {
|
|
795
936
|
Accept: "application/json",
|
|
@@ -799,11 +940,20 @@ var getUserInfo = async (oauthConfig, accessToken) => {
|
|
|
799
940
|
const json = await response.json();
|
|
800
941
|
const { success, data } = OAuthErrorResponse.safeParse(json);
|
|
801
942
|
if (success) {
|
|
802
|
-
throw new
|
|
943
|
+
throw new OAuthProtocolError(
|
|
944
|
+
data.error,
|
|
945
|
+
data?.error_description ?? "An error occurred while fetching user information."
|
|
946
|
+
);
|
|
803
947
|
}
|
|
804
948
|
return oauthConfig?.profile ? oauthConfig.profile(json) : getDefaultUserInfo(json);
|
|
805
949
|
} catch (error) {
|
|
806
|
-
|
|
950
|
+
if (isOAuthProtocolError(error)) {
|
|
951
|
+
throw error;
|
|
952
|
+
}
|
|
953
|
+
if (isNativeError(error)) {
|
|
954
|
+
throw new OAuthProtocolError("invalid_request", error.message, "", { cause: error });
|
|
955
|
+
}
|
|
956
|
+
throw new OAuthProtocolError("invalid_request", "Failed to fetch user information.", "", { cause: error });
|
|
807
957
|
}
|
|
808
958
|
};
|
|
809
959
|
|
|
@@ -811,11 +961,12 @@ var getUserInfo = async (oauthConfig, accessToken) => {
|
|
|
811
961
|
var createAccessToken = async (oauthConfig, redirectURI, code, codeVerifier) => {
|
|
812
962
|
const parsed = OAuthAccessToken.safeParse({ ...oauthConfig, redirectURI, code, codeVerifier });
|
|
813
963
|
if (!parsed.success) {
|
|
814
|
-
|
|
964
|
+
const msg = JSON.stringify(formatZodError(parsed.error), null, 2);
|
|
965
|
+
throw new AuthInternalError("INVALID_OAUTH_CONFIGURATION", msg);
|
|
815
966
|
}
|
|
816
967
|
const { accessToken, clientId, clientSecret, code: codeParsed, redirectURI: redirectParsed } = parsed.data;
|
|
817
968
|
try {
|
|
818
|
-
const response = await
|
|
969
|
+
const response = await fetchAsync(accessToken, {
|
|
819
970
|
method: "POST",
|
|
820
971
|
headers: {
|
|
821
972
|
Accept: "application/json",
|
|
@@ -835,13 +986,13 @@ var createAccessToken = async (oauthConfig, redirectURI, code, codeVerifier) =>
|
|
|
835
986
|
if (!token.success) {
|
|
836
987
|
const { success, data } = OAuthAccessTokenErrorResponse.safeParse(json);
|
|
837
988
|
if (!success) {
|
|
838
|
-
throw new
|
|
989
|
+
throw new OAuthProtocolError("INVALID_REQUEST", "Invalid access token response format");
|
|
839
990
|
}
|
|
840
|
-
throw new
|
|
991
|
+
throw new OAuthProtocolError(data.error, data?.error_description ?? "Failed to retrieve access token");
|
|
841
992
|
}
|
|
842
993
|
return token.data;
|
|
843
994
|
} catch (error) {
|
|
844
|
-
throw
|
|
995
|
+
throw error;
|
|
845
996
|
}
|
|
846
997
|
};
|
|
847
998
|
|
|
@@ -849,9 +1000,15 @@ var createAccessToken = async (oauthConfig, redirectURI, code, codeVerifier) =>
|
|
|
849
1000
|
var callbackConfig = (oauth) => {
|
|
850
1001
|
return (0, import_router3.createEndpointConfig)("/callback/:oauth", {
|
|
851
1002
|
schemas: {
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
1003
|
+
params: import_zod3.z.object({
|
|
1004
|
+
oauth: import_zod3.z.enum(
|
|
1005
|
+
Object.keys(oauth),
|
|
1006
|
+
"The OAuth provider is not supported or invalid."
|
|
1007
|
+
)
|
|
1008
|
+
}),
|
|
1009
|
+
searchParams: import_zod3.z.object({
|
|
1010
|
+
code: import_zod3.z.string("Missing code parameter in the OAuth authorization response."),
|
|
1011
|
+
state: import_zod3.z.string("Missing state parameter in the OAuth authorization response.")
|
|
855
1012
|
})
|
|
856
1013
|
},
|
|
857
1014
|
middlewares: [
|
|
@@ -859,7 +1016,7 @@ var callbackConfig = (oauth) => {
|
|
|
859
1016
|
const response = OAuthAuthorizationErrorResponse.safeParse(ctx.searchParams);
|
|
860
1017
|
if (response.success) {
|
|
861
1018
|
const { error, error_description } = response.data;
|
|
862
|
-
throw new
|
|
1019
|
+
throw new OAuthProtocolError(error, error_description ?? "OAuth Authorization Error");
|
|
863
1020
|
}
|
|
864
1021
|
return ctx;
|
|
865
1022
|
}
|
|
@@ -875,66 +1032,32 @@ var callbackAction = (oauth) => {
|
|
|
875
1032
|
request,
|
|
876
1033
|
params: { oauth: oauth2 },
|
|
877
1034
|
searchParams: { code, state },
|
|
878
|
-
context: { oauth: providers, cookies, jose
|
|
1035
|
+
context: { oauth: providers, cookies, jose }
|
|
879
1036
|
} = ctx;
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
}
|
|
890
|
-
const accessToken = await createAccessToken(oauthConfig, cookieRedirectURI, code, codeVerifier);
|
|
891
|
-
const sanitized = sanitizeURL(cookieRedirectTo);
|
|
892
|
-
if (!isValidRelativePath(sanitized)) {
|
|
893
|
-
throw new AuthError(
|
|
894
|
-
ERROR_RESPONSE.ACCESS_TOKEN.INVALID_REQUEST,
|
|
895
|
-
"Invalid redirect path. Potential open redirect attack detected."
|
|
896
|
-
);
|
|
897
|
-
}
|
|
898
|
-
const headers = new Headers(cacheControl);
|
|
899
|
-
headers.set("Location", sanitized);
|
|
900
|
-
const userInfo = await getUserInfo(oauthConfig, accessToken.access_token);
|
|
901
|
-
const sessionCookie = await createSessionCookie(userInfo, cookieOptions, jose);
|
|
902
|
-
const csrfToken = await createCSRF(jose);
|
|
903
|
-
const csrfCookie = setCookie(
|
|
904
|
-
"csrfToken",
|
|
905
|
-
csrfToken,
|
|
906
|
-
secureCookieOptions(
|
|
907
|
-
request,
|
|
908
|
-
{
|
|
909
|
-
...cookies,
|
|
910
|
-
strategy: "host"
|
|
911
|
-
},
|
|
912
|
-
trustedProxyHeaders
|
|
913
|
-
)
|
|
1037
|
+
const oauthConfig = providers[oauth2];
|
|
1038
|
+
const cookieState = getCookie(request, cookies.state.name);
|
|
1039
|
+
const cookieRedirectTo = getCookie(request, cookies.redirectTo.name);
|
|
1040
|
+
const cookieRedirectURI = getCookie(request, cookies.redirectURI.name);
|
|
1041
|
+
const codeVerifier = getCookie(request, cookies.codeVerifier.name);
|
|
1042
|
+
if (!equals(cookieState, state)) {
|
|
1043
|
+
throw new AuthSecurityError(
|
|
1044
|
+
"MISMATCHING_STATE",
|
|
1045
|
+
"The provided state passed in the OAuth response does not match the stored state."
|
|
914
1046
|
);
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
} catch (error) {
|
|
923
|
-
if (isAuthError(error)) {
|
|
924
|
-
const { type, message } = error;
|
|
925
|
-
return AuraResponse.json(
|
|
926
|
-
{ error: type, error_description: message },
|
|
927
|
-
{ status: import_router3.statusCode.BAD_REQUEST }
|
|
928
|
-
);
|
|
929
|
-
}
|
|
930
|
-
return AuraResponse.json(
|
|
931
|
-
{
|
|
932
|
-
error: ERROR_RESPONSE.ACCESS_TOKEN.INVALID_CLIENT,
|
|
933
|
-
error_description: "An unexpected error occurred"
|
|
934
|
-
},
|
|
935
|
-
{ status: import_router3.statusCode.INTERNAL_SERVER_ERROR }
|
|
1047
|
+
}
|
|
1048
|
+
const accessToken = await createAccessToken(oauthConfig, cookieRedirectURI, code, codeVerifier);
|
|
1049
|
+
const sanitized = sanitizeURL(cookieRedirectTo);
|
|
1050
|
+
if (!isValidRelativePath(sanitized)) {
|
|
1051
|
+
throw new AuthSecurityError(
|
|
1052
|
+
"POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED",
|
|
1053
|
+
"Invalid redirect path. Potential open redirect attack detected."
|
|
936
1054
|
);
|
|
937
1055
|
}
|
|
1056
|
+
const userInfo = await getUserInfo(oauthConfig, accessToken.access_token);
|
|
1057
|
+
const sessionCookie = await createSessionCookie(jose, userInfo);
|
|
1058
|
+
const csrfToken = await createCSRF(jose);
|
|
1059
|
+
const headers = new import_router3.HeadersBuilder(cacheControl).setHeader("Location", sanitized).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();
|
|
1060
|
+
return Response.json({ oauth: oauth2 }, { status: 302, headers });
|
|
938
1061
|
},
|
|
939
1062
|
callbackConfig(oauth)
|
|
940
1063
|
);
|
|
@@ -945,31 +1068,28 @@ var import_router4 = require("@aura-stack/router");
|
|
|
945
1068
|
var sessionAction = (0, import_router4.createEndpoint)("GET", "/session", async (ctx) => {
|
|
946
1069
|
const {
|
|
947
1070
|
request,
|
|
948
|
-
context: {
|
|
1071
|
+
context: { jose, cookies }
|
|
949
1072
|
} = ctx;
|
|
950
|
-
const cookieOptions = secureCookieOptions(request, cookies, trustedProxyHeaders);
|
|
951
1073
|
try {
|
|
952
|
-
const session = getCookie(request,
|
|
1074
|
+
const session = getCookie(request, cookies.sessionToken.name);
|
|
953
1075
|
const decoded = await jose.decodeJWT(session);
|
|
954
1076
|
const { exp, iat, jti, nbf, ...user } = decoded;
|
|
955
1077
|
const headers = new Headers(cacheControl);
|
|
956
1078
|
return Response.json({ user, expires: toISOString(exp * 1e3) }, { headers });
|
|
957
|
-
} catch {
|
|
958
|
-
const headers = new
|
|
959
|
-
const sessionCookie = expireCookie("sessionToken", cookieOptions);
|
|
960
|
-
headers.set("Set-Cookie", sessionCookie);
|
|
1079
|
+
} catch (error) {
|
|
1080
|
+
const headers = new import_router4.HeadersBuilder(cacheControl).setCookie(cookies.sessionToken.name, "", expiredCookieAttributes).toHeaders();
|
|
961
1081
|
return Response.json({ authenticated: false, message: "Unauthorized" }, { status: 401, headers });
|
|
962
1082
|
}
|
|
963
1083
|
});
|
|
964
1084
|
|
|
965
1085
|
// src/actions/signOut/signOut.ts
|
|
966
|
-
var
|
|
1086
|
+
var import_zod4 = require("zod");
|
|
967
1087
|
var import_router5 = require("@aura-stack/router");
|
|
968
1088
|
var config = (0, import_router5.createEndpointConfig)({
|
|
969
1089
|
schemas: {
|
|
970
|
-
searchParams:
|
|
971
|
-
token_type_hint:
|
|
972
|
-
redirectTo:
|
|
1090
|
+
searchParams: import_zod4.z.object({
|
|
1091
|
+
token_type_hint: import_zod4.z.literal("session_token"),
|
|
1092
|
+
redirectTo: import_zod4.z.string().optional()
|
|
973
1093
|
})
|
|
974
1094
|
}
|
|
975
1095
|
});
|
|
@@ -981,98 +1101,78 @@ var signOutAction = (0, import_router5.createEndpoint)(
|
|
|
981
1101
|
request,
|
|
982
1102
|
headers,
|
|
983
1103
|
searchParams: { redirectTo },
|
|
984
|
-
context: {
|
|
1104
|
+
context: { jose, cookies }
|
|
985
1105
|
} = ctx;
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
prefix: cookiesOptions.secure ? "__Host-" : ""
|
|
992
|
-
});
|
|
993
|
-
const header = headers.get("X-CSRF-Token");
|
|
994
|
-
if (!header || !session || !csrfToken) {
|
|
995
|
-
throw new Error("Missing CSRF token or session token");
|
|
996
|
-
}
|
|
997
|
-
await verifyCSRF(jose, csrfToken, header);
|
|
998
|
-
await jose.decodeJWT(session);
|
|
999
|
-
const normalizedOriginPath = getNormalizedOriginPath(request.url);
|
|
1000
|
-
const location = createRedirectTo(
|
|
1001
|
-
new Request(normalizedOriginPath, {
|
|
1002
|
-
headers
|
|
1003
|
-
}),
|
|
1004
|
-
redirectTo
|
|
1005
|
-
);
|
|
1006
|
-
const responseHeaders = new Headers(cacheControl);
|
|
1007
|
-
responseHeaders.append("Set-Cookie", expireCookie("sessionToken", cookiesOptions));
|
|
1008
|
-
responseHeaders.append(
|
|
1009
|
-
"Set-Cookie",
|
|
1010
|
-
expireCookie("csrfToken", { ...cookiesOptions, prefix: cookiesOptions.secure ? "__Host-" : "" })
|
|
1011
|
-
);
|
|
1012
|
-
responseHeaders.append("Location", location);
|
|
1013
|
-
return Response.json(
|
|
1014
|
-
{ message: "Signed out successfully" },
|
|
1015
|
-
{ status: import_router5.statusCode.ACCEPTED, headers: responseHeaders }
|
|
1016
|
-
);
|
|
1017
|
-
} catch (error) {
|
|
1018
|
-
if (error instanceof InvalidCsrfTokenError) {
|
|
1019
|
-
return AuraResponse.json(
|
|
1020
|
-
{
|
|
1021
|
-
error: "invalid_csrf_token",
|
|
1022
|
-
error_description: "The provided CSRF token is invalid or has expired"
|
|
1023
|
-
},
|
|
1024
|
-
{ status: import_router5.statusCode.UNAUTHORIZED }
|
|
1025
|
-
);
|
|
1026
|
-
}
|
|
1027
|
-
if (error instanceof InvalidRedirectToError) {
|
|
1028
|
-
const { type, message } = error;
|
|
1029
|
-
return AuraResponse.json(
|
|
1030
|
-
{
|
|
1031
|
-
error: type,
|
|
1032
|
-
error_description: message
|
|
1033
|
-
},
|
|
1034
|
-
{ status: import_router5.statusCode.BAD_REQUEST }
|
|
1035
|
-
);
|
|
1036
|
-
}
|
|
1037
|
-
return AuraResponse.json(
|
|
1038
|
-
{
|
|
1039
|
-
error: "invalid_session_token",
|
|
1040
|
-
error_description: "The provided sessionToken is invalid or has already expired"
|
|
1041
|
-
},
|
|
1042
|
-
{ status: import_router5.statusCode.UNAUTHORIZED }
|
|
1043
|
-
);
|
|
1106
|
+
const session = headers.getCookie(cookies.sessionToken.name);
|
|
1107
|
+
const csrfToken = headers.getCookie(cookies.csrfToken.name);
|
|
1108
|
+
const header = headers.getHeader("X-CSRF-Token");
|
|
1109
|
+
if (!session) {
|
|
1110
|
+
throw new AuthSecurityError("SESSION_TOKEN_MISSING", "The sessionToken is missing.");
|
|
1044
1111
|
}
|
|
1112
|
+
if (!csrfToken) {
|
|
1113
|
+
throw new AuthSecurityError("CSRF_TOKEN_MISSING", "The CSRF token is missing.");
|
|
1114
|
+
}
|
|
1115
|
+
if (!header) {
|
|
1116
|
+
throw new AuthSecurityError("CSRF_TOKEN_MISSING", "The CSRF header is missing.");
|
|
1117
|
+
}
|
|
1118
|
+
await verifyCSRF(jose, csrfToken, header);
|
|
1119
|
+
await jose.decodeJWT(session);
|
|
1120
|
+
const normalizedOriginPath = getNormalizedOriginPath(request.url);
|
|
1121
|
+
const location = createRedirectTo(
|
|
1122
|
+
new Request(normalizedOriginPath, {
|
|
1123
|
+
headers: headers.toHeaders()
|
|
1124
|
+
}),
|
|
1125
|
+
redirectTo
|
|
1126
|
+
);
|
|
1127
|
+
const headersList = new import_router5.HeadersBuilder(cacheControl).setHeader("Location", location).setCookie(cookies.csrfToken.name, "", expiredCookieAttributes).setCookie(cookies.sessionToken.name, "", expiredCookieAttributes).toHeaders();
|
|
1128
|
+
return Response.json({ message: "Signed out successfully" }, { status: import_router5.statusCode.ACCEPTED, headers: headersList });
|
|
1045
1129
|
},
|
|
1046
1130
|
config
|
|
1047
1131
|
);
|
|
1048
1132
|
|
|
1049
1133
|
// src/actions/csrfToken/csrfToken.ts
|
|
1050
1134
|
var import_router6 = require("@aura-stack/router");
|
|
1135
|
+
var getCSRFToken = (request, cookieName) => {
|
|
1136
|
+
try {
|
|
1137
|
+
return getCookie(request, cookieName);
|
|
1138
|
+
} catch {
|
|
1139
|
+
return void 0;
|
|
1140
|
+
}
|
|
1141
|
+
};
|
|
1051
1142
|
var csrfTokenAction = (0, import_router6.createEndpoint)("GET", "/csrfToken", async (ctx) => {
|
|
1052
1143
|
const {
|
|
1053
1144
|
request,
|
|
1054
|
-
context: {
|
|
1145
|
+
context: { jose, cookies }
|
|
1055
1146
|
} = ctx;
|
|
1056
|
-
const
|
|
1057
|
-
const
|
|
1058
|
-
const csrfToken = await createCSRF(jose, existingCSRFToken);
|
|
1147
|
+
const token = getCSRFToken(request, cookies.csrfToken.name);
|
|
1148
|
+
const csrfToken = await createCSRF(jose, token);
|
|
1059
1149
|
const headers = new Headers(cacheControl);
|
|
1060
|
-
headers.
|
|
1150
|
+
headers.append("Set-Cookie", setCookie(cookies.csrfToken.name, csrfToken, cookies.csrfToken.attributes));
|
|
1061
1151
|
return Response.json({ csrfToken }, { headers });
|
|
1062
1152
|
});
|
|
1063
1153
|
|
|
1064
1154
|
// src/index.ts
|
|
1065
1155
|
var createInternalConfig = (authConfig) => {
|
|
1156
|
+
const useSecure = authConfig?.trustedProxyHeaders ?? false;
|
|
1066
1157
|
return {
|
|
1067
1158
|
basePath: authConfig?.basePath ?? "/auth",
|
|
1068
1159
|
onError: onErrorHandler,
|
|
1069
1160
|
context: {
|
|
1070
1161
|
oauth: createBuiltInOAuthProviders(authConfig?.oauth),
|
|
1071
|
-
cookies: authConfig?.cookies ??
|
|
1162
|
+
cookies: createCookieStore(useSecure, authConfig?.cookies?.prefix, authConfig?.cookies?.overrides ?? {}),
|
|
1072
1163
|
jose: createJoseInstance(authConfig?.secret),
|
|
1164
|
+
secret: authConfig?.secret,
|
|
1073
1165
|
basePath: authConfig?.basePath ?? "/auth",
|
|
1074
|
-
trustedProxyHeaders:
|
|
1075
|
-
}
|
|
1166
|
+
trustedProxyHeaders: useSecure
|
|
1167
|
+
},
|
|
1168
|
+
middlewares: [
|
|
1169
|
+
(ctx) => {
|
|
1170
|
+
const useSecure2 = useSecureCookies(ctx.request, ctx.context.trustedProxyHeaders);
|
|
1171
|
+
const cookies = createCookieStore(useSecure2, authConfig?.cookies?.prefix, authConfig?.cookies?.overrides ?? {});
|
|
1172
|
+
ctx.context.cookies = cookies;
|
|
1173
|
+
return ctx;
|
|
1174
|
+
}
|
|
1175
|
+
]
|
|
1076
1176
|
};
|
|
1077
1177
|
};
|
|
1078
1178
|
var createAuth = (authConfig) => {
|