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/nest/index.cjs
CHANGED
|
@@ -40,24 +40,6 @@ var import_crypto = require("crypto");
|
|
|
40
40
|
var import_express = __toESM(require("express"), 1);
|
|
41
41
|
var import_jsonwebtoken4 = __toESM(require("jsonwebtoken"), 1);
|
|
42
42
|
|
|
43
|
-
// src/core/utils.ts
|
|
44
|
-
function baseProjectCookieOptionsFrom(cookie) {
|
|
45
|
-
const base = {
|
|
46
|
-
secure: cookie.secure ?? false,
|
|
47
|
-
sameSite: cookie.sameSite ?? "lax",
|
|
48
|
-
path: cookie.path ?? "/",
|
|
49
|
-
maxAge: cookie.maxAgeMs
|
|
50
|
-
};
|
|
51
|
-
if (cookie.domain) base.domain = cookie.domain;
|
|
52
|
-
return base;
|
|
53
|
-
}
|
|
54
|
-
function hasAnyRole(session, roles) {
|
|
55
|
-
if (!session || !session.roles || !Array.isArray(roles) || roles.length === 0) {
|
|
56
|
-
return false;
|
|
57
|
-
}
|
|
58
|
-
return roles.some((role) => session.roles.includes(role));
|
|
59
|
-
}
|
|
60
|
-
|
|
61
43
|
// src/config/loadConfig.ts
|
|
62
44
|
function loadConfig() {
|
|
63
45
|
return {
|
|
@@ -121,6 +103,37 @@ function isPlainObject(value) {
|
|
|
121
103
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
122
104
|
}
|
|
123
105
|
|
|
106
|
+
// src/core/utils.ts
|
|
107
|
+
function baseProjectCookieOptionsFrom(cookie) {
|
|
108
|
+
const base = {
|
|
109
|
+
secure: cookie.secure ?? false,
|
|
110
|
+
sameSite: cookie.sameSite ?? "lax",
|
|
111
|
+
path: cookie.path ?? "/",
|
|
112
|
+
maxAge: cookie.maxAgeMs
|
|
113
|
+
};
|
|
114
|
+
if (cookie.domain) base.domain = cookie.domain;
|
|
115
|
+
return base;
|
|
116
|
+
}
|
|
117
|
+
function buildClearCookieOptions(cookie) {
|
|
118
|
+
const opts = {
|
|
119
|
+
httpOnly: true,
|
|
120
|
+
// not strictly required but fine
|
|
121
|
+
secure: cookie.secure ?? false,
|
|
122
|
+
sameSite: cookie.sameSite ?? "lax",
|
|
123
|
+
path: cookie.path ?? "/"
|
|
124
|
+
};
|
|
125
|
+
if (cookie.domain) {
|
|
126
|
+
opts.domain = cookie.domain;
|
|
127
|
+
}
|
|
128
|
+
return opts;
|
|
129
|
+
}
|
|
130
|
+
function hasAnyRole(session, roles) {
|
|
131
|
+
if (!session || !session.roles || !Array.isArray(roles) || roles.length === 0) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
return roles.some((role) => session.roles.includes(role));
|
|
135
|
+
}
|
|
136
|
+
|
|
124
137
|
// src/core/roles.config.ts
|
|
125
138
|
var PLATFORM_ROLES = [
|
|
126
139
|
{
|
|
@@ -222,7 +235,7 @@ var MetadataSchema = new import_mongoose2.default.Schema(
|
|
|
222
235
|
);
|
|
223
236
|
var OrgUserSchema = new import_mongoose2.default.Schema(
|
|
224
237
|
{
|
|
225
|
-
id: { type: String, default: (0, import_uuid.v4)(), index: true },
|
|
238
|
+
id: { type: String, default: (0, import_uuid.v4)(), index: true, unique: true },
|
|
226
239
|
email: { type: String, required: true, unique: true },
|
|
227
240
|
firstName: { type: String, required: true },
|
|
228
241
|
lastName: { type: String, required: true },
|
|
@@ -442,6 +455,7 @@ var Invite = import_mongoose3.default.model("Invite", InviteSchema);
|
|
|
442
455
|
// src/services/auth-admin.service.ts
|
|
443
456
|
var import_bcrypt = __toESM(require("bcrypt"), 1);
|
|
444
457
|
var import_jsonwebtoken2 = __toESM(require("jsonwebtoken"), 1);
|
|
458
|
+
var import_uuid2 = require("uuid");
|
|
445
459
|
|
|
446
460
|
// src/models/client.model.ts
|
|
447
461
|
var import_mongoose4 = __toESM(require("mongoose"), 1);
|
|
@@ -511,14 +525,14 @@ var AuthAdminService = class {
|
|
|
511
525
|
async createUserInRealm(payload) {
|
|
512
526
|
const hashedPassword = payload.credentials?.[0]?.value ? await import_bcrypt.default.hash(payload.credentials[0].value, 10) : void 0;
|
|
513
527
|
const user = await OrgUser.create({
|
|
514
|
-
|
|
528
|
+
id: (0, import_uuid2.v4)(),
|
|
515
529
|
email: payload.email,
|
|
516
530
|
firstName: payload.firstName,
|
|
517
531
|
lastName: payload.lastName,
|
|
518
532
|
projectId: payload.projectId,
|
|
519
533
|
emailVerified: payload.emailVerified || false,
|
|
520
534
|
passwordHash: hashedPassword,
|
|
521
|
-
|
|
535
|
+
metadata: payload.metadata || []
|
|
522
536
|
});
|
|
523
537
|
return user;
|
|
524
538
|
}
|
|
@@ -606,29 +620,13 @@ var EmailService = class {
|
|
|
606
620
|
}
|
|
607
621
|
};
|
|
608
622
|
|
|
609
|
-
// src/utils/cookie.ts
|
|
610
|
-
function cookieOpts(isRefresh = false) {
|
|
611
|
-
const maxAge = isRefresh ? config.cookies.refreshTtlMs : config.cookies.accessTtlMs;
|
|
612
|
-
const secure = process.env.NODE_ENV === "production" ? process.env.COOKIE_SECURE ?? true : false;
|
|
613
|
-
return {
|
|
614
|
-
httpOnly: true,
|
|
615
|
-
secure,
|
|
616
|
-
sameSite: "none",
|
|
617
|
-
domain: process.env.COOKIE_DOMAIN,
|
|
618
|
-
maxAge
|
|
619
|
-
};
|
|
620
|
-
}
|
|
621
|
-
function clearOpts() {
|
|
622
|
-
const secure = process.env.NODE_ENV === "production" ? process.env.COOKIE_SECURE ?? true : false;
|
|
623
|
-
return {
|
|
624
|
-
domain: process.env.COOKIE_DOMAIN,
|
|
625
|
-
sameSite: "none",
|
|
626
|
-
secure
|
|
627
|
-
};
|
|
628
|
-
}
|
|
629
|
-
|
|
630
623
|
// src/express/auth.routes.ts
|
|
631
624
|
function createAuthRouter(options = {}) {
|
|
625
|
+
const googleClientId = process.env.GOOGLE_CLIENT_ID;
|
|
626
|
+
const googleClientSecret = process.env.GOOGLE_CLIENT_SECRET;
|
|
627
|
+
const googleRedirectUri = process.env.GOOGLE_REDIRECT_URI;
|
|
628
|
+
const googleDefaultRedirect = process.env.GOOGLE_DEFAULT_REDIRECT || getFrontendBaseUrl(options) || "/";
|
|
629
|
+
const isGoogleEnabled = !!googleClientId && !!googleClientSecret && !!googleRedirectUri;
|
|
632
630
|
if (options.config) {
|
|
633
631
|
configureAuthX(options.config);
|
|
634
632
|
}
|
|
@@ -653,8 +651,10 @@ function createAuthRouter(options = {}) {
|
|
|
653
651
|
);
|
|
654
652
|
r.post("/login", validateLogin, async (req, res) => {
|
|
655
653
|
const { email: emailAddress, password } = req.body || {};
|
|
654
|
+
console.log(emailAddress, password, "body");
|
|
656
655
|
try {
|
|
657
656
|
const user = await OrgUser.findOne({ email: emailAddress }).select("+password").lean();
|
|
657
|
+
console.log(user, "user");
|
|
658
658
|
if (!user) {
|
|
659
659
|
return res.status(400).json({
|
|
660
660
|
error: "Invalid email or password",
|
|
@@ -707,13 +707,13 @@ function createAuthRouter(options = {}) {
|
|
|
707
707
|
firstName,
|
|
708
708
|
lastName,
|
|
709
709
|
projectId,
|
|
710
|
-
credentials: [{ type: "password", value: password, temporary: false }]
|
|
710
|
+
credentials: [{ type: "password", value: password, temporary: false }],
|
|
711
|
+
metadata
|
|
711
712
|
});
|
|
712
713
|
await authAdmin.assignRealmRole(kcUser.id, "platform_user");
|
|
713
714
|
const user = await OrgUser.findOneAndUpdate(
|
|
714
715
|
{ email: kcUser.email },
|
|
715
716
|
{
|
|
716
|
-
id: kcUser.id,
|
|
717
717
|
email: kcUser.email,
|
|
718
718
|
firstName,
|
|
719
719
|
lastName,
|
|
@@ -753,8 +753,9 @@ function createAuthRouter(options = {}) {
|
|
|
753
753
|
return res.json(req.user || null);
|
|
754
754
|
});
|
|
755
755
|
r.post("/logout", async (_req, res) => {
|
|
756
|
-
|
|
757
|
-
res.clearCookie("
|
|
756
|
+
const clearOptions = buildClearCookieOptions(cookieConfig);
|
|
757
|
+
res.clearCookie("access_token", clearOptions);
|
|
758
|
+
res.clearCookie("refresh_token", clearOptions);
|
|
758
759
|
res.json({ ok: true });
|
|
759
760
|
});
|
|
760
761
|
r.put("/:userId/metadata", requireAuth(), async (req, res) => {
|
|
@@ -993,16 +994,186 @@ function createAuthRouter(options = {}) {
|
|
|
993
994
|
const user = await OrgUser.findOne({ email: req.query.email }).lean();
|
|
994
995
|
res.json(user || null);
|
|
995
996
|
});
|
|
996
|
-
r.get("/google",
|
|
997
|
-
|
|
997
|
+
r.get("/google", (req, res) => {
|
|
998
|
+
if (!isGoogleEnabled) {
|
|
999
|
+
return res.status(500).json({ error: "Google login not configured" });
|
|
1000
|
+
}
|
|
1001
|
+
const state = req.query.redirectTo ? encodeURIComponent(String(req.query.redirectTo)) : "";
|
|
1002
|
+
const params = new URLSearchParams({
|
|
1003
|
+
client_id: googleClientId,
|
|
1004
|
+
redirect_uri: googleRedirectUri,
|
|
1005
|
+
response_type: "code",
|
|
1006
|
+
scope: "openid email profile",
|
|
1007
|
+
access_type: "offline",
|
|
1008
|
+
prompt: "consent",
|
|
1009
|
+
state
|
|
1010
|
+
});
|
|
1011
|
+
const url = `https://accounts.google.com/o/oauth2/v2/auth?${params.toString()}`;
|
|
1012
|
+
res.redirect(url);
|
|
998
1013
|
});
|
|
999
|
-
r.get("/google/callback", async (
|
|
1000
|
-
|
|
1001
|
-
"
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
);
|
|
1005
|
-
|
|
1014
|
+
r.get("/google/callback", async (req, res) => {
|
|
1015
|
+
if (!isGoogleEnabled) {
|
|
1016
|
+
return res.status(500).json({ error: "Google login not configured" });
|
|
1017
|
+
}
|
|
1018
|
+
const code = String(req.query.code || "");
|
|
1019
|
+
const state = req.query.state ? String(req.query.state) : "";
|
|
1020
|
+
if (!code) {
|
|
1021
|
+
return res.status(400).json({ ok: false, error: "Missing authorization code" });
|
|
1022
|
+
}
|
|
1023
|
+
try {
|
|
1024
|
+
const tokenRes = await fetch("https://oauth2.googleapis.com/token", {
|
|
1025
|
+
method: "POST",
|
|
1026
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
1027
|
+
body: new URLSearchParams({
|
|
1028
|
+
code,
|
|
1029
|
+
client_id: googleClientId,
|
|
1030
|
+
client_secret: googleClientSecret,
|
|
1031
|
+
redirect_uri: googleRedirectUri,
|
|
1032
|
+
grant_type: "authorization_code"
|
|
1033
|
+
})
|
|
1034
|
+
});
|
|
1035
|
+
if (!tokenRes.ok) {
|
|
1036
|
+
const errJson = await tokenRes.json().catch(() => ({}));
|
|
1037
|
+
console.error("Google token error", errJson);
|
|
1038
|
+
return res.status(400).json({ ok: false, error: "Failed to exchange Google code" });
|
|
1039
|
+
}
|
|
1040
|
+
const tokenJson = await tokenRes.json();
|
|
1041
|
+
if (!tokenJson.id_token) {
|
|
1042
|
+
return res.status(400).json({ ok: false, error: "Missing id_token from Google" });
|
|
1043
|
+
}
|
|
1044
|
+
const decoded = import_jsonwebtoken4.default.decode(tokenJson.id_token);
|
|
1045
|
+
const email2 = decoded?.email;
|
|
1046
|
+
if (!email2) {
|
|
1047
|
+
return res.status(400).json({ ok: false, error: "Google account has no email" });
|
|
1048
|
+
}
|
|
1049
|
+
const emailVerified = decoded.email_verified ?? true;
|
|
1050
|
+
const firstName = decoded.given_name || "";
|
|
1051
|
+
const lastName = decoded.family_name || "";
|
|
1052
|
+
let user = await OrgUser.findOne({ email: email2 }).lean();
|
|
1053
|
+
if (!user) {
|
|
1054
|
+
const created = await OrgUser.create({
|
|
1055
|
+
email: email2,
|
|
1056
|
+
firstName,
|
|
1057
|
+
lastName,
|
|
1058
|
+
emailVerified,
|
|
1059
|
+
roles: ["platform_user"],
|
|
1060
|
+
projectId: null,
|
|
1061
|
+
metadata: []
|
|
1062
|
+
// you can also store googleId: decoded.sub
|
|
1063
|
+
});
|
|
1064
|
+
user = created.toObject();
|
|
1065
|
+
}
|
|
1066
|
+
const tokens = generateTokens(user);
|
|
1067
|
+
setAuthCookies(res, tokens, cookieConfig);
|
|
1068
|
+
const redirectTo = state ? decodeURIComponent(state) : googleDefaultRedirect;
|
|
1069
|
+
res.redirect(redirectTo);
|
|
1070
|
+
} catch (err) {
|
|
1071
|
+
console.error("Google callback error", err);
|
|
1072
|
+
const redirectError = googleDefaultRedirect.includes("?") ? `${googleDefaultRedirect}&error=google_login_failed` : `${googleDefaultRedirect}?error=google_login_failed`;
|
|
1073
|
+
res.redirect(redirectError);
|
|
1074
|
+
}
|
|
1075
|
+
});
|
|
1076
|
+
r.get("/github", (req, res) => {
|
|
1077
|
+
const githubClientId = process.env.GITHUB_CLIENT_ID;
|
|
1078
|
+
const githubRedirectUri = process.env.GITHUB_REDIRECT_URI;
|
|
1079
|
+
if (!githubClientId || !githubRedirectUri) {
|
|
1080
|
+
return res.status(500).json({ error: "GitHub login not configured" });
|
|
1081
|
+
}
|
|
1082
|
+
const state = req.query.redirectTo ? encodeURIComponent(String(req.query.redirectTo)) : "";
|
|
1083
|
+
const params = new URLSearchParams({
|
|
1084
|
+
client_id: githubClientId,
|
|
1085
|
+
redirect_uri: githubRedirectUri,
|
|
1086
|
+
scope: "user:email",
|
|
1087
|
+
state,
|
|
1088
|
+
allow_signup: "true"
|
|
1089
|
+
});
|
|
1090
|
+
const url = `https://github.com/login/oauth/authorize?${params.toString()}`;
|
|
1091
|
+
res.redirect(url);
|
|
1092
|
+
});
|
|
1093
|
+
r.get("/github/callback", async (req, res) => {
|
|
1094
|
+
const githubClientId = process.env.GITHUB_CLIENT_ID;
|
|
1095
|
+
const githubClientSecret = process.env.GITHUB_CLIENT_SECRET;
|
|
1096
|
+
const githubRedirectUri = process.env.GITHUB_REDIRECT_URI;
|
|
1097
|
+
const githubDefaultRedirect = process.env.GITHUB_DEFAULT_REDIRECT || getFrontendBaseUrl(options) || "/";
|
|
1098
|
+
if (!githubClientId || !githubClientSecret || !githubRedirectUri) {
|
|
1099
|
+
return res.status(500).json({ error: "GitHub login not configured" });
|
|
1100
|
+
}
|
|
1101
|
+
const code = String(req.query.code || "");
|
|
1102
|
+
const state = req.query.state ? String(req.query.state) : "";
|
|
1103
|
+
if (!code) {
|
|
1104
|
+
return res.status(400).json({ ok: false, error: "Missing GitHub code" });
|
|
1105
|
+
}
|
|
1106
|
+
try {
|
|
1107
|
+
const tokenRes = await fetch(
|
|
1108
|
+
"https://github.com/login/oauth/access_token",
|
|
1109
|
+
{
|
|
1110
|
+
method: "POST",
|
|
1111
|
+
headers: {
|
|
1112
|
+
Accept: "application/json",
|
|
1113
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
1114
|
+
},
|
|
1115
|
+
body: new URLSearchParams({
|
|
1116
|
+
client_id: githubClientId,
|
|
1117
|
+
client_secret: githubClientSecret,
|
|
1118
|
+
code,
|
|
1119
|
+
redirect_uri: githubRedirectUri
|
|
1120
|
+
})
|
|
1121
|
+
}
|
|
1122
|
+
);
|
|
1123
|
+
const tokenJson = await tokenRes.json();
|
|
1124
|
+
if (!tokenJson.access_token) {
|
|
1125
|
+
console.error("GitHub token error:", tokenJson);
|
|
1126
|
+
return res.status(400).json({ ok: false, error: "Failed to get GitHub access token" });
|
|
1127
|
+
}
|
|
1128
|
+
const accessToken = tokenJson.access_token;
|
|
1129
|
+
const userRes = await fetch("https://api.github.com/user", {
|
|
1130
|
+
headers: {
|
|
1131
|
+
Authorization: `Bearer ${accessToken}`,
|
|
1132
|
+
Accept: "application/vnd.github+json"
|
|
1133
|
+
}
|
|
1134
|
+
});
|
|
1135
|
+
const githubUser = await userRes.json();
|
|
1136
|
+
const emailRes = await fetch("https://api.github.com/user/emails", {
|
|
1137
|
+
headers: {
|
|
1138
|
+
Authorization: `Bearer ${accessToken}`,
|
|
1139
|
+
Accept: "application/vnd.github+json"
|
|
1140
|
+
}
|
|
1141
|
+
});
|
|
1142
|
+
const emails = await emailRes.json();
|
|
1143
|
+
const primaryEmail = emails?.find(
|
|
1144
|
+
(e) => e.primary && e.verified
|
|
1145
|
+
)?.email;
|
|
1146
|
+
if (!primaryEmail) {
|
|
1147
|
+
return res.status(400).json({
|
|
1148
|
+
ok: false,
|
|
1149
|
+
error: "GitHub account has no verified email"
|
|
1150
|
+
});
|
|
1151
|
+
}
|
|
1152
|
+
const firstName = githubUser.name?.split(" ")[0] || "";
|
|
1153
|
+
const lastName = githubUser.name?.split(" ").slice(1).join(" ") || "";
|
|
1154
|
+
let user = await OrgUser.findOne({ email: primaryEmail }).lean();
|
|
1155
|
+
if (!user) {
|
|
1156
|
+
const created = await OrgUser.create({
|
|
1157
|
+
email: primaryEmail,
|
|
1158
|
+
firstName,
|
|
1159
|
+
lastName,
|
|
1160
|
+
emailVerified: true,
|
|
1161
|
+
roles: ["platform_user"],
|
|
1162
|
+
projectId: null,
|
|
1163
|
+
metadata: [],
|
|
1164
|
+
githubId: githubUser.id
|
|
1165
|
+
});
|
|
1166
|
+
user = created.toObject();
|
|
1167
|
+
}
|
|
1168
|
+
const tokens = generateTokens(user);
|
|
1169
|
+
setAuthCookies(res, tokens, cookieConfig);
|
|
1170
|
+
const redirectTo = state ? decodeURIComponent(state) : githubDefaultRedirect;
|
|
1171
|
+
res.redirect(redirectTo);
|
|
1172
|
+
} catch (err) {
|
|
1173
|
+
console.error("GitHub callback error:", err);
|
|
1174
|
+
const redirectError = githubDefaultRedirect.includes("?") ? `${githubDefaultRedirect}&error=github_login_failed` : `${githubDefaultRedirect}?error=github_login_failed`;
|
|
1175
|
+
res.redirect(redirectError);
|
|
1176
|
+
}
|
|
1006
1177
|
});
|
|
1007
1178
|
r.get("/get-users", async (req, res) => {
|
|
1008
1179
|
const user = await OrgUser.find({ projectId: req.query.projectId }).lean();
|