aaspai-authx 0.0.9 → 0.1.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/express/index.cjs +226 -55
- package/dist/express/index.cjs.map +1 -1
- package/dist/express/index.js +226 -55
- package/dist/express/index.js.map +1 -1
- package/dist/index.cjs +252 -81
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +252 -81
- package/dist/index.js.map +1 -1
- package/dist/nest/index.cjs +226 -55
- package/dist/nest/index.cjs.map +1 -1
- package/dist/nest/index.js +226 -55
- package/dist/nest/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -83,50 +83,6 @@ var import_crypto = require("crypto");
|
|
|
83
83
|
var import_express = __toESM(require("express"), 1);
|
|
84
84
|
var import_jsonwebtoken4 = __toESM(require("jsonwebtoken"), 1);
|
|
85
85
|
|
|
86
|
-
// src/core/utils.ts
|
|
87
|
-
function hasRole(session, role) {
|
|
88
|
-
if (!session || !session.roles) return false;
|
|
89
|
-
return session.roles.includes(role);
|
|
90
|
-
}
|
|
91
|
-
function baseProjectCookieOptionsFrom(cookie) {
|
|
92
|
-
const base = {
|
|
93
|
-
secure: cookie.secure ?? false,
|
|
94
|
-
sameSite: cookie.sameSite ?? "lax",
|
|
95
|
-
path: cookie.path ?? "/",
|
|
96
|
-
maxAge: cookie.maxAgeMs
|
|
97
|
-
};
|
|
98
|
-
if (cookie.domain) base.domain = cookie.domain;
|
|
99
|
-
return base;
|
|
100
|
-
}
|
|
101
|
-
function hasAnyRole(session, roles) {
|
|
102
|
-
if (!session || !session.roles || !Array.isArray(roles) || roles.length === 0) {
|
|
103
|
-
return false;
|
|
104
|
-
}
|
|
105
|
-
return roles.some((role) => session.roles.includes(role));
|
|
106
|
-
}
|
|
107
|
-
function hasAllRoles(session, roles) {
|
|
108
|
-
if (!session || !session.roles || !Array.isArray(roles) || roles.length === 0) {
|
|
109
|
-
return false;
|
|
110
|
-
}
|
|
111
|
-
return roles.every((role) => session.roles.includes(role));
|
|
112
|
-
}
|
|
113
|
-
function hasPermission(session, permission) {
|
|
114
|
-
if (!session || !session.permissions) return false;
|
|
115
|
-
return session.permissions.includes(permission);
|
|
116
|
-
}
|
|
117
|
-
function hasAnyPermission(session, permissions) {
|
|
118
|
-
if (!session || !session.permissions || !Array.isArray(permissions) || permissions.length === 0) {
|
|
119
|
-
return false;
|
|
120
|
-
}
|
|
121
|
-
return permissions.some((perm) => session.permissions.includes(perm));
|
|
122
|
-
}
|
|
123
|
-
function hasAllPermissions(session, permissions) {
|
|
124
|
-
if (!session || !session.permissions || !Array.isArray(permissions) || permissions.length === 0) {
|
|
125
|
-
return false;
|
|
126
|
-
}
|
|
127
|
-
return permissions.every((perm) => session.permissions.includes(perm));
|
|
128
|
-
}
|
|
129
|
-
|
|
130
86
|
// src/config/loadConfig.ts
|
|
131
87
|
function loadConfig() {
|
|
132
88
|
return {
|
|
@@ -190,6 +146,63 @@ function isPlainObject(value) {
|
|
|
190
146
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
191
147
|
}
|
|
192
148
|
|
|
149
|
+
// src/core/utils.ts
|
|
150
|
+
function hasRole(session, role) {
|
|
151
|
+
if (!session || !session.roles) return false;
|
|
152
|
+
return session.roles.includes(role);
|
|
153
|
+
}
|
|
154
|
+
function baseProjectCookieOptionsFrom(cookie) {
|
|
155
|
+
const base = {
|
|
156
|
+
secure: cookie.secure ?? false,
|
|
157
|
+
sameSite: cookie.sameSite ?? "lax",
|
|
158
|
+
path: cookie.path ?? "/",
|
|
159
|
+
maxAge: cookie.maxAgeMs
|
|
160
|
+
};
|
|
161
|
+
if (cookie.domain) base.domain = cookie.domain;
|
|
162
|
+
return base;
|
|
163
|
+
}
|
|
164
|
+
function buildClearCookieOptions(cookie) {
|
|
165
|
+
const opts = {
|
|
166
|
+
httpOnly: true,
|
|
167
|
+
// not strictly required but fine
|
|
168
|
+
secure: cookie.secure ?? false,
|
|
169
|
+
sameSite: cookie.sameSite ?? "lax",
|
|
170
|
+
path: cookie.path ?? "/"
|
|
171
|
+
};
|
|
172
|
+
if (cookie.domain) {
|
|
173
|
+
opts.domain = cookie.domain;
|
|
174
|
+
}
|
|
175
|
+
return opts;
|
|
176
|
+
}
|
|
177
|
+
function hasAnyRole(session, roles) {
|
|
178
|
+
if (!session || !session.roles || !Array.isArray(roles) || roles.length === 0) {
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
return roles.some((role) => session.roles.includes(role));
|
|
182
|
+
}
|
|
183
|
+
function hasAllRoles(session, roles) {
|
|
184
|
+
if (!session || !session.roles || !Array.isArray(roles) || roles.length === 0) {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
return roles.every((role) => session.roles.includes(role));
|
|
188
|
+
}
|
|
189
|
+
function hasPermission(session, permission) {
|
|
190
|
+
if (!session || !session.permissions) return false;
|
|
191
|
+
return session.permissions.includes(permission);
|
|
192
|
+
}
|
|
193
|
+
function hasAnyPermission(session, permissions) {
|
|
194
|
+
if (!session || !session.permissions || !Array.isArray(permissions) || permissions.length === 0) {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
return permissions.some((perm) => session.permissions.includes(perm));
|
|
198
|
+
}
|
|
199
|
+
function hasAllPermissions(session, permissions) {
|
|
200
|
+
if (!session || !session.permissions || !Array.isArray(permissions) || permissions.length === 0) {
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
return permissions.every((perm) => session.permissions.includes(perm));
|
|
204
|
+
}
|
|
205
|
+
|
|
193
206
|
// src/core/roles.config.ts
|
|
194
207
|
var PLATFORM_ROLES = [
|
|
195
208
|
{
|
|
@@ -291,7 +304,7 @@ var MetadataSchema = new import_mongoose2.default.Schema(
|
|
|
291
304
|
);
|
|
292
305
|
var OrgUserSchema = new import_mongoose2.default.Schema(
|
|
293
306
|
{
|
|
294
|
-
id: { type: String, default: (0, import_uuid.v4)(), index: true },
|
|
307
|
+
id: { type: String, default: (0, import_uuid.v4)(), index: true, unique: true },
|
|
295
308
|
email: { type: String, required: true, unique: true },
|
|
296
309
|
firstName: { type: String, required: true },
|
|
297
310
|
lastName: { type: String, required: true },
|
|
@@ -526,6 +539,7 @@ var Invite = import_mongoose3.default.model("Invite", InviteSchema);
|
|
|
526
539
|
// src/services/auth-admin.service.ts
|
|
527
540
|
var import_bcrypt = __toESM(require("bcrypt"), 1);
|
|
528
541
|
var import_jsonwebtoken2 = __toESM(require("jsonwebtoken"), 1);
|
|
542
|
+
var import_uuid2 = require("uuid");
|
|
529
543
|
|
|
530
544
|
// src/models/client.model.ts
|
|
531
545
|
var import_mongoose4 = __toESM(require("mongoose"), 1);
|
|
@@ -595,14 +609,14 @@ var AuthAdminService = class {
|
|
|
595
609
|
async createUserInRealm(payload) {
|
|
596
610
|
const hashedPassword = payload.credentials?.[0]?.value ? await import_bcrypt.default.hash(payload.credentials[0].value, 10) : void 0;
|
|
597
611
|
const user = await OrgUser.create({
|
|
598
|
-
|
|
612
|
+
id: (0, import_uuid2.v4)(),
|
|
599
613
|
email: payload.email,
|
|
600
614
|
firstName: payload.firstName,
|
|
601
615
|
lastName: payload.lastName,
|
|
602
616
|
projectId: payload.projectId,
|
|
603
617
|
emailVerified: payload.emailVerified || false,
|
|
604
618
|
passwordHash: hashedPassword,
|
|
605
|
-
|
|
619
|
+
metadata: payload.metadata || []
|
|
606
620
|
});
|
|
607
621
|
return user;
|
|
608
622
|
}
|
|
@@ -690,29 +704,13 @@ var EmailService = class {
|
|
|
690
704
|
}
|
|
691
705
|
};
|
|
692
706
|
|
|
693
|
-
// src/utils/cookie.ts
|
|
694
|
-
function cookieOpts(isRefresh = false) {
|
|
695
|
-
const maxAge = isRefresh ? config.cookies.refreshTtlMs : config.cookies.accessTtlMs;
|
|
696
|
-
const secure = process.env.NODE_ENV === "production" ? process.env.COOKIE_SECURE ?? true : false;
|
|
697
|
-
return {
|
|
698
|
-
httpOnly: true,
|
|
699
|
-
secure,
|
|
700
|
-
sameSite: "none",
|
|
701
|
-
domain: process.env.COOKIE_DOMAIN,
|
|
702
|
-
maxAge
|
|
703
|
-
};
|
|
704
|
-
}
|
|
705
|
-
function clearOpts() {
|
|
706
|
-
const secure = process.env.NODE_ENV === "production" ? process.env.COOKIE_SECURE ?? true : false;
|
|
707
|
-
return {
|
|
708
|
-
domain: process.env.COOKIE_DOMAIN,
|
|
709
|
-
sameSite: "none",
|
|
710
|
-
secure
|
|
711
|
-
};
|
|
712
|
-
}
|
|
713
|
-
|
|
714
707
|
// src/express/auth.routes.ts
|
|
715
708
|
function createAuthRouter(options = {}) {
|
|
709
|
+
const googleClientId = process.env.GOOGLE_CLIENT_ID;
|
|
710
|
+
const googleClientSecret = process.env.GOOGLE_CLIENT_SECRET;
|
|
711
|
+
const googleRedirectUri = process.env.GOOGLE_REDIRECT_URI;
|
|
712
|
+
const googleDefaultRedirect = process.env.GOOGLE_DEFAULT_REDIRECT || getFrontendBaseUrl(options) || "/";
|
|
713
|
+
const isGoogleEnabled = !!googleClientId && !!googleClientSecret && !!googleRedirectUri;
|
|
716
714
|
if (options.config) {
|
|
717
715
|
configureAuthX(options.config);
|
|
718
716
|
}
|
|
@@ -737,8 +735,10 @@ function createAuthRouter(options = {}) {
|
|
|
737
735
|
);
|
|
738
736
|
r.post("/login", validateLogin, async (req, res) => {
|
|
739
737
|
const { email: emailAddress, password } = req.body || {};
|
|
738
|
+
console.log(emailAddress, password, "body");
|
|
740
739
|
try {
|
|
741
740
|
const user = await OrgUser.findOne({ email: emailAddress }).select("+password").lean();
|
|
741
|
+
console.log(user, "user");
|
|
742
742
|
if (!user) {
|
|
743
743
|
return res.status(400).json({
|
|
744
744
|
error: "Invalid email or password",
|
|
@@ -791,13 +791,13 @@ function createAuthRouter(options = {}) {
|
|
|
791
791
|
firstName,
|
|
792
792
|
lastName,
|
|
793
793
|
projectId,
|
|
794
|
-
credentials: [{ type: "password", value: password, temporary: false }]
|
|
794
|
+
credentials: [{ type: "password", value: password, temporary: false }],
|
|
795
|
+
metadata
|
|
795
796
|
});
|
|
796
797
|
await authAdmin.assignRealmRole(kcUser.id, "platform_user");
|
|
797
798
|
const user = await OrgUser.findOneAndUpdate(
|
|
798
799
|
{ email: kcUser.email },
|
|
799
800
|
{
|
|
800
|
-
id: kcUser.id,
|
|
801
801
|
email: kcUser.email,
|
|
802
802
|
firstName,
|
|
803
803
|
lastName,
|
|
@@ -837,8 +837,9 @@ function createAuthRouter(options = {}) {
|
|
|
837
837
|
return res.json(req.user || null);
|
|
838
838
|
});
|
|
839
839
|
r.post("/logout", async (_req, res) => {
|
|
840
|
-
|
|
841
|
-
res.clearCookie("
|
|
840
|
+
const clearOptions = buildClearCookieOptions(cookieConfig);
|
|
841
|
+
res.clearCookie("access_token", clearOptions);
|
|
842
|
+
res.clearCookie("refresh_token", clearOptions);
|
|
842
843
|
res.json({ ok: true });
|
|
843
844
|
});
|
|
844
845
|
r.put("/:userId/metadata", requireAuth(), async (req, res) => {
|
|
@@ -1077,16 +1078,186 @@ function createAuthRouter(options = {}) {
|
|
|
1077
1078
|
const user = await OrgUser.findOne({ email: req.query.email }).lean();
|
|
1078
1079
|
res.json(user || null);
|
|
1079
1080
|
});
|
|
1080
|
-
r.get("/google",
|
|
1081
|
-
|
|
1081
|
+
r.get("/google", (req, res) => {
|
|
1082
|
+
if (!isGoogleEnabled) {
|
|
1083
|
+
return res.status(500).json({ error: "Google login not configured" });
|
|
1084
|
+
}
|
|
1085
|
+
const state = req.query.redirectTo ? encodeURIComponent(String(req.query.redirectTo)) : "";
|
|
1086
|
+
const params = new URLSearchParams({
|
|
1087
|
+
client_id: googleClientId,
|
|
1088
|
+
redirect_uri: googleRedirectUri,
|
|
1089
|
+
response_type: "code",
|
|
1090
|
+
scope: "openid email profile",
|
|
1091
|
+
access_type: "offline",
|
|
1092
|
+
prompt: "consent",
|
|
1093
|
+
state
|
|
1094
|
+
});
|
|
1095
|
+
const url = `https://accounts.google.com/o/oauth2/v2/auth?${params.toString()}`;
|
|
1096
|
+
res.redirect(url);
|
|
1082
1097
|
});
|
|
1083
|
-
r.get("/google/callback", async (
|
|
1084
|
-
|
|
1085
|
-
"
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
);
|
|
1089
|
-
|
|
1098
|
+
r.get("/google/callback", async (req, res) => {
|
|
1099
|
+
if (!isGoogleEnabled) {
|
|
1100
|
+
return res.status(500).json({ error: "Google login not configured" });
|
|
1101
|
+
}
|
|
1102
|
+
const code = String(req.query.code || "");
|
|
1103
|
+
const state = req.query.state ? String(req.query.state) : "";
|
|
1104
|
+
if (!code) {
|
|
1105
|
+
return res.status(400).json({ ok: false, error: "Missing authorization code" });
|
|
1106
|
+
}
|
|
1107
|
+
try {
|
|
1108
|
+
const tokenRes = await fetch("https://oauth2.googleapis.com/token", {
|
|
1109
|
+
method: "POST",
|
|
1110
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
1111
|
+
body: new URLSearchParams({
|
|
1112
|
+
code,
|
|
1113
|
+
client_id: googleClientId,
|
|
1114
|
+
client_secret: googleClientSecret,
|
|
1115
|
+
redirect_uri: googleRedirectUri,
|
|
1116
|
+
grant_type: "authorization_code"
|
|
1117
|
+
})
|
|
1118
|
+
});
|
|
1119
|
+
if (!tokenRes.ok) {
|
|
1120
|
+
const errJson = await tokenRes.json().catch(() => ({}));
|
|
1121
|
+
console.error("Google token error", errJson);
|
|
1122
|
+
return res.status(400).json({ ok: false, error: "Failed to exchange Google code" });
|
|
1123
|
+
}
|
|
1124
|
+
const tokenJson = await tokenRes.json();
|
|
1125
|
+
if (!tokenJson.id_token) {
|
|
1126
|
+
return res.status(400).json({ ok: false, error: "Missing id_token from Google" });
|
|
1127
|
+
}
|
|
1128
|
+
const decoded = import_jsonwebtoken4.default.decode(tokenJson.id_token);
|
|
1129
|
+
const email2 = decoded?.email;
|
|
1130
|
+
if (!email2) {
|
|
1131
|
+
return res.status(400).json({ ok: false, error: "Google account has no email" });
|
|
1132
|
+
}
|
|
1133
|
+
const emailVerified = decoded.email_verified ?? true;
|
|
1134
|
+
const firstName = decoded.given_name || "";
|
|
1135
|
+
const lastName = decoded.family_name || "";
|
|
1136
|
+
let user = await OrgUser.findOne({ email: email2 }).lean();
|
|
1137
|
+
if (!user) {
|
|
1138
|
+
const created = await OrgUser.create({
|
|
1139
|
+
email: email2,
|
|
1140
|
+
firstName,
|
|
1141
|
+
lastName,
|
|
1142
|
+
emailVerified,
|
|
1143
|
+
roles: ["platform_user"],
|
|
1144
|
+
projectId: null,
|
|
1145
|
+
metadata: []
|
|
1146
|
+
// you can also store googleId: decoded.sub
|
|
1147
|
+
});
|
|
1148
|
+
user = created.toObject();
|
|
1149
|
+
}
|
|
1150
|
+
const tokens = generateTokens(user);
|
|
1151
|
+
setAuthCookies(res, tokens, cookieConfig);
|
|
1152
|
+
const redirectTo = state ? decodeURIComponent(state) : googleDefaultRedirect;
|
|
1153
|
+
res.redirect(redirectTo);
|
|
1154
|
+
} catch (err) {
|
|
1155
|
+
console.error("Google callback error", err);
|
|
1156
|
+
const redirectError = googleDefaultRedirect.includes("?") ? `${googleDefaultRedirect}&error=google_login_failed` : `${googleDefaultRedirect}?error=google_login_failed`;
|
|
1157
|
+
res.redirect(redirectError);
|
|
1158
|
+
}
|
|
1159
|
+
});
|
|
1160
|
+
r.get("/github", (req, res) => {
|
|
1161
|
+
const githubClientId = process.env.GITHUB_CLIENT_ID;
|
|
1162
|
+
const githubRedirectUri = process.env.GITHUB_REDIRECT_URI;
|
|
1163
|
+
if (!githubClientId || !githubRedirectUri) {
|
|
1164
|
+
return res.status(500).json({ error: "GitHub login not configured" });
|
|
1165
|
+
}
|
|
1166
|
+
const state = req.query.redirectTo ? encodeURIComponent(String(req.query.redirectTo)) : "";
|
|
1167
|
+
const params = new URLSearchParams({
|
|
1168
|
+
client_id: githubClientId,
|
|
1169
|
+
redirect_uri: githubRedirectUri,
|
|
1170
|
+
scope: "user:email",
|
|
1171
|
+
state,
|
|
1172
|
+
allow_signup: "true"
|
|
1173
|
+
});
|
|
1174
|
+
const url = `https://github.com/login/oauth/authorize?${params.toString()}`;
|
|
1175
|
+
res.redirect(url);
|
|
1176
|
+
});
|
|
1177
|
+
r.get("/github/callback", async (req, res) => {
|
|
1178
|
+
const githubClientId = process.env.GITHUB_CLIENT_ID;
|
|
1179
|
+
const githubClientSecret = process.env.GITHUB_CLIENT_SECRET;
|
|
1180
|
+
const githubRedirectUri = process.env.GITHUB_REDIRECT_URI;
|
|
1181
|
+
const githubDefaultRedirect = process.env.GITHUB_DEFAULT_REDIRECT || getFrontendBaseUrl(options) || "/";
|
|
1182
|
+
if (!githubClientId || !githubClientSecret || !githubRedirectUri) {
|
|
1183
|
+
return res.status(500).json({ error: "GitHub login not configured" });
|
|
1184
|
+
}
|
|
1185
|
+
const code = String(req.query.code || "");
|
|
1186
|
+
const state = req.query.state ? String(req.query.state) : "";
|
|
1187
|
+
if (!code) {
|
|
1188
|
+
return res.status(400).json({ ok: false, error: "Missing GitHub code" });
|
|
1189
|
+
}
|
|
1190
|
+
try {
|
|
1191
|
+
const tokenRes = await fetch(
|
|
1192
|
+
"https://github.com/login/oauth/access_token",
|
|
1193
|
+
{
|
|
1194
|
+
method: "POST",
|
|
1195
|
+
headers: {
|
|
1196
|
+
Accept: "application/json",
|
|
1197
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
1198
|
+
},
|
|
1199
|
+
body: new URLSearchParams({
|
|
1200
|
+
client_id: githubClientId,
|
|
1201
|
+
client_secret: githubClientSecret,
|
|
1202
|
+
code,
|
|
1203
|
+
redirect_uri: githubRedirectUri
|
|
1204
|
+
})
|
|
1205
|
+
}
|
|
1206
|
+
);
|
|
1207
|
+
const tokenJson = await tokenRes.json();
|
|
1208
|
+
if (!tokenJson.access_token) {
|
|
1209
|
+
console.error("GitHub token error:", tokenJson);
|
|
1210
|
+
return res.status(400).json({ ok: false, error: "Failed to get GitHub access token" });
|
|
1211
|
+
}
|
|
1212
|
+
const accessToken = tokenJson.access_token;
|
|
1213
|
+
const userRes = await fetch("https://api.github.com/user", {
|
|
1214
|
+
headers: {
|
|
1215
|
+
Authorization: `Bearer ${accessToken}`,
|
|
1216
|
+
Accept: "application/vnd.github+json"
|
|
1217
|
+
}
|
|
1218
|
+
});
|
|
1219
|
+
const githubUser = await userRes.json();
|
|
1220
|
+
const emailRes = await fetch("https://api.github.com/user/emails", {
|
|
1221
|
+
headers: {
|
|
1222
|
+
Authorization: `Bearer ${accessToken}`,
|
|
1223
|
+
Accept: "application/vnd.github+json"
|
|
1224
|
+
}
|
|
1225
|
+
});
|
|
1226
|
+
const emails = await emailRes.json();
|
|
1227
|
+
const primaryEmail = emails?.find(
|
|
1228
|
+
(e) => e.primary && e.verified
|
|
1229
|
+
)?.email;
|
|
1230
|
+
if (!primaryEmail) {
|
|
1231
|
+
return res.status(400).json({
|
|
1232
|
+
ok: false,
|
|
1233
|
+
error: "GitHub account has no verified email"
|
|
1234
|
+
});
|
|
1235
|
+
}
|
|
1236
|
+
const firstName = githubUser.name?.split(" ")[0] || "";
|
|
1237
|
+
const lastName = githubUser.name?.split(" ").slice(1).join(" ") || "";
|
|
1238
|
+
let user = await OrgUser.findOne({ email: primaryEmail }).lean();
|
|
1239
|
+
if (!user) {
|
|
1240
|
+
const created = await OrgUser.create({
|
|
1241
|
+
email: primaryEmail,
|
|
1242
|
+
firstName,
|
|
1243
|
+
lastName,
|
|
1244
|
+
emailVerified: true,
|
|
1245
|
+
roles: ["platform_user"],
|
|
1246
|
+
projectId: null,
|
|
1247
|
+
metadata: [],
|
|
1248
|
+
githubId: githubUser.id
|
|
1249
|
+
});
|
|
1250
|
+
user = created.toObject();
|
|
1251
|
+
}
|
|
1252
|
+
const tokens = generateTokens(user);
|
|
1253
|
+
setAuthCookies(res, tokens, cookieConfig);
|
|
1254
|
+
const redirectTo = state ? decodeURIComponent(state) : githubDefaultRedirect;
|
|
1255
|
+
res.redirect(redirectTo);
|
|
1256
|
+
} catch (err) {
|
|
1257
|
+
console.error("GitHub callback error:", err);
|
|
1258
|
+
const redirectError = githubDefaultRedirect.includes("?") ? `${githubDefaultRedirect}&error=github_login_failed` : `${githubDefaultRedirect}?error=github_login_failed`;
|
|
1259
|
+
res.redirect(redirectError);
|
|
1260
|
+
}
|
|
1090
1261
|
});
|
|
1091
1262
|
r.get("/get-users", async (req, res) => {
|
|
1092
1263
|
const user = await OrgUser.find({ projectId: req.query.projectId }).lean();
|