@aura-stack/auth 0.1.0-rc.8 → 0.1.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.cjs +15 -15
- package/dist/@types/index.d.ts +7 -31
- package/dist/@types/index.js +1 -1
- package/dist/@types/router.d.cjs +1 -1
- package/dist/@types/router.d.d.ts +7 -7
- package/dist/@types/utility.cjs +15 -15
- package/dist/@types/utility.d.ts +6 -6
- package/dist/@types/utility.js +1 -1
- package/dist/actions/callback/access-token.cjs +143 -143
- package/dist/actions/callback/access-token.d.ts +15 -20
- package/dist/actions/callback/access-token.js +8 -4
- package/dist/actions/callback/callback.cjs +437 -455
- package/dist/actions/callback/callback.d.ts +10 -12
- package/dist/actions/callback/callback.js +16 -12
- package/dist/actions/callback/userinfo.cjs +131 -134
- package/dist/actions/callback/userinfo.d.ts +9 -9
- package/dist/actions/callback/userinfo.js +10 -6
- package/dist/actions/csrfToken/csrfToken.cjs +162 -171
- package/dist/actions/csrfToken/csrfToken.d.ts +3 -3
- package/dist/actions/csrfToken/csrfToken.js +12 -8
- package/dist/actions/index.cjs +746 -773
- package/dist/actions/index.d.ts +13 -13
- package/dist/actions/index.js +34 -18
- package/dist/actions/session/session.cjs +149 -155
- package/dist/actions/session/session.d.ts +3 -3
- package/dist/actions/session/session.js +11 -7
- package/dist/actions/signIn/authorization.cjs +231 -249
- package/dist/actions/signIn/authorization.d.ts +12 -18
- package/dist/actions/signIn/authorization.js +16 -6
- package/dist/actions/signIn/signIn.cjs +396 -423
- package/dist/actions/signIn/signIn.d.ts +10 -10
- package/dist/actions/signIn/signIn.js +14 -10
- package/dist/actions/signOut/signOut.cjs +417 -440
- package/dist/actions/signOut/signOut.d.ts +3 -3
- package/dist/actions/signOut/signOut.js +15 -11
- package/dist/assert.cjs +35 -36
- package/dist/assert.d.ts +4 -4
- package/dist/assert.js +10 -2
- package/dist/chunk-256KIVJL.js +85 -96
- package/dist/chunk-42XB3YCW.js +19 -17
- package/dist/chunk-6SM22VVJ.js +13 -10
- package/dist/chunk-CAKJT3KS.js +84 -69
- package/dist/chunk-E3OXBRYF.js +19 -17
- package/dist/chunk-EBPE35JT.js +28 -26
- package/dist/chunk-FIPU4MLT.js +18 -16
- package/dist/chunk-FJUDBLCP.js +50 -43
- package/dist/chunk-FKRDCWBF.js +19 -17
- package/dist/chunk-GZU3RBTB.js +51 -40
- package/dist/chunk-HGJ4TXY4.js +132 -100
- package/dist/chunk-HMRKN75I.js +63 -63
- package/dist/chunk-IKHPGFCW.js +11 -9
- package/dist/chunk-JAPMIE6S.js +7 -5
- package/dist/chunk-KRNOMBXQ.js +19 -17
- package/dist/chunk-LLR722CL.js +91 -70
- package/dist/chunk-RLT4RFKV.js +39 -30
- package/dist/chunk-SJPDVKUS.js +107 -88
- package/dist/chunk-SMQO5WD7.js +26 -16
- package/dist/chunk-STHEPPUZ.js +8 -6
- package/dist/chunk-UJJ7R56J.js +47 -37
- package/dist/chunk-UTDLUEEG.js +27 -21
- package/dist/chunk-VFTYH33W.js +54 -37
- package/dist/chunk-XXJKNKGQ.js +33 -23
- package/dist/chunk-ZV4BH47P.js +132 -134
- package/dist/cookie.cjs +169 -175
- package/dist/cookie.d.ts +23 -51
- package/dist/cookie.js +34 -34
- package/dist/error.cjs +75 -75
- package/dist/error.d.ts +30 -30
- package/dist/error.js +15 -8
- package/dist/headers.cjs +28 -28
- package/dist/headers.d.ts +2 -2
- package/dist/headers.js +6 -2
- package/dist/index-DpfbvTZ_.d.ts +249 -298
- package/dist/index.cjs +936 -969
- package/dist/index.d.ts +10 -31
- package/dist/index.js +70 -50
- package/dist/jose.cjs +61 -64
- package/dist/jose.d.ts +8 -8
- package/dist/jose.js +9 -5
- package/dist/oauth/bitbucket.cjs +38 -38
- package/dist/oauth/bitbucket.d.ts +7 -7
- package/dist/oauth/bitbucket.js +6 -2
- package/dist/oauth/discord.cjs +48 -48
- package/dist/oauth/discord.d.ts +7 -7
- package/dist/oauth/discord.js +6 -2
- package/dist/oauth/figma.cjs +39 -39
- package/dist/oauth/figma.d.ts +7 -7
- package/dist/oauth/figma.js +6 -2
- package/dist/oauth/github.cjs +31 -31
- package/dist/oauth/github.d.ts +7 -7
- package/dist/oauth/github.js +6 -2
- package/dist/oauth/gitlab.cjs +39 -39
- package/dist/oauth/gitlab.d.ts +7 -7
- package/dist/oauth/gitlab.js +6 -2
- package/dist/oauth/index.cjs +180 -180
- package/dist/oauth/index.d.ts +7 -26
- package/dist/oauth/index.js +36 -9
- package/dist/oauth/spotify.cjs +39 -39
- package/dist/oauth/spotify.d.ts +7 -7
- package/dist/oauth/spotify.js +6 -2
- package/dist/oauth/x.cjs +39 -39
- package/dist/oauth/x.d.ts +7 -7
- package/dist/oauth/x.js +6 -2
- package/dist/response.cjs +27 -27
- package/dist/response.d.ts +2 -2
- package/dist/response.js +6 -2
- package/dist/schemas.cjs +91 -91
- package/dist/schemas.d.ts +93 -126
- package/dist/schemas.js +18 -18
- package/dist/secure.cjs +95 -98
- package/dist/secure.d.ts +17 -17
- package/dist/secure.js +18 -4
- package/dist/utils.cjs +119 -132
- package/dist/utils.d.ts +11 -26
- package/dist/utils.js +21 -21
- package/package.json +2 -2
package/dist/actions/index.cjs
CHANGED
|
@@ -1,891 +1,864 @@
|
|
|
1
|
-
"use strict"
|
|
2
|
-
var __create = Object.create
|
|
3
|
-
var __defProp = Object.defineProperty
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
8
|
var __export = (target, all) => {
|
|
9
|
-
|
|
10
|
-
}
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
11
12
|
var __copyProps = (to, from, except, desc) => {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
var __toESM = (mod, isNodeMode, target) => (
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
)
|
|
29
|
-
)
|
|
30
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod)
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
31
29
|
|
|
32
30
|
// src/actions/index.ts
|
|
33
|
-
var actions_exports = {}
|
|
31
|
+
var actions_exports = {};
|
|
34
32
|
__export(actions_exports, {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
})
|
|
41
|
-
module.exports = __toCommonJS(actions_exports)
|
|
33
|
+
callbackAction: () => callbackAction,
|
|
34
|
+
csrfTokenAction: () => csrfTokenAction,
|
|
35
|
+
sessionAction: () => sessionAction,
|
|
36
|
+
signInAction: () => signInAction,
|
|
37
|
+
signOutAction: () => signOutAction
|
|
38
|
+
});
|
|
39
|
+
module.exports = __toCommonJS(actions_exports);
|
|
42
40
|
|
|
43
41
|
// src/actions/signIn/signIn.ts
|
|
44
|
-
var import_zod = __toESM(require("zod"), 1)
|
|
45
|
-
var import_router2 = require("@aura-stack/router")
|
|
42
|
+
var import_zod = __toESM(require("zod"), 1);
|
|
43
|
+
var import_router2 = require("@aura-stack/router");
|
|
46
44
|
|
|
47
45
|
// src/response.ts
|
|
48
46
|
var AuraResponse = class extends Response {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
47
|
+
static json(body, init) {
|
|
48
|
+
return Response.json(body, init);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
53
51
|
|
|
54
52
|
// src/secure.ts
|
|
55
|
-
var import_node_crypto = __toESM(require("crypto"), 1)
|
|
53
|
+
var import_node_crypto = __toESM(require("crypto"), 1);
|
|
56
54
|
|
|
57
55
|
// src/utils.ts
|
|
58
|
-
var import_router = require("@aura-stack/router")
|
|
56
|
+
var import_router = require("@aura-stack/router");
|
|
59
57
|
|
|
60
58
|
// src/error.ts
|
|
61
59
|
var AuthError = class extends Error {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
60
|
+
constructor(type, message) {
|
|
61
|
+
super(message);
|
|
62
|
+
this.type = type;
|
|
63
|
+
this.name = "AuthError";
|
|
64
|
+
}
|
|
65
|
+
};
|
|
68
66
|
var InvalidCsrfTokenError = class extends AuthError {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
67
|
+
constructor(message = "The provided CSRF token is invalid or has expired") {
|
|
68
|
+
super("invalid_csrf_token", message);
|
|
69
|
+
this.name = "InvalidCsrfTokenError";
|
|
70
|
+
}
|
|
71
|
+
};
|
|
74
72
|
var InvalidRedirectToError = class extends AuthError {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
73
|
+
constructor(message = "The redirectTo parameter does not match the hosted origin.") {
|
|
74
|
+
super("invalid_redirect_to", message);
|
|
75
|
+
this.name = "InvalidRedirectToError";
|
|
76
|
+
}
|
|
77
|
+
};
|
|
80
78
|
var isAuthError = (error) => {
|
|
81
|
-
|
|
82
|
-
}
|
|
79
|
+
return error instanceof AuthError;
|
|
80
|
+
};
|
|
83
81
|
var throwAuthError = (error, message) => {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
throw new AuthError("invalid_request", error.message ?? message)
|
|
82
|
+
if (error instanceof Error) {
|
|
83
|
+
if (isAuthError(error)) {
|
|
84
|
+
throw error;
|
|
89
85
|
}
|
|
90
|
-
|
|
86
|
+
throw new AuthError("invalid_request", error.message ?? message);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
91
89
|
var ERROR_RESPONSE = {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
90
|
+
AUTHORIZATION: {
|
|
91
|
+
INVALID_REQUEST: "invalid_request",
|
|
92
|
+
UNAUTHORIZED_CLIENT: "unauthorized_client",
|
|
93
|
+
ACCESS_DENIED: "access_denied",
|
|
94
|
+
UNSUPPORTED_RESPONSE_TYPE: "unsupported_response_type",
|
|
95
|
+
INVALID_SCOPE: "invalid_scope",
|
|
96
|
+
SERVER_ERROR: "server_error",
|
|
97
|
+
TEMPORARILY_UNAVAILABLE: "temporarily_unavailable"
|
|
98
|
+
},
|
|
99
|
+
ACCESS_TOKEN: {
|
|
100
|
+
INVALID_REQUEST: "invalid_request",
|
|
101
|
+
INVALID_CLIENT: "invalid_client",
|
|
102
|
+
INVALID_GRANT: "invalid_grant",
|
|
103
|
+
UNAUTHORIZED_CLIENT: "unauthorized_client",
|
|
104
|
+
UNSUPPORTED_GRANT_TYPE: "unsupported_grant_type",
|
|
105
|
+
INVALID_SCOPE: "invalid_scope"
|
|
106
|
+
}
|
|
107
|
+
};
|
|
110
108
|
|
|
111
109
|
// src/utils.ts
|
|
112
110
|
var toSnakeCase = (str) => {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
.replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2")
|
|
116
|
-
.toLowerCase()
|
|
117
|
-
.replace(/^_+/, "")
|
|
118
|
-
}
|
|
111
|
+
return str.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2").toLowerCase().replace(/^_+/, "");
|
|
112
|
+
};
|
|
119
113
|
var toUpperCase = (str) => {
|
|
120
|
-
|
|
121
|
-
}
|
|
114
|
+
return str.toUpperCase();
|
|
115
|
+
};
|
|
122
116
|
var toCastCase = (obj, type = "snake") => {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
117
|
+
return Object.entries(obj).reduce((previous, [key, value]) => {
|
|
118
|
+
const newKey = type === "snake" ? toSnakeCase(key) : toUpperCase(key);
|
|
119
|
+
return { ...previous, [newKey]: value };
|
|
120
|
+
}, {});
|
|
121
|
+
};
|
|
128
122
|
var equals = (a, b) => {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
123
|
+
if (a === null || b === null || a === void 0 || b === void 0) return false;
|
|
124
|
+
return a === b;
|
|
125
|
+
};
|
|
132
126
|
var sanitizeURL = (url2) => {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
let sanitized = decodedURL
|
|
160
|
-
.replace(/\/\.\.\//g, "/")
|
|
161
|
-
.replace(/\/\.\.$/, "")
|
|
162
|
-
.replace(/\.{2,}/g, "")
|
|
163
|
-
.replace(/\/{2,}/g, "/")
|
|
164
|
-
if (sanitized !== "/" && sanitized.endsWith("/")) {
|
|
165
|
-
sanitized = sanitized.replace(/\/+$/, "/")
|
|
166
|
-
} else if (sanitized !== "/") {
|
|
167
|
-
sanitized = sanitized.replace(/\/+$/, "")
|
|
168
|
-
}
|
|
169
|
-
return sanitized
|
|
170
|
-
} catch {
|
|
171
|
-
return url2.trim()
|
|
127
|
+
try {
|
|
128
|
+
let decodedURL = decodeURIComponent(url2).trim();
|
|
129
|
+
const protocolMatch = decodedURL.match(/^([a-zA-Z][a-zA-Z0-9+.-]*:\/\/)/);
|
|
130
|
+
let protocol = "";
|
|
131
|
+
let rest = decodedURL;
|
|
132
|
+
if (protocolMatch) {
|
|
133
|
+
protocol = protocolMatch[1];
|
|
134
|
+
rest = decodedURL.slice(protocol.length);
|
|
135
|
+
const slashIndex = rest.indexOf("/");
|
|
136
|
+
if (slashIndex === -1) {
|
|
137
|
+
return protocol + rest;
|
|
138
|
+
}
|
|
139
|
+
const domain = rest.slice(0, slashIndex);
|
|
140
|
+
let path = rest.slice(slashIndex).replace(/\/\.\.\//g, "/").replace(/\/\.\.$/, "").replace(/\.{2,}/g, "").replace(/\/{2,}/g, "/");
|
|
141
|
+
if (path !== "/" && path.endsWith("/")) {
|
|
142
|
+
path = path.replace(/\/+$/, "/");
|
|
143
|
+
} else if (path !== "/") {
|
|
144
|
+
path = path.replace(/\/+$/, "");
|
|
145
|
+
}
|
|
146
|
+
return protocol + domain + path;
|
|
147
|
+
}
|
|
148
|
+
let sanitized = decodedURL.replace(/\/\.\.\//g, "/").replace(/\/\.\.$/, "").replace(/\.{2,}/g, "").replace(/\/{2,}/g, "/");
|
|
149
|
+
if (sanitized !== "/" && sanitized.endsWith("/")) {
|
|
150
|
+
sanitized = sanitized.replace(/\/+$/, "/");
|
|
151
|
+
} else if (sanitized !== "/") {
|
|
152
|
+
sanitized = sanitized.replace(/\/+$/, "");
|
|
172
153
|
}
|
|
173
|
-
|
|
154
|
+
return sanitized;
|
|
155
|
+
} catch {
|
|
156
|
+
return url2.trim();
|
|
157
|
+
}
|
|
158
|
+
};
|
|
174
159
|
var isValidRelativePath = (path) => {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
}
|
|
160
|
+
if (!path || typeof path !== "string") return false;
|
|
161
|
+
if (!path.startsWith("/") || path.includes("://") || path.includes("\r") || path.includes("\n")) return false;
|
|
162
|
+
if (/[\x00-\x1F\x7F]/.test(path) || path.includes("\0")) return false;
|
|
163
|
+
const sanitized = sanitizeURL(path);
|
|
164
|
+
if (sanitized.includes("..")) return false;
|
|
165
|
+
return true;
|
|
166
|
+
};
|
|
182
167
|
var getNormalizedOriginPath = (path) => {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
}
|
|
168
|
+
try {
|
|
169
|
+
const url2 = new URL(path);
|
|
170
|
+
url2.hash = "";
|
|
171
|
+
url2.search = "";
|
|
172
|
+
return `${url2.origin}${url2.pathname}`;
|
|
173
|
+
} catch {
|
|
174
|
+
return sanitizeURL(path);
|
|
175
|
+
}
|
|
176
|
+
};
|
|
192
177
|
var toISOString = (date) => {
|
|
193
|
-
|
|
194
|
-
}
|
|
178
|
+
return new Date(date).toISOString();
|
|
179
|
+
};
|
|
195
180
|
|
|
196
181
|
// src/secure.ts
|
|
197
182
|
var generateSecure = (length = 32) => {
|
|
198
|
-
|
|
199
|
-
}
|
|
183
|
+
return import_node_crypto.default.randomBytes(length).toString("base64url");
|
|
184
|
+
};
|
|
200
185
|
var createHash = (data, base = "hex") => {
|
|
201
|
-
|
|
202
|
-
}
|
|
186
|
+
return import_node_crypto.default.createHash("sha256").update(data).digest().toString(base);
|
|
187
|
+
};
|
|
203
188
|
var createPKCE = async (verifier) => {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
}
|
|
189
|
+
const codeVerifier = verifier ?? generateSecure(86);
|
|
190
|
+
const codeChallenge = createHash(codeVerifier, "base64url");
|
|
191
|
+
return { codeVerifier, codeChallenge, method: "S256" };
|
|
192
|
+
};
|
|
208
193
|
var createCSRF = async (jose, csrfCookie) => {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
}
|
|
215
|
-
return jose.signJWS({ token })
|
|
216
|
-
} catch {
|
|
217
|
-
const token = generateSecure(32)
|
|
218
|
-
return jose.signJWS({ token })
|
|
194
|
+
try {
|
|
195
|
+
const token = generateSecure(32);
|
|
196
|
+
if (csrfCookie) {
|
|
197
|
+
await jose.verifyJWS(csrfCookie);
|
|
198
|
+
return csrfCookie;
|
|
219
199
|
}
|
|
220
|
-
}
|
|
200
|
+
return jose.signJWS({ token });
|
|
201
|
+
} catch {
|
|
202
|
+
const token = generateSecure(32);
|
|
203
|
+
return jose.signJWS({ token });
|
|
204
|
+
}
|
|
205
|
+
};
|
|
221
206
|
var verifyCSRF = async (jose, cookie, header) => {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
}
|
|
233
|
-
return true
|
|
234
|
-
} catch {
|
|
235
|
-
throw new InvalidCsrfTokenError()
|
|
207
|
+
try {
|
|
208
|
+
const { token: cookieToken } = await jose.verifyJWS(cookie);
|
|
209
|
+
const { token: headerToken } = await jose.verifyJWS(header);
|
|
210
|
+
const cookieBuffer = Buffer.from(cookieToken);
|
|
211
|
+
const headerBuffer = Buffer.from(headerToken);
|
|
212
|
+
if (!equals(headerBuffer.length, cookieBuffer.length)) {
|
|
213
|
+
throw new InvalidCsrfTokenError();
|
|
214
|
+
}
|
|
215
|
+
if (!import_node_crypto.default.timingSafeEqual(cookieBuffer, headerBuffer)) {
|
|
216
|
+
throw new InvalidCsrfTokenError();
|
|
236
217
|
}
|
|
237
|
-
|
|
218
|
+
return true;
|
|
219
|
+
} catch {
|
|
220
|
+
throw new InvalidCsrfTokenError();
|
|
221
|
+
}
|
|
222
|
+
};
|
|
238
223
|
|
|
239
224
|
// src/cookie.ts
|
|
240
|
-
var import_cookie = require("cookie")
|
|
225
|
+
var import_cookie = require("cookie");
|
|
241
226
|
|
|
242
227
|
// src/assert.ts
|
|
243
228
|
var isRequest = (value) => {
|
|
244
|
-
|
|
245
|
-
}
|
|
229
|
+
return typeof Request !== "undefined" && value instanceof Request;
|
|
230
|
+
};
|
|
246
231
|
var isValidURL = (value) => {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
}
|
|
232
|
+
if (value.includes("\r\n") || value.includes("\n") || value.includes("\r")) return false;
|
|
233
|
+
const regex = /^https?:\/\/(?:[a-zA-Z0-9._-]+|localhost|\[[0-9a-fA-F:]+\])(?::\d{1,5})?(?:\/[a-zA-Z0-9._~!$&'()*+,;=:@-]*)*\/?$/;
|
|
234
|
+
return regex.test(value);
|
|
235
|
+
};
|
|
252
236
|
|
|
253
237
|
// src/cookie.ts
|
|
254
|
-
var import_cookie2 = require("cookie")
|
|
255
|
-
var COOKIE_NAME = "aura-auth"
|
|
238
|
+
var import_cookie2 = require("cookie");
|
|
239
|
+
var COOKIE_NAME = "aura-auth";
|
|
256
240
|
var defaultCookieOptions = {
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
}
|
|
241
|
+
httpOnly: true,
|
|
242
|
+
sameSite: "lax",
|
|
243
|
+
path: "/",
|
|
244
|
+
maxAge: 60 * 60 * 24 * 15
|
|
245
|
+
};
|
|
262
246
|
var defaultStandardCookieConfig = {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
}
|
|
247
|
+
secure: false,
|
|
248
|
+
httpOnly: true,
|
|
249
|
+
prefix: ""
|
|
250
|
+
};
|
|
267
251
|
var defaultSecureCookieConfig = {
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
}
|
|
252
|
+
secure: true,
|
|
253
|
+
prefix: "__Secure-"
|
|
254
|
+
};
|
|
271
255
|
var defaultHostCookieConfig = {
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
}
|
|
256
|
+
secure: true,
|
|
257
|
+
prefix: "__Host-",
|
|
258
|
+
path: "/",
|
|
259
|
+
domain: void 0
|
|
260
|
+
};
|
|
277
261
|
var expiredCookieOptions = {
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
}
|
|
262
|
+
...defaultCookieOptions,
|
|
263
|
+
expires: /* @__PURE__ */ new Date(0),
|
|
264
|
+
maxAge: 0
|
|
265
|
+
};
|
|
282
266
|
var defineDefaultCookieOptions = (options2) => {
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
}
|
|
267
|
+
return {
|
|
268
|
+
name: options2?.name ?? COOKIE_NAME,
|
|
269
|
+
prefix: options2?.prefix ?? (options2?.secure ? "__Secure-" : ""),
|
|
270
|
+
...defaultCookieOptions,
|
|
271
|
+
...options2
|
|
272
|
+
};
|
|
273
|
+
};
|
|
290
274
|
var setCookie = (cookieName, value, options2) => {
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
}
|
|
275
|
+
const { prefix, name } = defineDefaultCookieOptions(options2);
|
|
276
|
+
const cookieNameWithPrefix = `${prefix}${name}.${cookieName}`;
|
|
277
|
+
return (0, import_cookie.serialize)(cookieNameWithPrefix, value, {
|
|
278
|
+
...defaultCookieOptions,
|
|
279
|
+
...options2
|
|
280
|
+
});
|
|
281
|
+
};
|
|
298
282
|
var getCookie = (petition, cookie, options2, optional = false) => {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
}
|
|
304
|
-
throw new AuthError("invalid_request", "No cookies found. There is no active session")
|
|
283
|
+
const cookies = isRequest(petition) ? petition.headers.get("Cookie") : petition.headers.getSetCookie().join("; ");
|
|
284
|
+
if (!cookies) {
|
|
285
|
+
if (optional) {
|
|
286
|
+
return "";
|
|
305
287
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
288
|
+
throw new AuthError("invalid_request", "No cookies found. There is no active session");
|
|
289
|
+
}
|
|
290
|
+
const { name, prefix } = defineDefaultCookieOptions(options2);
|
|
291
|
+
const parsedCookies = (0, import_cookie.parse)(cookies);
|
|
292
|
+
const value = parsedCookies[`${prefix}${name}.${cookie}`];
|
|
293
|
+
if (value === void 0) {
|
|
294
|
+
if (optional) {
|
|
295
|
+
return "";
|
|
314
296
|
}
|
|
315
|
-
|
|
316
|
-
}
|
|
297
|
+
throw new AuthError("invalid_request", `Cookie "${cookie}" not found. There is no active session`);
|
|
298
|
+
}
|
|
299
|
+
return value;
|
|
300
|
+
};
|
|
317
301
|
var createSessionCookie = async (session, cookieOptions, jose) => {
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
}
|
|
302
|
+
try {
|
|
303
|
+
const encoded = await jose.encodeJWT(session);
|
|
304
|
+
return setCookie("sessionToken", encoded, cookieOptions);
|
|
305
|
+
} catch (error) {
|
|
306
|
+
throw new AuthError("server_error", "Failed to create session cookie", { cause: error });
|
|
307
|
+
}
|
|
308
|
+
};
|
|
325
309
|
var secureCookieOptions = (request, cookieOptions, trustedProxyHeaders) => {
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
310
|
+
const name = cookieOptions.name ?? COOKIE_NAME;
|
|
311
|
+
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://");
|
|
312
|
+
if (!cookieOptions.options?.httpOnly) {
|
|
313
|
+
console.warn(
|
|
314
|
+
"[WARNING]: Cookie is configured without HttpOnly. This allows JavaScript access via document.cookie and increases XSS risk."
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
if (cookieOptions.options?.domain === "*") {
|
|
318
|
+
console.warn("[WARNING]: Cookie 'Domain' is set to '*', which is insecure. Avoid wildcard domains.");
|
|
319
|
+
}
|
|
320
|
+
if (!isSecure) {
|
|
321
|
+
const options2 = cookieOptions.options;
|
|
322
|
+
if (options2?.secure) {
|
|
323
|
+
console.warn(
|
|
324
|
+
"[WARNING]: The 'Secure' attribute will be disabled for this cookie. Serve over HTTPS to enforce Secure cookies."
|
|
325
|
+
);
|
|
336
326
|
}
|
|
337
|
-
if (
|
|
338
|
-
|
|
327
|
+
if (options2?.sameSite == "none") {
|
|
328
|
+
console.warn("[WARNING]: SameSite=None without a secure connection can be blocked by browsers.");
|
|
339
329
|
}
|
|
340
|
-
if (
|
|
341
|
-
|
|
342
|
-
if (options2?.secure) {
|
|
343
|
-
console.warn(
|
|
344
|
-
"[WARNING]: The 'Secure' attribute will be disabled for this cookie. Serve over HTTPS to enforce Secure cookies."
|
|
345
|
-
)
|
|
346
|
-
}
|
|
347
|
-
if (options2?.sameSite == "none") {
|
|
348
|
-
console.warn("[WARNING]: SameSite=None without a secure connection can be blocked by browsers.")
|
|
349
|
-
}
|
|
350
|
-
if (process.env.NODE_ENV === "production") {
|
|
351
|
-
console.warn("[WARNING]: In production, ensure cookies are served over HTTPS to maintain security.")
|
|
352
|
-
}
|
|
353
|
-
return {
|
|
354
|
-
...defaultCookieOptions,
|
|
355
|
-
...cookieOptions.options,
|
|
356
|
-
sameSite: options2?.sameSite === "none" ? "lax" : (options2?.sameSite ?? "lax"),
|
|
357
|
-
...defaultStandardCookieConfig,
|
|
358
|
-
name,
|
|
359
|
-
}
|
|
330
|
+
if (process.env.NODE_ENV === "production") {
|
|
331
|
+
console.warn("[WARNING]: In production, ensure cookies are served over HTTPS to maintain security.");
|
|
360
332
|
}
|
|
361
|
-
return
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
333
|
+
return {
|
|
334
|
+
...defaultCookieOptions,
|
|
335
|
+
...cookieOptions.options,
|
|
336
|
+
sameSite: options2?.sameSite === "none" ? "lax" : options2?.sameSite ?? "lax",
|
|
337
|
+
...defaultStandardCookieConfig,
|
|
338
|
+
name
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
return cookieOptions.strategy === "host" ? {
|
|
342
|
+
...defaultCookieOptions,
|
|
343
|
+
...cookieOptions.options,
|
|
344
|
+
...defaultHostCookieConfig,
|
|
345
|
+
name
|
|
346
|
+
} : { ...defaultCookieOptions, ...cookieOptions.options, ...defaultSecureCookieConfig, name };
|
|
347
|
+
};
|
|
370
348
|
var expireCookie = (name, options2) => {
|
|
371
|
-
|
|
372
|
-
}
|
|
349
|
+
return setCookie(name, "", { ...options2, ...expiredCookieOptions });
|
|
350
|
+
};
|
|
373
351
|
var oauthCookie = (options2) => {
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
}
|
|
352
|
+
return {
|
|
353
|
+
...options2,
|
|
354
|
+
secure: options2.secure,
|
|
355
|
+
httpOnly: options2.httpOnly,
|
|
356
|
+
maxAge: 5 * 60,
|
|
357
|
+
expires: new Date(Date.now() + 5 * 60 * 1e3)
|
|
358
|
+
};
|
|
359
|
+
};
|
|
382
360
|
|
|
383
361
|
// src/schemas.ts
|
|
384
|
-
var import_v4 = require("zod/v4")
|
|
362
|
+
var import_v4 = require("zod/v4");
|
|
385
363
|
var OAuthProviderConfigSchema = (0, import_v4.object)({
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
})
|
|
364
|
+
authorizeURL: (0, import_v4.url)(),
|
|
365
|
+
accessToken: (0, import_v4.url)(),
|
|
366
|
+
scope: (0, import_v4.string)().optional(),
|
|
367
|
+
userInfo: (0, import_v4.url)(),
|
|
368
|
+
responseType: (0, import_v4.enum)(["code", "token", "id_token"]),
|
|
369
|
+
clientId: (0, import_v4.string)(),
|
|
370
|
+
clientSecret: (0, import_v4.string)()
|
|
371
|
+
});
|
|
394
372
|
var OAuthAuthorization = OAuthProviderConfigSchema.extend({
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
})
|
|
373
|
+
redirectURI: (0, import_v4.string)(),
|
|
374
|
+
state: (0, import_v4.string)(),
|
|
375
|
+
codeChallenge: (0, import_v4.string)(),
|
|
376
|
+
codeChallengeMethod: (0, import_v4.enum)(["plain", "S256"])
|
|
377
|
+
});
|
|
400
378
|
var OAuthAuthorizationResponse = (0, import_v4.object)({
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
})
|
|
379
|
+
state: (0, import_v4.string)(),
|
|
380
|
+
code: (0, import_v4.string)()
|
|
381
|
+
});
|
|
404
382
|
var OAuthAuthorizationErrorResponse = (0, import_v4.object)({
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
})
|
|
383
|
+
error: (0, import_v4.enum)([
|
|
384
|
+
"invalid_request",
|
|
385
|
+
"unauthorized_client",
|
|
386
|
+
"access_denied",
|
|
387
|
+
"unsupported_response_type",
|
|
388
|
+
"invalid_scope",
|
|
389
|
+
"server_error",
|
|
390
|
+
"temporarily_unavailable"
|
|
391
|
+
]),
|
|
392
|
+
error_description: (0, import_v4.string)().optional(),
|
|
393
|
+
error_uri: (0, import_v4.string)().optional(),
|
|
394
|
+
state: (0, import_v4.string)()
|
|
395
|
+
});
|
|
418
396
|
var OAuthAccessToken = OAuthProviderConfigSchema.extend({
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
})
|
|
397
|
+
redirectURI: (0, import_v4.string)(),
|
|
398
|
+
code: (0, import_v4.string)(),
|
|
399
|
+
codeVerifier: (0, import_v4.string)().min(43).max(128)
|
|
400
|
+
});
|
|
423
401
|
var OAuthAccessTokenResponse = (0, import_v4.object)({
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
})
|
|
402
|
+
access_token: (0, import_v4.string)(),
|
|
403
|
+
token_type: (0, import_v4.string)(),
|
|
404
|
+
expires_in: (0, import_v4.number)().optional(),
|
|
405
|
+
refresh_token: (0, import_v4.string)().optional(),
|
|
406
|
+
scope: (0, import_v4.string)().optional()
|
|
407
|
+
});
|
|
430
408
|
var OAuthAccessTokenErrorResponse = (0, import_v4.object)({
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
})
|
|
409
|
+
error: (0, import_v4.enum)([
|
|
410
|
+
"invalid_request",
|
|
411
|
+
"invalid_client",
|
|
412
|
+
"invalid_grant",
|
|
413
|
+
"unauthorized_client",
|
|
414
|
+
"unsupported_grant_type",
|
|
415
|
+
"invalid_scope"
|
|
416
|
+
]),
|
|
417
|
+
error_description: (0, import_v4.string)().optional(),
|
|
418
|
+
error_uri: (0, import_v4.string)().optional()
|
|
419
|
+
});
|
|
442
420
|
var OAuthErrorResponse = (0, import_v4.object)({
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
})
|
|
421
|
+
error: (0, import_v4.string)(),
|
|
422
|
+
error_description: (0, import_v4.string)().optional()
|
|
423
|
+
});
|
|
446
424
|
|
|
447
425
|
// src/actions/signIn/authorization.ts
|
|
448
426
|
var createAuthorizationURL = (oauthConfig, redirectURI, state, codeChallenge, codeChallengeMethod) => {
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
}
|
|
427
|
+
const parsed = OAuthAuthorization.safeParse({ ...oauthConfig, redirectURI, state, codeChallenge, codeChallengeMethod });
|
|
428
|
+
if (!parsed.success) {
|
|
429
|
+
throw new AuthError(ERROR_RESPONSE.AUTHORIZATION.SERVER_ERROR, "Invalid OAuth configuration");
|
|
430
|
+
}
|
|
431
|
+
const { authorizeURL, ...options2 } = parsed.data;
|
|
432
|
+
const { userInfo, accessToken, clientSecret, ...required } = options2;
|
|
433
|
+
const searchParams = new URLSearchParams(toCastCase(required));
|
|
434
|
+
return `${authorizeURL}?${searchParams}`;
|
|
435
|
+
};
|
|
458
436
|
var getOriginURL = (request, trustedProxyHeaders) => {
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
} else {
|
|
469
|
-
return new URL(getNormalizedOriginPath(request.url))
|
|
470
|
-
}
|
|
471
|
-
}
|
|
437
|
+
const headers = request.headers;
|
|
438
|
+
if (trustedProxyHeaders) {
|
|
439
|
+
const protocol = headers.get("X-Forwarded-Proto") ?? headers.get("Forwarded")?.match(/proto=([^;]+)/i)?.[1] ?? "http";
|
|
440
|
+
const host = headers.get("X-Forwarded-Host") ?? headers.get("Host") ?? headers.get("Forwarded")?.match(/host=([^;]+)/i)?.[1] ?? null;
|
|
441
|
+
return new URL(`${protocol}://${host}${getNormalizedOriginPath(new URL(request.url).pathname)}`);
|
|
442
|
+
} else {
|
|
443
|
+
return new URL(getNormalizedOriginPath(request.url));
|
|
444
|
+
}
|
|
445
|
+
};
|
|
472
446
|
var createRedirectURI = (request, oauth, basePath, trustedProxyHeaders) => {
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
}
|
|
447
|
+
const url2 = getOriginURL(request, trustedProxyHeaders);
|
|
448
|
+
return `${url2.origin}${basePath}/callback/${oauth}`;
|
|
449
|
+
};
|
|
476
450
|
var createRedirectTo = (request, redirectTo, trustedProxyHeaders) => {
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
}
|
|
514
|
-
throw new AuthError(ERROR_RESPONSE.AUTHORIZATION.INVALID_REQUEST, "Invalid origin (potential CSRF).")
|
|
451
|
+
try {
|
|
452
|
+
const headers = request.headers;
|
|
453
|
+
const origin = headers.get("Origin");
|
|
454
|
+
const referer = headers.get("Referer");
|
|
455
|
+
let hostedURL = getOriginURL(request, trustedProxyHeaders);
|
|
456
|
+
if (redirectTo) {
|
|
457
|
+
if (redirectTo.startsWith("/")) {
|
|
458
|
+
return sanitizeURL(redirectTo);
|
|
459
|
+
}
|
|
460
|
+
const redirectToURL = new URL(sanitizeURL(getNormalizedOriginPath(redirectTo)));
|
|
461
|
+
if (!isValidURL(redirectTo) || !equals(redirectToURL.origin, hostedURL.origin)) {
|
|
462
|
+
throw new InvalidRedirectToError();
|
|
463
|
+
}
|
|
464
|
+
return sanitizeURL(redirectToURL.pathname);
|
|
465
|
+
}
|
|
466
|
+
if (referer) {
|
|
467
|
+
const refererURL = new URL(sanitizeURL(referer));
|
|
468
|
+
if (!isValidURL(referer) || !equals(refererURL.origin, hostedURL.origin)) {
|
|
469
|
+
throw new AuthError(
|
|
470
|
+
ERROR_RESPONSE.AUTHORIZATION.INVALID_REQUEST,
|
|
471
|
+
"The referer of the request does not match the hosted origin."
|
|
472
|
+
);
|
|
473
|
+
}
|
|
474
|
+
return sanitizeURL(refererURL.pathname);
|
|
475
|
+
}
|
|
476
|
+
if (origin) {
|
|
477
|
+
const originURL = new URL(sanitizeURL(getNormalizedOriginPath(origin)));
|
|
478
|
+
if (!isValidURL(origin) || !equals(originURL.origin, hostedURL.origin)) {
|
|
479
|
+
throw new AuthError(ERROR_RESPONSE.AUTHORIZATION.INVALID_REQUEST, "Invalid origin (potential CSRF).");
|
|
480
|
+
}
|
|
481
|
+
return sanitizeURL(originURL.pathname);
|
|
482
|
+
}
|
|
483
|
+
return "/";
|
|
484
|
+
} catch (error) {
|
|
485
|
+
if (isAuthError(error)) {
|
|
486
|
+
throw error;
|
|
515
487
|
}
|
|
516
|
-
|
|
488
|
+
throw new AuthError(ERROR_RESPONSE.AUTHORIZATION.INVALID_REQUEST, "Invalid origin (potential CSRF).");
|
|
489
|
+
}
|
|
490
|
+
};
|
|
517
491
|
|
|
518
492
|
// src/actions/signIn/signIn.ts
|
|
519
493
|
var signInConfig = (oauth) => {
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
}
|
|
494
|
+
return (0, import_router2.createEndpointConfig)("/signIn/:oauth", {
|
|
495
|
+
schemas: {
|
|
496
|
+
params: import_zod.default.object({
|
|
497
|
+
oauth: import_zod.default.enum(Object.keys(oauth)),
|
|
498
|
+
redirectTo: import_zod.default.string().optional()
|
|
499
|
+
})
|
|
500
|
+
}
|
|
501
|
+
});
|
|
502
|
+
};
|
|
529
503
|
var signInAction = (oauth) => {
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
}
|
|
504
|
+
return (0, import_router2.createEndpoint)(
|
|
505
|
+
"GET",
|
|
506
|
+
"/signIn/:oauth",
|
|
507
|
+
async (ctx) => {
|
|
508
|
+
const {
|
|
509
|
+
request,
|
|
510
|
+
params: { oauth: oauth2, redirectTo },
|
|
511
|
+
context: { oauth: providers, cookies, trustedProxyHeaders, basePath }
|
|
512
|
+
} = ctx;
|
|
513
|
+
try {
|
|
514
|
+
const cookieOptions = secureCookieOptions(request, cookies, trustedProxyHeaders);
|
|
515
|
+
const state = generateSecure();
|
|
516
|
+
const redirectURI = createRedirectURI(request, oauth2, basePath, trustedProxyHeaders);
|
|
517
|
+
const stateCookie = setCookie("state", state, oauthCookie(cookieOptions));
|
|
518
|
+
const redirectURICookie = setCookie("redirect_uri", redirectURI, oauthCookie(cookieOptions));
|
|
519
|
+
const redirectToCookie = setCookie(
|
|
520
|
+
"redirect_to",
|
|
521
|
+
createRedirectTo(request, redirectTo, trustedProxyHeaders),
|
|
522
|
+
oauthCookie(cookieOptions)
|
|
523
|
+
);
|
|
524
|
+
const { codeVerifier, codeChallenge, method } = await createPKCE();
|
|
525
|
+
const codeVerifierCookie = setCookie("code_verifier", codeVerifier, oauthCookie(cookieOptions));
|
|
526
|
+
const authorization = createAuthorizationURL(providers[oauth2], redirectURI, state, codeChallenge, method);
|
|
527
|
+
const headers = new Headers();
|
|
528
|
+
headers.set("Location", authorization);
|
|
529
|
+
headers.append("Set-Cookie", stateCookie);
|
|
530
|
+
headers.append("Set-Cookie", redirectURICookie);
|
|
531
|
+
headers.append("Set-Cookie", redirectToCookie);
|
|
532
|
+
headers.append("Set-Cookie", codeVerifierCookie);
|
|
533
|
+
return Response.json(
|
|
534
|
+
{ oauth: oauth2 },
|
|
535
|
+
{
|
|
536
|
+
status: 302,
|
|
537
|
+
headers
|
|
538
|
+
}
|
|
539
|
+
);
|
|
540
|
+
} catch (error) {
|
|
541
|
+
if (isAuthError(error)) {
|
|
542
|
+
const { type, message } = error;
|
|
543
|
+
return AuraResponse.json(
|
|
544
|
+
{ error: type, error_description: message },
|
|
545
|
+
{ status: import_router2.statusCode.BAD_REQUEST }
|
|
546
|
+
);
|
|
547
|
+
}
|
|
548
|
+
return AuraResponse.json(
|
|
549
|
+
{
|
|
550
|
+
error: ERROR_RESPONSE.AUTHORIZATION.SERVER_ERROR,
|
|
551
|
+
error_description: "An unexpected error occurred"
|
|
552
|
+
},
|
|
553
|
+
{ status: import_router2.statusCode.INTERNAL_SERVER_ERROR }
|
|
554
|
+
);
|
|
555
|
+
}
|
|
556
|
+
},
|
|
557
|
+
signInConfig(oauth)
|
|
558
|
+
);
|
|
559
|
+
};
|
|
586
560
|
|
|
587
561
|
// src/actions/callback/callback.ts
|
|
588
|
-
var import_zod2 = __toESM(require("zod"), 1)
|
|
589
|
-
var import_router3 = require("@aura-stack/router")
|
|
562
|
+
var import_zod2 = __toESM(require("zod"), 1);
|
|
563
|
+
var import_router3 = require("@aura-stack/router");
|
|
590
564
|
|
|
591
565
|
// src/headers.ts
|
|
592
566
|
var cacheControl = {
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
}
|
|
567
|
+
"Cache-Control": "no-store",
|
|
568
|
+
Pragma: "no-cache",
|
|
569
|
+
Expires: "0",
|
|
570
|
+
Vary: "Cookie"
|
|
571
|
+
};
|
|
598
572
|
|
|
599
573
|
// src/actions/callback/userinfo.ts
|
|
600
574
|
var getDefaultUserInfo = (profile) => {
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
}
|
|
575
|
+
const sub = generateSecure(16);
|
|
576
|
+
return {
|
|
577
|
+
sub: profile?.id ?? profile?.sub ?? sub,
|
|
578
|
+
email: profile?.email,
|
|
579
|
+
name: profile?.name ?? profile?.username ?? profile?.nickname,
|
|
580
|
+
image: profile?.image ?? profile?.picture
|
|
581
|
+
};
|
|
582
|
+
};
|
|
609
583
|
var getUserInfo = async (oauthConfig, accessToken) => {
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
}
|
|
624
|
-
return oauthConfig?.profile ? oauthConfig.profile(json) : getDefaultUserInfo(json)
|
|
625
|
-
} catch (error) {
|
|
626
|
-
throw throwAuthError(error, "Failed to retrieve userinfo")
|
|
584
|
+
const userinfoEndpoint = oauthConfig.userInfo;
|
|
585
|
+
try {
|
|
586
|
+
const response = await fetch(userinfoEndpoint, {
|
|
587
|
+
method: "GET",
|
|
588
|
+
headers: {
|
|
589
|
+
Accept: "application/json",
|
|
590
|
+
Authorization: `Bearer ${accessToken}`
|
|
591
|
+
}
|
|
592
|
+
});
|
|
593
|
+
const json = await response.json();
|
|
594
|
+
const { success, data } = OAuthErrorResponse.safeParse(json);
|
|
595
|
+
if (success) {
|
|
596
|
+
throw new AuthError(data.error, data?.error_description ?? "An error occurred while fetching user information.");
|
|
627
597
|
}
|
|
628
|
-
|
|
598
|
+
return oauthConfig?.profile ? oauthConfig.profile(json) : getDefaultUserInfo(json);
|
|
599
|
+
} catch (error) {
|
|
600
|
+
throw throwAuthError(error, "Failed to retrieve userinfo");
|
|
601
|
+
}
|
|
602
|
+
};
|
|
629
603
|
|
|
630
604
|
// src/actions/callback/access-token.ts
|
|
631
605
|
var createAccessToken = async (oauthConfig, redirectURI, code, codeVerifier) => {
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
606
|
+
const parsed = OAuthAccessToken.safeParse({ ...oauthConfig, redirectURI, code, codeVerifier });
|
|
607
|
+
if (!parsed.success) {
|
|
608
|
+
throw new AuthError(ERROR_RESPONSE.ACCESS_TOKEN.INVALID_REQUEST, "Invalid OAuth configuration");
|
|
609
|
+
}
|
|
610
|
+
const { accessToken, clientId, clientSecret, code: codeParsed, redirectURI: redirectParsed } = parsed.data;
|
|
611
|
+
try {
|
|
612
|
+
const response = await fetch(accessToken, {
|
|
613
|
+
method: "POST",
|
|
614
|
+
headers: {
|
|
615
|
+
Accept: "application/json",
|
|
616
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
617
|
+
},
|
|
618
|
+
body: new URLSearchParams({
|
|
619
|
+
client_id: clientId,
|
|
620
|
+
client_secret: clientSecret,
|
|
621
|
+
code: codeParsed,
|
|
622
|
+
redirect_uri: redirectParsed,
|
|
623
|
+
grant_type: "authorization_code",
|
|
624
|
+
code_verifier: codeVerifier
|
|
625
|
+
}).toString()
|
|
626
|
+
});
|
|
627
|
+
const json = await response.json();
|
|
628
|
+
const token = OAuthAccessTokenResponse.safeParse(json);
|
|
629
|
+
if (!token.success) {
|
|
630
|
+
const { success, data } = OAuthAccessTokenErrorResponse.safeParse(json);
|
|
631
|
+
if (!success) {
|
|
632
|
+
throw new AuthError(ERROR_RESPONSE.ACCESS_TOKEN.INVALID_GRANT, "Invalid access token response format");
|
|
633
|
+
}
|
|
634
|
+
throw new AuthError(data.error, data?.error_description ?? "Failed to retrieve access token");
|
|
635
635
|
}
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
Accept: "application/json",
|
|
642
|
-
"Content-Type": "application/x-www-form-urlencoded",
|
|
643
|
-
},
|
|
644
|
-
body: new URLSearchParams({
|
|
645
|
-
client_id: clientId,
|
|
646
|
-
client_secret: clientSecret,
|
|
647
|
-
code: codeParsed,
|
|
648
|
-
redirect_uri: redirectParsed,
|
|
649
|
-
grant_type: "authorization_code",
|
|
650
|
-
code_verifier: codeVerifier,
|
|
651
|
-
}).toString(),
|
|
652
|
-
})
|
|
653
|
-
const json = await response.json()
|
|
654
|
-
const token = OAuthAccessTokenResponse.safeParse(json)
|
|
655
|
-
if (!token.success) {
|
|
656
|
-
const { success, data } = OAuthAccessTokenErrorResponse.safeParse(json)
|
|
657
|
-
if (!success) {
|
|
658
|
-
throw new AuthError(ERROR_RESPONSE.ACCESS_TOKEN.INVALID_GRANT, "Invalid access token response format")
|
|
659
|
-
}
|
|
660
|
-
throw new AuthError(data.error, data?.error_description ?? "Failed to retrieve access token")
|
|
661
|
-
}
|
|
662
|
-
return token.data
|
|
663
|
-
} catch (error) {
|
|
664
|
-
throw throwAuthError(error, "Failed to create access token")
|
|
665
|
-
}
|
|
666
|
-
}
|
|
636
|
+
return token.data;
|
|
637
|
+
} catch (error) {
|
|
638
|
+
throw throwAuthError(error, "Failed to create access token");
|
|
639
|
+
}
|
|
640
|
+
};
|
|
667
641
|
|
|
668
642
|
// src/actions/callback/callback.ts
|
|
669
643
|
var callbackConfig = (oauth) => {
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
}
|
|
644
|
+
return (0, import_router3.createEndpointConfig)("/callback/:oauth", {
|
|
645
|
+
schemas: {
|
|
646
|
+
searchParams: OAuthAuthorizationResponse,
|
|
647
|
+
params: import_zod2.default.object({
|
|
648
|
+
oauth: import_zod2.default.enum(Object.keys(oauth))
|
|
649
|
+
})
|
|
650
|
+
},
|
|
651
|
+
middlewares: [
|
|
652
|
+
(ctx) => {
|
|
653
|
+
const response = OAuthAuthorizationErrorResponse.safeParse(ctx.searchParams);
|
|
654
|
+
if (response.success) {
|
|
655
|
+
const { error, error_description } = response.data;
|
|
656
|
+
throw new AuthError(error, error_description ?? "OAuth Authorization Error");
|
|
657
|
+
}
|
|
658
|
+
return ctx;
|
|
659
|
+
}
|
|
660
|
+
]
|
|
661
|
+
});
|
|
662
|
+
};
|
|
689
663
|
var callbackAction = (oauth) => {
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
}
|
|
664
|
+
return (0, import_router3.createEndpoint)(
|
|
665
|
+
"GET",
|
|
666
|
+
"/callback/:oauth",
|
|
667
|
+
async (ctx) => {
|
|
668
|
+
const {
|
|
669
|
+
request,
|
|
670
|
+
params: { oauth: oauth2 },
|
|
671
|
+
searchParams: { code, state },
|
|
672
|
+
context: { oauth: providers, cookies, jose, trustedProxyHeaders }
|
|
673
|
+
} = ctx;
|
|
674
|
+
try {
|
|
675
|
+
const oauthConfig = providers[oauth2];
|
|
676
|
+
const cookieOptions = secureCookieOptions(request, cookies, trustedProxyHeaders);
|
|
677
|
+
const cookieState = getCookie(request, "state", cookieOptions);
|
|
678
|
+
const cookieRedirectTo = getCookie(request, "redirect_to", cookieOptions);
|
|
679
|
+
const cookieRedirectURI = getCookie(request, "redirect_uri", cookieOptions);
|
|
680
|
+
const codeVerifier = getCookie(request, "code_verifier", cookieOptions);
|
|
681
|
+
if (!equals(cookieState, state)) {
|
|
682
|
+
throw new AuthError(ERROR_RESPONSE.ACCESS_TOKEN.INVALID_REQUEST, "Mismatching state");
|
|
683
|
+
}
|
|
684
|
+
const accessToken = await createAccessToken(oauthConfig, cookieRedirectURI, code, codeVerifier);
|
|
685
|
+
const sanitized = sanitizeURL(cookieRedirectTo);
|
|
686
|
+
if (!isValidRelativePath(sanitized)) {
|
|
687
|
+
throw new AuthError(
|
|
688
|
+
ERROR_RESPONSE.ACCESS_TOKEN.INVALID_REQUEST,
|
|
689
|
+
"Invalid redirect path. Potential open redirect attack detected."
|
|
690
|
+
);
|
|
691
|
+
}
|
|
692
|
+
const headers = new Headers(cacheControl);
|
|
693
|
+
headers.set("Location", sanitized);
|
|
694
|
+
const userInfo = await getUserInfo(oauthConfig, accessToken.access_token);
|
|
695
|
+
const sessionCookie = await createSessionCookie(userInfo, cookieOptions, jose);
|
|
696
|
+
const csrfToken = await createCSRF(jose);
|
|
697
|
+
const csrfCookie = setCookie(
|
|
698
|
+
"csrfToken",
|
|
699
|
+
csrfToken,
|
|
700
|
+
secureCookieOptions(
|
|
701
|
+
request,
|
|
702
|
+
{
|
|
703
|
+
...cookies,
|
|
704
|
+
strategy: "host"
|
|
705
|
+
},
|
|
706
|
+
trustedProxyHeaders
|
|
707
|
+
)
|
|
708
|
+
);
|
|
709
|
+
headers.set("Set-Cookie", sessionCookie);
|
|
710
|
+
headers.append("Set-Cookie", expireCookie("state", cookieOptions));
|
|
711
|
+
headers.append("Set-Cookie", expireCookie("redirect_uri", cookieOptions));
|
|
712
|
+
headers.append("Set-Cookie", expireCookie("redirect_to", cookieOptions));
|
|
713
|
+
headers.append("Set-Cookie", expireCookie("code_verifier", cookieOptions));
|
|
714
|
+
headers.append("Set-Cookie", csrfCookie);
|
|
715
|
+
return Response.json({ oauth: oauth2 }, { status: 302, headers });
|
|
716
|
+
} catch (error) {
|
|
717
|
+
if (isAuthError(error)) {
|
|
718
|
+
const { type, message } = error;
|
|
719
|
+
return AuraResponse.json(
|
|
720
|
+
{ error: type, error_description: message },
|
|
721
|
+
{ status: import_router3.statusCode.BAD_REQUEST }
|
|
722
|
+
);
|
|
723
|
+
}
|
|
724
|
+
return AuraResponse.json(
|
|
725
|
+
{
|
|
726
|
+
error: ERROR_RESPONSE.ACCESS_TOKEN.INVALID_CLIENT,
|
|
727
|
+
error_description: "An unexpected error occurred"
|
|
728
|
+
},
|
|
729
|
+
{ status: import_router3.statusCode.INTERNAL_SERVER_ERROR }
|
|
730
|
+
);
|
|
731
|
+
}
|
|
732
|
+
},
|
|
733
|
+
callbackConfig(oauth)
|
|
734
|
+
);
|
|
735
|
+
};
|
|
762
736
|
|
|
763
737
|
// src/actions/session/session.ts
|
|
764
|
-
var import_router4 = require("@aura-stack/router")
|
|
738
|
+
var import_router4 = require("@aura-stack/router");
|
|
765
739
|
var sessionAction = (0, import_router4.createEndpoint)("GET", "/session", async (ctx) => {
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
})
|
|
740
|
+
const {
|
|
741
|
+
request,
|
|
742
|
+
context: { cookies, jose, trustedProxyHeaders }
|
|
743
|
+
} = ctx;
|
|
744
|
+
const cookieOptions = secureCookieOptions(request, cookies, trustedProxyHeaders);
|
|
745
|
+
try {
|
|
746
|
+
const session = getCookie(request, "sessionToken", cookieOptions);
|
|
747
|
+
const decoded = await jose.decodeJWT(session);
|
|
748
|
+
const { exp, iat, jti, nbf, ...user } = decoded;
|
|
749
|
+
const headers = new Headers(cacheControl);
|
|
750
|
+
return Response.json({ user, expires: toISOString(exp * 1e3) }, { headers });
|
|
751
|
+
} catch {
|
|
752
|
+
const headers = new Headers(cacheControl);
|
|
753
|
+
const sessionCookie = expireCookie("sessionToken", cookieOptions);
|
|
754
|
+
headers.set("Set-Cookie", sessionCookie);
|
|
755
|
+
return Response.json({ authenticated: false, message: "Unauthorized" }, { status: 401, headers });
|
|
756
|
+
}
|
|
757
|
+
});
|
|
784
758
|
|
|
785
759
|
// src/actions/signOut/signOut.ts
|
|
786
|
-
var import_zod3 = __toESM(require("zod"), 1)
|
|
787
|
-
var import_router5 = require("@aura-stack/router")
|
|
760
|
+
var import_zod3 = __toESM(require("zod"), 1);
|
|
761
|
+
var import_router5 = require("@aura-stack/router");
|
|
788
762
|
var config = (0, import_router5.createEndpointConfig)({
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
})
|
|
763
|
+
schemas: {
|
|
764
|
+
searchParams: import_zod3.default.object({
|
|
765
|
+
token_type_hint: import_zod3.default.literal("session_token"),
|
|
766
|
+
redirectTo: import_zod3.default.string().optional()
|
|
767
|
+
})
|
|
768
|
+
}
|
|
769
|
+
});
|
|
796
770
|
var signOutAction = (0, import_router5.createEndpoint)(
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
)
|
|
771
|
+
"POST",
|
|
772
|
+
"/signOut",
|
|
773
|
+
async (ctx) => {
|
|
774
|
+
const {
|
|
775
|
+
request,
|
|
776
|
+
headers,
|
|
777
|
+
searchParams: { redirectTo },
|
|
778
|
+
context: { cookies, jose, trustedProxyHeaders }
|
|
779
|
+
} = ctx;
|
|
780
|
+
try {
|
|
781
|
+
const cookiesOptions = secureCookieOptions(request, cookies, trustedProxyHeaders);
|
|
782
|
+
const session = getCookie(request, "sessionToken", cookiesOptions);
|
|
783
|
+
const csrfToken = getCookie(request, "csrfToken", {
|
|
784
|
+
...cookiesOptions,
|
|
785
|
+
prefix: cookiesOptions.secure ? "__Host-" : ""
|
|
786
|
+
});
|
|
787
|
+
const header = headers.get("X-CSRF-Token");
|
|
788
|
+
if (!header || !session || !csrfToken) {
|
|
789
|
+
throw new Error("Missing CSRF token or session token");
|
|
790
|
+
}
|
|
791
|
+
await verifyCSRF(jose, csrfToken, header);
|
|
792
|
+
await jose.decodeJWT(session);
|
|
793
|
+
const normalizedOriginPath = getNormalizedOriginPath(request.url);
|
|
794
|
+
const location = createRedirectTo(
|
|
795
|
+
new Request(normalizedOriginPath, {
|
|
796
|
+
headers
|
|
797
|
+
}),
|
|
798
|
+
redirectTo
|
|
799
|
+
);
|
|
800
|
+
const responseHeaders = new Headers(cacheControl);
|
|
801
|
+
responseHeaders.append("Set-Cookie", expireCookie("sessionToken", cookiesOptions));
|
|
802
|
+
responseHeaders.append(
|
|
803
|
+
"Set-Cookie",
|
|
804
|
+
expireCookie("csrfToken", { ...cookiesOptions, prefix: cookiesOptions.secure ? "__Host-" : "" })
|
|
805
|
+
);
|
|
806
|
+
responseHeaders.append("Location", location);
|
|
807
|
+
return Response.json(
|
|
808
|
+
{ message: "Signed out successfully" },
|
|
809
|
+
{ status: import_router5.statusCode.ACCEPTED, headers: responseHeaders }
|
|
810
|
+
);
|
|
811
|
+
} catch (error) {
|
|
812
|
+
if (error instanceof InvalidCsrfTokenError) {
|
|
813
|
+
return AuraResponse.json(
|
|
814
|
+
{
|
|
815
|
+
error: "invalid_csrf_token",
|
|
816
|
+
error_description: "The provided CSRF token is invalid or has expired"
|
|
817
|
+
},
|
|
818
|
+
{ status: import_router5.statusCode.UNAUTHORIZED }
|
|
819
|
+
);
|
|
820
|
+
}
|
|
821
|
+
if (error instanceof InvalidRedirectToError) {
|
|
822
|
+
const { type, message } = error;
|
|
823
|
+
return AuraResponse.json(
|
|
824
|
+
{
|
|
825
|
+
error: type,
|
|
826
|
+
error_description: message
|
|
827
|
+
},
|
|
828
|
+
{ status: import_router5.statusCode.BAD_REQUEST }
|
|
829
|
+
);
|
|
830
|
+
}
|
|
831
|
+
return AuraResponse.json(
|
|
832
|
+
{
|
|
833
|
+
error: "invalid_session_token",
|
|
834
|
+
error_description: "The provided sessionToken is invalid or has already expired"
|
|
835
|
+
},
|
|
836
|
+
{ status: import_router5.statusCode.UNAUTHORIZED }
|
|
837
|
+
);
|
|
838
|
+
}
|
|
839
|
+
},
|
|
840
|
+
config
|
|
841
|
+
);
|
|
868
842
|
|
|
869
843
|
// src/actions/csrfToken/csrfToken.ts
|
|
870
|
-
var import_router6 = require("@aura-stack/router")
|
|
844
|
+
var import_router6 = require("@aura-stack/router");
|
|
871
845
|
var csrfTokenAction = (0, import_router6.createEndpoint)("GET", "/csrfToken", async (ctx) => {
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
})
|
|
846
|
+
const {
|
|
847
|
+
request,
|
|
848
|
+
context: { cookies, jose, trustedProxyHeaders }
|
|
849
|
+
} = ctx;
|
|
850
|
+
const cookieOptions = secureCookieOptions(request, { ...cookies, strategy: "host" }, trustedProxyHeaders);
|
|
851
|
+
const existingCSRFToken = getCookie(request, "csrfToken", cookieOptions, true);
|
|
852
|
+
const csrfToken = await createCSRF(jose, existingCSRFToken);
|
|
853
|
+
const headers = new Headers(cacheControl);
|
|
854
|
+
headers.set("Set-Cookie", setCookie("csrfToken", csrfToken, cookieOptions));
|
|
855
|
+
return Response.json({ csrfToken }, { headers });
|
|
856
|
+
});
|
|
883
857
|
// Annotate the CommonJS export names for ESM import in node:
|
|
884
|
-
0 &&
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
})
|
|
858
|
+
0 && (module.exports = {
|
|
859
|
+
callbackAction,
|
|
860
|
+
csrfTokenAction,
|
|
861
|
+
sessionAction,
|
|
862
|
+
signInAction,
|
|
863
|
+
signOutAction
|
|
864
|
+
});
|