aaspai-authx 0.1.0 → 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.d.cts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -31,50 +31,6 @@ import express, {
|
|
|
31
31
|
} from "express";
|
|
32
32
|
import jwt4 from "jsonwebtoken";
|
|
33
33
|
|
|
34
|
-
// src/core/utils.ts
|
|
35
|
-
function hasRole(session, role) {
|
|
36
|
-
if (!session || !session.roles) return false;
|
|
37
|
-
return session.roles.includes(role);
|
|
38
|
-
}
|
|
39
|
-
function baseProjectCookieOptionsFrom(cookie) {
|
|
40
|
-
const base = {
|
|
41
|
-
secure: cookie.secure ?? false,
|
|
42
|
-
sameSite: cookie.sameSite ?? "lax",
|
|
43
|
-
path: cookie.path ?? "/",
|
|
44
|
-
maxAge: cookie.maxAgeMs
|
|
45
|
-
};
|
|
46
|
-
if (cookie.domain) base.domain = cookie.domain;
|
|
47
|
-
return base;
|
|
48
|
-
}
|
|
49
|
-
function hasAnyRole(session, roles) {
|
|
50
|
-
if (!session || !session.roles || !Array.isArray(roles) || roles.length === 0) {
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
return roles.some((role) => session.roles.includes(role));
|
|
54
|
-
}
|
|
55
|
-
function hasAllRoles(session, roles) {
|
|
56
|
-
if (!session || !session.roles || !Array.isArray(roles) || roles.length === 0) {
|
|
57
|
-
return false;
|
|
58
|
-
}
|
|
59
|
-
return roles.every((role) => session.roles.includes(role));
|
|
60
|
-
}
|
|
61
|
-
function hasPermission(session, permission) {
|
|
62
|
-
if (!session || !session.permissions) return false;
|
|
63
|
-
return session.permissions.includes(permission);
|
|
64
|
-
}
|
|
65
|
-
function hasAnyPermission(session, permissions) {
|
|
66
|
-
if (!session || !session.permissions || !Array.isArray(permissions) || permissions.length === 0) {
|
|
67
|
-
return false;
|
|
68
|
-
}
|
|
69
|
-
return permissions.some((perm) => session.permissions.includes(perm));
|
|
70
|
-
}
|
|
71
|
-
function hasAllPermissions(session, permissions) {
|
|
72
|
-
if (!session || !session.permissions || !Array.isArray(permissions) || permissions.length === 0) {
|
|
73
|
-
return false;
|
|
74
|
-
}
|
|
75
|
-
return permissions.every((perm) => session.permissions.includes(perm));
|
|
76
|
-
}
|
|
77
|
-
|
|
78
34
|
// src/config/loadConfig.ts
|
|
79
35
|
function loadConfig() {
|
|
80
36
|
return {
|
|
@@ -138,6 +94,63 @@ function isPlainObject(value) {
|
|
|
138
94
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
139
95
|
}
|
|
140
96
|
|
|
97
|
+
// src/core/utils.ts
|
|
98
|
+
function hasRole(session, role) {
|
|
99
|
+
if (!session || !session.roles) return false;
|
|
100
|
+
return session.roles.includes(role);
|
|
101
|
+
}
|
|
102
|
+
function baseProjectCookieOptionsFrom(cookie) {
|
|
103
|
+
const base = {
|
|
104
|
+
secure: cookie.secure ?? false,
|
|
105
|
+
sameSite: cookie.sameSite ?? "lax",
|
|
106
|
+
path: cookie.path ?? "/",
|
|
107
|
+
maxAge: cookie.maxAgeMs
|
|
108
|
+
};
|
|
109
|
+
if (cookie.domain) base.domain = cookie.domain;
|
|
110
|
+
return base;
|
|
111
|
+
}
|
|
112
|
+
function buildClearCookieOptions(cookie) {
|
|
113
|
+
const opts = {
|
|
114
|
+
httpOnly: true,
|
|
115
|
+
// not strictly required but fine
|
|
116
|
+
secure: cookie.secure ?? false,
|
|
117
|
+
sameSite: cookie.sameSite ?? "lax",
|
|
118
|
+
path: cookie.path ?? "/"
|
|
119
|
+
};
|
|
120
|
+
if (cookie.domain) {
|
|
121
|
+
opts.domain = cookie.domain;
|
|
122
|
+
}
|
|
123
|
+
return opts;
|
|
124
|
+
}
|
|
125
|
+
function hasAnyRole(session, roles) {
|
|
126
|
+
if (!session || !session.roles || !Array.isArray(roles) || roles.length === 0) {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
return roles.some((role) => session.roles.includes(role));
|
|
130
|
+
}
|
|
131
|
+
function hasAllRoles(session, roles) {
|
|
132
|
+
if (!session || !session.roles || !Array.isArray(roles) || roles.length === 0) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
return roles.every((role) => session.roles.includes(role));
|
|
136
|
+
}
|
|
137
|
+
function hasPermission(session, permission) {
|
|
138
|
+
if (!session || !session.permissions) return false;
|
|
139
|
+
return session.permissions.includes(permission);
|
|
140
|
+
}
|
|
141
|
+
function hasAnyPermission(session, permissions) {
|
|
142
|
+
if (!session || !session.permissions || !Array.isArray(permissions) || permissions.length === 0) {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
return permissions.some((perm) => session.permissions.includes(perm));
|
|
146
|
+
}
|
|
147
|
+
function hasAllPermissions(session, permissions) {
|
|
148
|
+
if (!session || !session.permissions || !Array.isArray(permissions) || permissions.length === 0) {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
return permissions.every((perm) => session.permissions.includes(perm));
|
|
152
|
+
}
|
|
153
|
+
|
|
141
154
|
// src/core/roles.config.ts
|
|
142
155
|
var PLATFORM_ROLES = [
|
|
143
156
|
{
|
|
@@ -239,7 +252,7 @@ var MetadataSchema = new mongoose2.Schema(
|
|
|
239
252
|
);
|
|
240
253
|
var OrgUserSchema = new mongoose2.Schema(
|
|
241
254
|
{
|
|
242
|
-
id: { type: String, default: uuid(), index: true },
|
|
255
|
+
id: { type: String, default: uuid(), index: true, unique: true },
|
|
243
256
|
email: { type: String, required: true, unique: true },
|
|
244
257
|
firstName: { type: String, required: true },
|
|
245
258
|
lastName: { type: String, required: true },
|
|
@@ -474,6 +487,7 @@ var Invite = mongoose3.model("Invite", InviteSchema);
|
|
|
474
487
|
// src/services/auth-admin.service.ts
|
|
475
488
|
import bcrypt from "bcrypt";
|
|
476
489
|
import jwt2 from "jsonwebtoken";
|
|
490
|
+
import { v4 as uuid2 } from "uuid";
|
|
477
491
|
|
|
478
492
|
// src/models/client.model.ts
|
|
479
493
|
import mongoose4, { Schema as Schema2 } from "mongoose";
|
|
@@ -543,14 +557,14 @@ var AuthAdminService = class {
|
|
|
543
557
|
async createUserInRealm(payload) {
|
|
544
558
|
const hashedPassword = payload.credentials?.[0]?.value ? await bcrypt.hash(payload.credentials[0].value, 10) : void 0;
|
|
545
559
|
const user = await OrgUser.create({
|
|
546
|
-
|
|
560
|
+
id: uuid2(),
|
|
547
561
|
email: payload.email,
|
|
548
562
|
firstName: payload.firstName,
|
|
549
563
|
lastName: payload.lastName,
|
|
550
564
|
projectId: payload.projectId,
|
|
551
565
|
emailVerified: payload.emailVerified || false,
|
|
552
566
|
passwordHash: hashedPassword,
|
|
553
|
-
|
|
567
|
+
metadata: payload.metadata || []
|
|
554
568
|
});
|
|
555
569
|
return user;
|
|
556
570
|
}
|
|
@@ -638,29 +652,13 @@ var EmailService = class {
|
|
|
638
652
|
}
|
|
639
653
|
};
|
|
640
654
|
|
|
641
|
-
// src/utils/cookie.ts
|
|
642
|
-
function cookieOpts(isRefresh = false) {
|
|
643
|
-
const maxAge = isRefresh ? config.cookies.refreshTtlMs : config.cookies.accessTtlMs;
|
|
644
|
-
const secure = process.env.NODE_ENV === "production" ? process.env.COOKIE_SECURE ?? true : false;
|
|
645
|
-
return {
|
|
646
|
-
httpOnly: true,
|
|
647
|
-
secure,
|
|
648
|
-
sameSite: "none",
|
|
649
|
-
domain: process.env.COOKIE_DOMAIN,
|
|
650
|
-
maxAge
|
|
651
|
-
};
|
|
652
|
-
}
|
|
653
|
-
function clearOpts() {
|
|
654
|
-
const secure = process.env.NODE_ENV === "production" ? process.env.COOKIE_SECURE ?? true : false;
|
|
655
|
-
return {
|
|
656
|
-
domain: process.env.COOKIE_DOMAIN,
|
|
657
|
-
sameSite: "none",
|
|
658
|
-
secure
|
|
659
|
-
};
|
|
660
|
-
}
|
|
661
|
-
|
|
662
655
|
// src/express/auth.routes.ts
|
|
663
656
|
function createAuthRouter(options = {}) {
|
|
657
|
+
const googleClientId = process.env.GOOGLE_CLIENT_ID;
|
|
658
|
+
const googleClientSecret = process.env.GOOGLE_CLIENT_SECRET;
|
|
659
|
+
const googleRedirectUri = process.env.GOOGLE_REDIRECT_URI;
|
|
660
|
+
const googleDefaultRedirect = process.env.GOOGLE_DEFAULT_REDIRECT || getFrontendBaseUrl(options) || "/";
|
|
661
|
+
const isGoogleEnabled = !!googleClientId && !!googleClientSecret && !!googleRedirectUri;
|
|
664
662
|
if (options.config) {
|
|
665
663
|
configureAuthX(options.config);
|
|
666
664
|
}
|
|
@@ -685,8 +683,10 @@ function createAuthRouter(options = {}) {
|
|
|
685
683
|
);
|
|
686
684
|
r.post("/login", validateLogin, async (req, res) => {
|
|
687
685
|
const { email: emailAddress, password } = req.body || {};
|
|
686
|
+
console.log(emailAddress, password, "body");
|
|
688
687
|
try {
|
|
689
688
|
const user = await OrgUser.findOne({ email: emailAddress }).select("+password").lean();
|
|
689
|
+
console.log(user, "user");
|
|
690
690
|
if (!user) {
|
|
691
691
|
return res.status(400).json({
|
|
692
692
|
error: "Invalid email or password",
|
|
@@ -739,13 +739,13 @@ function createAuthRouter(options = {}) {
|
|
|
739
739
|
firstName,
|
|
740
740
|
lastName,
|
|
741
741
|
projectId,
|
|
742
|
-
credentials: [{ type: "password", value: password, temporary: false }]
|
|
742
|
+
credentials: [{ type: "password", value: password, temporary: false }],
|
|
743
|
+
metadata
|
|
743
744
|
});
|
|
744
745
|
await authAdmin.assignRealmRole(kcUser.id, "platform_user");
|
|
745
746
|
const user = await OrgUser.findOneAndUpdate(
|
|
746
747
|
{ email: kcUser.email },
|
|
747
748
|
{
|
|
748
|
-
id: kcUser.id,
|
|
749
749
|
email: kcUser.email,
|
|
750
750
|
firstName,
|
|
751
751
|
lastName,
|
|
@@ -785,8 +785,9 @@ function createAuthRouter(options = {}) {
|
|
|
785
785
|
return res.json(req.user || null);
|
|
786
786
|
});
|
|
787
787
|
r.post("/logout", async (_req, res) => {
|
|
788
|
-
|
|
789
|
-
res.clearCookie("
|
|
788
|
+
const clearOptions = buildClearCookieOptions(cookieConfig);
|
|
789
|
+
res.clearCookie("access_token", clearOptions);
|
|
790
|
+
res.clearCookie("refresh_token", clearOptions);
|
|
790
791
|
res.json({ ok: true });
|
|
791
792
|
});
|
|
792
793
|
r.put("/:userId/metadata", requireAuth(), async (req, res) => {
|
|
@@ -1025,16 +1026,186 @@ function createAuthRouter(options = {}) {
|
|
|
1025
1026
|
const user = await OrgUser.findOne({ email: req.query.email }).lean();
|
|
1026
1027
|
res.json(user || null);
|
|
1027
1028
|
});
|
|
1028
|
-
r.get("/google",
|
|
1029
|
-
|
|
1029
|
+
r.get("/google", (req, res) => {
|
|
1030
|
+
if (!isGoogleEnabled) {
|
|
1031
|
+
return res.status(500).json({ error: "Google login not configured" });
|
|
1032
|
+
}
|
|
1033
|
+
const state = req.query.redirectTo ? encodeURIComponent(String(req.query.redirectTo)) : "";
|
|
1034
|
+
const params = new URLSearchParams({
|
|
1035
|
+
client_id: googleClientId,
|
|
1036
|
+
redirect_uri: googleRedirectUri,
|
|
1037
|
+
response_type: "code",
|
|
1038
|
+
scope: "openid email profile",
|
|
1039
|
+
access_type: "offline",
|
|
1040
|
+
prompt: "consent",
|
|
1041
|
+
state
|
|
1042
|
+
});
|
|
1043
|
+
const url = `https://accounts.google.com/o/oauth2/v2/auth?${params.toString()}`;
|
|
1044
|
+
res.redirect(url);
|
|
1030
1045
|
});
|
|
1031
|
-
r.get("/google/callback", async (
|
|
1032
|
-
|
|
1033
|
-
"
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
);
|
|
1037
|
-
|
|
1046
|
+
r.get("/google/callback", async (req, res) => {
|
|
1047
|
+
if (!isGoogleEnabled) {
|
|
1048
|
+
return res.status(500).json({ error: "Google login not configured" });
|
|
1049
|
+
}
|
|
1050
|
+
const code = String(req.query.code || "");
|
|
1051
|
+
const state = req.query.state ? String(req.query.state) : "";
|
|
1052
|
+
if (!code) {
|
|
1053
|
+
return res.status(400).json({ ok: false, error: "Missing authorization code" });
|
|
1054
|
+
}
|
|
1055
|
+
try {
|
|
1056
|
+
const tokenRes = await fetch("https://oauth2.googleapis.com/token", {
|
|
1057
|
+
method: "POST",
|
|
1058
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
1059
|
+
body: new URLSearchParams({
|
|
1060
|
+
code,
|
|
1061
|
+
client_id: googleClientId,
|
|
1062
|
+
client_secret: googleClientSecret,
|
|
1063
|
+
redirect_uri: googleRedirectUri,
|
|
1064
|
+
grant_type: "authorization_code"
|
|
1065
|
+
})
|
|
1066
|
+
});
|
|
1067
|
+
if (!tokenRes.ok) {
|
|
1068
|
+
const errJson = await tokenRes.json().catch(() => ({}));
|
|
1069
|
+
console.error("Google token error", errJson);
|
|
1070
|
+
return res.status(400).json({ ok: false, error: "Failed to exchange Google code" });
|
|
1071
|
+
}
|
|
1072
|
+
const tokenJson = await tokenRes.json();
|
|
1073
|
+
if (!tokenJson.id_token) {
|
|
1074
|
+
return res.status(400).json({ ok: false, error: "Missing id_token from Google" });
|
|
1075
|
+
}
|
|
1076
|
+
const decoded = jwt4.decode(tokenJson.id_token);
|
|
1077
|
+
const email2 = decoded?.email;
|
|
1078
|
+
if (!email2) {
|
|
1079
|
+
return res.status(400).json({ ok: false, error: "Google account has no email" });
|
|
1080
|
+
}
|
|
1081
|
+
const emailVerified = decoded.email_verified ?? true;
|
|
1082
|
+
const firstName = decoded.given_name || "";
|
|
1083
|
+
const lastName = decoded.family_name || "";
|
|
1084
|
+
let user = await OrgUser.findOne({ email: email2 }).lean();
|
|
1085
|
+
if (!user) {
|
|
1086
|
+
const created = await OrgUser.create({
|
|
1087
|
+
email: email2,
|
|
1088
|
+
firstName,
|
|
1089
|
+
lastName,
|
|
1090
|
+
emailVerified,
|
|
1091
|
+
roles: ["platform_user"],
|
|
1092
|
+
projectId: null,
|
|
1093
|
+
metadata: []
|
|
1094
|
+
// you can also store googleId: decoded.sub
|
|
1095
|
+
});
|
|
1096
|
+
user = created.toObject();
|
|
1097
|
+
}
|
|
1098
|
+
const tokens = generateTokens(user);
|
|
1099
|
+
setAuthCookies(res, tokens, cookieConfig);
|
|
1100
|
+
const redirectTo = state ? decodeURIComponent(state) : googleDefaultRedirect;
|
|
1101
|
+
res.redirect(redirectTo);
|
|
1102
|
+
} catch (err) {
|
|
1103
|
+
console.error("Google callback error", err);
|
|
1104
|
+
const redirectError = googleDefaultRedirect.includes("?") ? `${googleDefaultRedirect}&error=google_login_failed` : `${googleDefaultRedirect}?error=google_login_failed`;
|
|
1105
|
+
res.redirect(redirectError);
|
|
1106
|
+
}
|
|
1107
|
+
});
|
|
1108
|
+
r.get("/github", (req, res) => {
|
|
1109
|
+
const githubClientId = process.env.GITHUB_CLIENT_ID;
|
|
1110
|
+
const githubRedirectUri = process.env.GITHUB_REDIRECT_URI;
|
|
1111
|
+
if (!githubClientId || !githubRedirectUri) {
|
|
1112
|
+
return res.status(500).json({ error: "GitHub login not configured" });
|
|
1113
|
+
}
|
|
1114
|
+
const state = req.query.redirectTo ? encodeURIComponent(String(req.query.redirectTo)) : "";
|
|
1115
|
+
const params = new URLSearchParams({
|
|
1116
|
+
client_id: githubClientId,
|
|
1117
|
+
redirect_uri: githubRedirectUri,
|
|
1118
|
+
scope: "user:email",
|
|
1119
|
+
state,
|
|
1120
|
+
allow_signup: "true"
|
|
1121
|
+
});
|
|
1122
|
+
const url = `https://github.com/login/oauth/authorize?${params.toString()}`;
|
|
1123
|
+
res.redirect(url);
|
|
1124
|
+
});
|
|
1125
|
+
r.get("/github/callback", async (req, res) => {
|
|
1126
|
+
const githubClientId = process.env.GITHUB_CLIENT_ID;
|
|
1127
|
+
const githubClientSecret = process.env.GITHUB_CLIENT_SECRET;
|
|
1128
|
+
const githubRedirectUri = process.env.GITHUB_REDIRECT_URI;
|
|
1129
|
+
const githubDefaultRedirect = process.env.GITHUB_DEFAULT_REDIRECT || getFrontendBaseUrl(options) || "/";
|
|
1130
|
+
if (!githubClientId || !githubClientSecret || !githubRedirectUri) {
|
|
1131
|
+
return res.status(500).json({ error: "GitHub login not configured" });
|
|
1132
|
+
}
|
|
1133
|
+
const code = String(req.query.code || "");
|
|
1134
|
+
const state = req.query.state ? String(req.query.state) : "";
|
|
1135
|
+
if (!code) {
|
|
1136
|
+
return res.status(400).json({ ok: false, error: "Missing GitHub code" });
|
|
1137
|
+
}
|
|
1138
|
+
try {
|
|
1139
|
+
const tokenRes = await fetch(
|
|
1140
|
+
"https://github.com/login/oauth/access_token",
|
|
1141
|
+
{
|
|
1142
|
+
method: "POST",
|
|
1143
|
+
headers: {
|
|
1144
|
+
Accept: "application/json",
|
|
1145
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
1146
|
+
},
|
|
1147
|
+
body: new URLSearchParams({
|
|
1148
|
+
client_id: githubClientId,
|
|
1149
|
+
client_secret: githubClientSecret,
|
|
1150
|
+
code,
|
|
1151
|
+
redirect_uri: githubRedirectUri
|
|
1152
|
+
})
|
|
1153
|
+
}
|
|
1154
|
+
);
|
|
1155
|
+
const tokenJson = await tokenRes.json();
|
|
1156
|
+
if (!tokenJson.access_token) {
|
|
1157
|
+
console.error("GitHub token error:", tokenJson);
|
|
1158
|
+
return res.status(400).json({ ok: false, error: "Failed to get GitHub access token" });
|
|
1159
|
+
}
|
|
1160
|
+
const accessToken = tokenJson.access_token;
|
|
1161
|
+
const userRes = await fetch("https://api.github.com/user", {
|
|
1162
|
+
headers: {
|
|
1163
|
+
Authorization: `Bearer ${accessToken}`,
|
|
1164
|
+
Accept: "application/vnd.github+json"
|
|
1165
|
+
}
|
|
1166
|
+
});
|
|
1167
|
+
const githubUser = await userRes.json();
|
|
1168
|
+
const emailRes = await fetch("https://api.github.com/user/emails", {
|
|
1169
|
+
headers: {
|
|
1170
|
+
Authorization: `Bearer ${accessToken}`,
|
|
1171
|
+
Accept: "application/vnd.github+json"
|
|
1172
|
+
}
|
|
1173
|
+
});
|
|
1174
|
+
const emails = await emailRes.json();
|
|
1175
|
+
const primaryEmail = emails?.find(
|
|
1176
|
+
(e) => e.primary && e.verified
|
|
1177
|
+
)?.email;
|
|
1178
|
+
if (!primaryEmail) {
|
|
1179
|
+
return res.status(400).json({
|
|
1180
|
+
ok: false,
|
|
1181
|
+
error: "GitHub account has no verified email"
|
|
1182
|
+
});
|
|
1183
|
+
}
|
|
1184
|
+
const firstName = githubUser.name?.split(" ")[0] || "";
|
|
1185
|
+
const lastName = githubUser.name?.split(" ").slice(1).join(" ") || "";
|
|
1186
|
+
let user = await OrgUser.findOne({ email: primaryEmail }).lean();
|
|
1187
|
+
if (!user) {
|
|
1188
|
+
const created = await OrgUser.create({
|
|
1189
|
+
email: primaryEmail,
|
|
1190
|
+
firstName,
|
|
1191
|
+
lastName,
|
|
1192
|
+
emailVerified: true,
|
|
1193
|
+
roles: ["platform_user"],
|
|
1194
|
+
projectId: null,
|
|
1195
|
+
metadata: [],
|
|
1196
|
+
githubId: githubUser.id
|
|
1197
|
+
});
|
|
1198
|
+
user = created.toObject();
|
|
1199
|
+
}
|
|
1200
|
+
const tokens = generateTokens(user);
|
|
1201
|
+
setAuthCookies(res, tokens, cookieConfig);
|
|
1202
|
+
const redirectTo = state ? decodeURIComponent(state) : githubDefaultRedirect;
|
|
1203
|
+
res.redirect(redirectTo);
|
|
1204
|
+
} catch (err) {
|
|
1205
|
+
console.error("GitHub callback error:", err);
|
|
1206
|
+
const redirectError = githubDefaultRedirect.includes("?") ? `${githubDefaultRedirect}&error=github_login_failed` : `${githubDefaultRedirect}?error=github_login_failed`;
|
|
1207
|
+
res.redirect(redirectError);
|
|
1208
|
+
}
|
|
1038
1209
|
});
|
|
1039
1210
|
r.get("/get-users", async (req, res) => {
|
|
1040
1211
|
const user = await OrgUser.find({ projectId: req.query.projectId }).lean();
|