Revert callback endpoint to redirect flow

cgen-c9eadecac65f4661a7c7bf99445f2ca5
This commit is contained in:
Builder.io 2025-11-09 08:18:50 +00:00
parent d58f467603
commit a622df780d

View file

@ -20,14 +20,19 @@ interface DiscordTokenResponse {
} }
export default async function handler(req: any, res: any) { export default async function handler(req: any, res: any) {
if (req.method !== "POST") { if (req.method !== "GET") {
return res.status(405).json({ error: "Method not allowed" }); return res.status(405).json({ error: "Method not allowed" });
} }
const { code, state } = req.body; const { code, state, error } = req.query;
// Handle Discord error
if (error) {
return res.redirect(`/login?error=${error}`);
}
if (!code) { if (!code) {
return res.status(400).json({ message: "No authorization code provided" }); return res.redirect("/login?error=no_code");
} }
const clientId = process.env.DISCORD_CLIENT_ID; const clientId = process.env.DISCORD_CLIENT_ID;
@ -37,36 +42,31 @@ export default async function handler(req: any, res: any) {
if (!clientId || !clientSecret || !supabaseUrl || !supabaseServiceRole) { if (!clientId || !clientSecret || !supabaseUrl || !supabaseServiceRole) {
console.error("[Discord OAuth] Missing environment variables"); console.error("[Discord OAuth] Missing environment variables");
return res.status(500).json({ message: "Server configuration error" }); return res.redirect("/login?error=config");
} }
try { try {
const redirectUri = `${process.env.VITE_API_BASE || "https://aethex.dev"}/api/discord/oauth/callback`; const redirectUri = `${process.env.VITE_API_BASE || "https://aethex.dev"}/api/discord/oauth/callback`;
// Exchange code for access token // Exchange code for access token
const tokenResponse = await fetch( const tokenResponse = await fetch("https://discord.com/api/v10/oauth2/token", {
"https://discord.com/api/v10/oauth2/token", method: "POST",
{ headers: {
method: "POST", "Content-Type": "application/x-www-form-urlencoded",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: new URLSearchParams({
client_id: clientId,
client_secret: clientSecret,
grant_type: "authorization_code",
code,
redirect_uri: redirectUri,
}).toString(),
}, },
); body: new URLSearchParams({
client_id: clientId,
client_secret: clientSecret,
grant_type: "authorization_code",
code,
redirect_uri: redirectUri,
}).toString(),
});
if (!tokenResponse.ok) { if (!tokenResponse.ok) {
const errorData = await tokenResponse.json(); const errorData = await tokenResponse.json();
console.error("[Discord OAuth] Token exchange failed:", errorData); console.error("[Discord OAuth] Token exchange failed:", errorData);
return res.status(400).json({ return res.redirect("/login?error=token_exchange");
message: "Failed to authenticate with Discord. Please try again.",
});
} }
const tokenData: DiscordTokenResponse = await tokenResponse.json(); const tokenData: DiscordTokenResponse = await tokenResponse.json();
@ -80,9 +80,7 @@ export default async function handler(req: any, res: any) {
if (!userResponse.ok) { if (!userResponse.ok) {
console.error("[Discord OAuth] User fetch failed:", userResponse.status); console.error("[Discord OAuth] User fetch failed:", userResponse.status);
return res.status(400).json({ return res.redirect("/login?error=user_fetch");
message: "Failed to fetch Discord profile. Please try again.",
});
} }
const discordUser: DiscordUser = await userResponse.json(); const discordUser: DiscordUser = await userResponse.json();
@ -117,49 +115,38 @@ export default async function handler(req: any, res: any) {
} else { } else {
// Create new user // Create new user
// First create auth user // First create auth user
const { data: authData, error: authError } = const { data: authData, error: authError } = await supabase.auth.admin.createUser({
await supabase.auth.admin.createUser({ email: discordUser.email,
email: discordUser.email, email_confirm: true,
email_confirm: true, user_metadata: {
user_metadata: { full_name: discordUser.username,
full_name: discordUser.username, avatar_url: discordUser.avatar
avatar_url: discordUser.avatar ? `https://cdn.discordapp.com/avatars/${discordUser.id}/${discordUser.avatar}.png`
? `https://cdn.discordapp.com/avatars/${discordUser.id}/${discordUser.avatar}.png` : null,
: null, },
}, });
});
if (authError || !authData.user) { if (authError || !authData.user) {
console.error( console.error("[Discord OAuth] Auth user creation failed:", authError);
"[Discord OAuth] Auth user creation failed:", return res.redirect("/login?error=auth_create");
authError,
);
return res.status(500).json({ message: "Failed to create account" });
} }
userId = authData.user.id; userId = authData.user.id;
isNewUser = true; isNewUser = true;
// Create user profile // Create user profile
const { error: profileError } = await supabase const { error: profileError } = await supabase.from("user_profiles").insert({
.from("user_profiles") id: userId,
.insert({ email: discordUser.email,
id: userId, full_name: discordUser.username,
email: discordUser.email, avatar_url: discordUser.avatar
full_name: discordUser.username, ? `https://cdn.discordapp.com/avatars/${discordUser.id}/${discordUser.avatar}.png`
avatar_url: discordUser.avatar : null,
? `https://cdn.discordapp.com/avatars/${discordUser.id}/${discordUser.avatar}.png` });
: null,
});
if (profileError) { if (profileError) {
console.error( console.error("[Discord OAuth] Profile creation failed:", profileError);
"[Discord OAuth] Profile creation failed:", return res.redirect("/login?error=profile_create");
profileError,
);
return res
.status(500)
.json({ message: "Failed to create user profile" });
} }
} }
} }
@ -173,20 +160,17 @@ export default async function handler(req: any, res: any) {
if (linkError) { if (linkError) {
console.error("[Discord OAuth] Link creation failed:", linkError); console.error("[Discord OAuth] Link creation failed:", linkError);
return res return res.redirect("/login?error=link_create");
.status(500)
.json({ message: "Failed to link Discord account" });
} }
// Generate session token // Generate session token
const { data: sessionData, error: sessionError } = const { data: sessionData, error: sessionError } = await supabase.auth.admin.createSession({
await supabase.auth.admin.createSession({ user_id: userId,
user_id: userId, });
});
if (sessionError || !sessionData.session) { if (sessionError || !sessionData.session) {
console.error("[Discord OAuth] Session creation failed:", sessionError); console.error("[Discord OAuth] Session creation failed:", sessionError);
return res.status(500).json({ message: "Failed to create session" }); return res.redirect("/login?error=session_create");
} }
// Set session cookies // Set session cookies
@ -194,29 +178,22 @@ export default async function handler(req: any, res: any) {
const refreshTokenCookie = `sb-refresh-token=${sessionData.session.refresh_token}; Path=/; Secure; HttpOnly; SameSite=Lax; Max-Age=604800`; const refreshTokenCookie = `sb-refresh-token=${sessionData.session.refresh_token}; Path=/; Secure; HttpOnly; SameSite=Lax; Max-Age=604800`;
res.setHeader("Set-Cookie", [accessTokenCookie, refreshTokenCookie]); res.setHeader("Set-Cookie", [accessTokenCookie, refreshTokenCookie]);
res.setHeader("Content-Type", "application/json");
return res.status(200).json({ // Redirect to next page
success: true, const nextPath =
message: isNewUser state && typeof state === "string" && state.startsWith("/")
? "Account created successfully" ? state
: "Linked successfully", : isNewUser
session: { ? "/onboarding"
access_token: sessionData.session.access_token, : "/dashboard";
refresh_token: sessionData.session.refresh_token,
}, const redirectUrl = new URL(
user: { nextPath,
id: userId, process.env.VITE_API_BASE || "https://aethex.dev"
email: discordUser.email, );
full_name: discordUser.username, res.redirect(redirectUrl.toString());
discord_id: discordUser.id,
},
isNewUser,
});
} catch (error) { } catch (error) {
console.error("[Discord OAuth] Callback error:", error); console.error("[Discord OAuth] Callback error:", error);
res.status(500).json({ res.redirect("/login?error=unknown");
message: "An unexpected error occurred. Please try again.",
});
} }
} }