diff --git a/src/app/api/auth/callback/route.ts b/src/app/api/auth/callback/route.ts new file mode 100644 index 0000000..4ecd122 --- /dev/null +++ b/src/app/api/auth/callback/route.ts @@ -0,0 +1,22 @@ +// app/auth/callback/route.ts +import { NextRequest, NextResponse } from "next/server"; +import { createClient } from "@/lib/supabase/server"; + +export async function GET(req: NextRequest) { + const code = req.nextUrl.searchParams.get("code"); + + if (!code) { + return NextResponse.json({ error: "code param required" }, { status: 400 }); + } + + const supabase = await createClient(); + + const { error } = await supabase.auth.exchangeCodeForSession(code); + + if (error) { + console.error(error); + return NextResponse.json({ error: error.message }, { status: 500 }); + } + + return NextResponse.redirect(new URL("/runs", req.url)); +} diff --git a/src/components/auth/ContinueWith.tsx b/src/components/auth/ContinueWith.tsx index d3c85d1..b5c2cef 100644 --- a/src/components/auth/ContinueWith.tsx +++ b/src/components/auth/ContinueWith.tsx @@ -6,7 +6,7 @@ import { signInWithGitHub } from "@/modules/account/actions"; export default function ContinueWith() { const continueWithGithub = () => { - signInWithGitHub(); + signInWithGitHub(window.location.origin); }; const continueWithGoogle = () => {}; diff --git a/src/lib/supabase.ts b/src/lib/supabase/server.ts similarity index 55% rename from src/lib/supabase.ts rename to src/lib/supabase/server.ts index ae00085..c9431c0 100644 --- a/src/lib/supabase.ts +++ b/src/lib/supabase/server.ts @@ -24,3 +24,25 @@ export async function createClient() { }, ); } + +export async function createClientApi() { + const cookieStore = await cookies(); + + return createServerClient( + process.env.SUPABASE_URL!, + process.env.SUPABASE_SECRET_KEY!, + { + cookies: { + get(name: string) { + return cookieStore.get(name)?.value; + }, + set(name: string, value: string, options: CookieOptions) { + cookieStore.set(name, value, options); + }, + remove(name: string, options: CookieOptions) { + cookieStore.set(name, "", options); + }, + }, + }, + ); +} diff --git a/src/modules/account/actions.ts b/src/modules/account/actions.ts index a2e7820..c9eb583 100644 --- a/src/modules/account/actions.ts +++ b/src/modules/account/actions.ts @@ -1,14 +1,17 @@ "use server"; import * as Core from "./core"; -import { createClient } from "@/lib/supabase"; +import { createClient } from "@/lib/supabase/server"; import { redirect } from "next/navigation"; -export async function signInWithGitHub() { +export async function signInWithGitHub(origin: string) { const supabase = await createClient(); const { data, error } = await supabase.auth.signInWithOAuth({ provider: "github", + options: { + redirectTo: `${origin}/api/auth/callback`, + }, }); if (error) { @@ -19,6 +22,16 @@ export async function signInWithGitHub() { return redirect(data.url); } +export async function getSession() { + const supabase = await createClient(); + + try { + return await Core.getSession(supabase); + } catch { + return redirect("/login"); + } +} + export async function signOut() { const supabase = await createClient(); diff --git a/src/modules/account/core.ts b/src/modules/account/core.ts index 7edcfc7..7d56432 100644 --- a/src/modules/account/core.ts +++ b/src/modules/account/core.ts @@ -4,6 +4,22 @@ import { SupabaseClient, User } from "@supabase/supabase-js"; import "server-only"; import { UserProfile } from "../user/types"; +export async function signInWithGitHub(supabase: SupabaseClient) { + const { data, error } = await supabase.auth.signInWithOAuth({ + provider: "github", + options: { + redirectTo: `/auth/callback`, + }, + }); + + if (error) { + console.error(error); + throw error; + } + + return data.url; +} + export async function getProfile( supabase: SupabaseClient, user: User, @@ -36,10 +52,11 @@ export async function getGithubProfile( .from("profiles") .insert({ id: user.id, - username: user.user_metadata.login || null, - full_name: user.user_metadata.name || null, + username: user.user_metadata.user_name || `user_${user.id.slice(0, 6)}`, avatar_url: user.user_metadata.avatar_url || null, - }) + bio: "", + created_at: new Date(), + } satisfies UserProfile) .select() .single(); @@ -52,17 +69,26 @@ export async function getSession( supabase: SupabaseClient, ): Promise<[User, UserProfile]> { const { - data: { session }, + data: { user }, error: sessionError, - } = await supabase.auth.getSession(); + } = await supabase.auth.getUser(); - if (sessionError || !session?.user) { + if (sessionError || !user) { throw new Error("No authenticated user found"); } - const user = session.user; - const profile = await getProfile(supabase, user); return [user, profile]; } + +export async function getSessionRedirect( + supabase: SupabaseClient, + redirect: (s: string) => void, +): Promise<[User, UserProfile] | undefined> { + try { + return await getSession(supabase); + } catch { + redirect("/login"); + } +} diff --git a/src/modules/live-run/actions.ts b/src/modules/live-run/actions.ts index 221d8eb..daf80a1 100644 --- a/src/modules/live-run/actions.ts +++ b/src/modules/live-run/actions.ts @@ -1,9 +1,16 @@ "use server"; +import { createClient } from "@/lib/supabase/server"; +import { getSession, getSessionRedirect } from "../account/core"; import * as Core from "./core"; import { Run } from "./types"; +import { redirect } from "next/navigation"; export async function getLiveRuns(): Promise { + const supabase = await createClient(); + + const _ = await getSession(supabase); + return [ { id: 1, diff --git a/src/modules/user/types.ts b/src/modules/user/types.ts index 4e35545..39d5758 100644 --- a/src/modules/user/types.ts +++ b/src/modules/user/types.ts @@ -1,6 +1,7 @@ export interface UserProfile { id: string; username: string; - full_name: string; avatar_url: string; + bio: string; + created_at: Date; }