feat(auth): expose ADMIN_EMAILS via /api/config/auth and grant SPA admin when email matches

Made-with: Cursor
This commit is contained in:
dosangyoon
2026-03-23 10:31:15 +09:00
parent ea104aef6e
commit 899cdf14d0
4 changed files with 70 additions and 11 deletions

View File

@@ -238,8 +238,7 @@ app.get("/api/config/auth", async (_req, res) => {
value: {
auth0: { domain: AUTH0_DOMAIN, clientId: AUTH0_CLIENT_ID },
connections: { google: AUTH0_GOOGLE_CONNECTION },
// Deprecated: admin is stored per-user in DB (ncue_user.is_admin)
adminEmails: [],
adminEmails: Array.from(ADMIN_EMAILS).sort(),
},
updated_at: null,
source: "env",
@@ -249,11 +248,19 @@ app.get("/api/config/auth", async (_req, res) => {
await ensureConfigTable();
const r = await pool.query(`select value, updated_at from public.${CONFIG_TABLE} where key = $1`, ["auth"]);
if (!r.rows?.length) return res.status(404).json({ ok: false, error: "not_set" });
const v = r.rows[0].value || {};
let v = r.rows[0].value || {};
if (typeof v !== "object" || v === null) v = {};
// legacy: allowedEmails -> adminEmails
if (v && typeof v === "object" && !v.adminEmails && Array.isArray(v.allowedEmails)) {
v.adminEmails = v.allowedEmails;
if (!v.adminEmails && Array.isArray(v.allowedEmails)) v = { ...v, adminEmails: v.allowedEmails };
const merged = new Set(ADMIN_EMAILS);
const ae = v.adminEmails;
if (Array.isArray(ae)) {
for (const x of ae) {
const s = String(x || "").trim().toLowerCase();
if (s) merged.add(s);
}
}
v = { ...v, adminEmails: Array.from(merged).sort() };
res.json({ ok: true, value: v, updated_at: r.rows[0].updated_at, source: "db" });
} catch (e) {
res.status(500).json({ ok: false, error: "server_error" });