- Published on
Using Supabase Types in Your TypeScript Project
- Authors
- Name
- Shelton Ma
1. Generating TypeScript Types
Leverage Supabase's TypeScript types for strong type safety in your application. Refer to the Generating TypeScript Types guide for details.
Save in src/database.types.ts, create client:
// src/utils/supabase/client.ts
import { Database } from "@/database.types";
import { createBrowserClient } from "@supabase/ssr";
export function createClient() {
return createBrowserClient<Database>(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);
}
2. Setting Up Server-Side Authentication in Next.js
Setting up Server-Side Auth for Next.js
Step 1: Install Required Packages
Install Supabase libraries for client and server-side rendering:
pnpm add @supabase/supabase-js @supabase/ssr
Step 2: Configure Client and Middleware
src/utils/supabase/client.ts
src/utils/supabase/server.ts
src/middleware.ts
import { createServerClient } from "@supabase/ssr"; import { NextResponse, type NextRequest } from "next/server"; const isPublicRoute = (request: NextRequest) => { const publicRoutes = [ /^\/$/, // Root path /^\/sign-in(.*)/, // Sign-in path /^\/sign-up(.*)/, // Sign-up path /^\/error$/, // Error page ]; return publicRoutes.some((route) => route.test(request.nextUrl.pathname)); }; export async function updateSession(request: NextRequest) { let supabaseResponse = NextResponse.next({ request, }); const supabase = createServerClient( process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, { cookies: { getAll() { return request.cookies.getAll(); }, setAll(cookiesToSet) { cookiesToSet.forEach(({ name, value }) => request.cookies.set(name, value) ); supabaseResponse = NextResponse.next({ request, }); cookiesToSet.forEach(({ name, value, options }) => supabaseResponse.cookies.set(name, value, options) ); }, }, } ); const { data: { user }, } = await supabase.auth.getUser(); if (!user && !isPublicRoute(request)) { // no user, potentially respond by redirecting the user to the login page const url = request.nextUrl.clone(); url.pathname = "/sign-in"; return NextResponse.redirect(url); } return supabaseResponse; }
Step 3: Enable Email/Password Authentication
const onSignIn = async (values: z.infer<typeof formSchema>) => {
setLoading(true);
try {
const { data, error } = await createClient().auth.signInWithPassword({
email: values.email,
password: values.password,
});
if (error) {
form.setError("email", {
message: error.message || "An unexpected error occurred.",
});
return;
}
if (data?.user) {
window.location.href = "/dashboard";
} else {
form.setError("email", {
message: "Authentication failed. Please try again.",
});
}
} catch (error) {
toast.error(`Unexpected error during sign-in:, ${error}`);
form.setError("email", {
message: "An unexpected error occurred. Please try again later.",
});
} finally {
setLoading(false);
}
};
Step 4: Enable OAuth Authentication
signInWithOAuth
const handleOAuthLogin = async (provider: Provider) => { setLoading(true); // oauth login logic try { const { data, error } = await createClient().auth.signInWithOAuth({ provider: provider, options: { redirectTo: `${process.env.NEXT_PUBLIC_APP_URL}/callback` }, }); if (error) { setLoading(false); toast.error(error.message); return; } if (data?.url) { // Redirect the user to the GitHub login page window.location.href = data.url; } else { toast.error("Unexpected error: No redirect URL provided."); } } catch (e) { console.error(e); } finally { setLoading(false); } };
At the callback endpoint, handle the code exchange to save the user session.
// src/app/(auth)/callback/page.tsx export default function AuthCallbackPage() { const router = useRouter(); const searchParams = useSearchParams(); const code = searchParams.get("code"); useEffect(() => { const handleCallback = async () => { const supabase = createClient(); const { data, error } = await supabase.auth.exchangeCodeForSession(code!); if (error) { console.error("Token Exchange Error", error); alert("Authentication failed. Please try again."); router.push("/"); } if (data?.session?.access_token) { supabase.auth.setSession(data.session); console.log("User Logged In"); // Redirect to your desired page after login router.push("/dashboard"); } }; // Only run if router query has code if (code) handleCallback(); }, [router, code]); return ( <div className="flex flex-col items-center justify-center h-screen gap-4"> <p className="text-xl ">Loading...</p> <Loader className="size-12 animate-spin" /> </div> ); }
Step 5: Check User Session
useEffect(() => {
const checkSession = async () => {
const {
data: { session },
error,
} = await createClient().auth.getSession();
if (session) {
// User is authenticated
router.replace("/dashboard");
} else if (error) {
toast.error(`Error retrieving session:, ${error.message}`);
}
};
checkSession();
}, [router]);