completionId: cgen-ef43d215ec7048b89ea5bcb5d94e9a0f
cgen-ef43d215ec7048b89ea5bcb5d94e9a0f
This commit is contained in:
parent
b3c2c6146d
commit
06930aee74
1 changed files with 121 additions and 0 deletions
121
server/index.ts
121
server/index.ts
|
|
@ -448,6 +448,127 @@ export function createServer() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Discord OAuth: callback handler
|
||||||
|
app.post("/api/discord/oauth/callback", async (req, res) => {
|
||||||
|
const { code, state } = (req.body || {}) as {
|
||||||
|
code?: string;
|
||||||
|
state?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!code) {
|
||||||
|
return res.status(400).json({ error: "Authorization code is required" });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const clientId = process.env.VITE_DISCORD_CLIENT_ID || "578971245454950421";
|
||||||
|
const clientSecret = process.env.DISCORD_CLIENT_SECRET;
|
||||||
|
const redirectUri =
|
||||||
|
process.env.DISCORD_REDIRECT_URI ||
|
||||||
|
`${process.env.PUBLIC_BASE_URL || process.env.SITE_URL || "http://localhost:5173"}/discord/callback`;
|
||||||
|
|
||||||
|
if (!clientSecret) {
|
||||||
|
console.warn(
|
||||||
|
"[Discord OAuth] DISCORD_CLIENT_SECRET not configured, skipping token exchange",
|
||||||
|
);
|
||||||
|
return res.json({
|
||||||
|
ok: true,
|
||||||
|
access_token: null,
|
||||||
|
message: "Discord auth configured for Activity context only",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exchange authorization code for access token
|
||||||
|
const tokenResponse = await fetch("https://discord.com/api/oauth2/token", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
|
},
|
||||||
|
body: new URLSearchParams({
|
||||||
|
client_id: clientId,
|
||||||
|
client_secret: clientSecret,
|
||||||
|
code,
|
||||||
|
grant_type: "authorization_code",
|
||||||
|
redirect_uri: redirectUri,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!tokenResponse.ok) {
|
||||||
|
const errorData = await tokenResponse.text();
|
||||||
|
console.error("[Discord OAuth] Token exchange failed:", {
|
||||||
|
status: tokenResponse.status,
|
||||||
|
error: errorData,
|
||||||
|
});
|
||||||
|
return res.status(400).json({
|
||||||
|
error: "Failed to exchange authorization code",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const tokenData = await tokenResponse.json();
|
||||||
|
|
||||||
|
// Get Discord user information
|
||||||
|
const userResponse = await fetch("https://discord.com/api/users/@me", {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${tokenData.access_token}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!userResponse.ok) {
|
||||||
|
return res.status(400).json({
|
||||||
|
error: "Failed to retrieve Discord user information",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const discordUser = await userResponse.json();
|
||||||
|
|
||||||
|
// Optionally: create or update Supabase user linked to Discord account
|
||||||
|
if (adminSupabase && discordUser.id) {
|
||||||
|
try {
|
||||||
|
// Check if user with Discord ID exists
|
||||||
|
const { data: existingUser } = await adminSupabase
|
||||||
|
.from("user_profiles")
|
||||||
|
.select("id")
|
||||||
|
.eq("discord_id", discordUser.id)
|
||||||
|
.maybeSingle();
|
||||||
|
|
||||||
|
if (!existingUser && discordUser.email) {
|
||||||
|
// Attempt to find by email
|
||||||
|
const { data: userByEmail } = await adminSupabase
|
||||||
|
.from("user_profiles")
|
||||||
|
.select("id")
|
||||||
|
.eq("email", discordUser.email)
|
||||||
|
.maybeSingle();
|
||||||
|
|
||||||
|
if (userByEmail) {
|
||||||
|
// Update existing user with Discord ID
|
||||||
|
await adminSupabase
|
||||||
|
.from("user_profiles")
|
||||||
|
.update({ discord_id: discordUser.id })
|
||||||
|
.eq("id", userByEmail.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.warn("[Discord OAuth] Failed to link Discord ID:", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.json({
|
||||||
|
ok: true,
|
||||||
|
access_token: tokenData.access_token,
|
||||||
|
discord_user: {
|
||||||
|
id: discordUser.id,
|
||||||
|
username: discordUser.username,
|
||||||
|
avatar: discordUser.avatar,
|
||||||
|
email: discordUser.email,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (e: any) {
|
||||||
|
console.error("[Discord OAuth] Error:", e);
|
||||||
|
return res.status(500).json({
|
||||||
|
error: e?.message || "Internal server error during Discord OAuth",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Site settings (admin-managed)
|
// Site settings (admin-managed)
|
||||||
app.get("/api/site-settings", async (req, res) => {
|
app.get("/api/site-settings", async (req, res) => {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue