Complete Supabase Auth implementation with OAuth, email/password, and session management for Google Antigravity.
# Supabase Auth SSR Patterns for Google Antigravity
Supabase provides a powerful authentication system that integrates seamlessly with Next.js. Google Antigravity's Gemini 3 helps you implement secure authentication flows with OAuth providers, email/password, and session management.
## Supabase Client Setup
Configure the Supabase client for both server and client components:
```typescript
// lib/supabase/client.ts
import { createBrowserClient } from "@supabase/ssr";
export function createClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);
}
```
```typescript
// lib/supabase/server.ts
import { createServerClient } from "@supabase/ssr";
import { cookies } from "next/headers";
export async function createClient() {
const cookieStore = await cookies();
return createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return cookieStore.getAll();
},
setAll(cookiesToSet) {
try {
cookiesToSet.forEach(({ name, value, options }) =>
cookieStore.set(name, value, options)
);
} catch {
// Server component - cannot set cookies
}
},
},
}
);
}
```
## Middleware for Session Refresh
Keep sessions fresh with middleware:
```typescript
// middleware.ts
import { createServerClient } from "@supabase/ssr";
import { NextResponse, type NextRequest } from "next/server";
export async function middleware(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, options }) =>
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 && request.nextUrl.pathname.startsWith("/dashboard")) {
const url = request.nextUrl.clone();
url.pathname = "/login";
return NextResponse.redirect(url);
}
if (user && ["/login", "/signup"].includes(request.nextUrl.pathname)) {
const url = request.nextUrl.clone();
url.pathname = "/dashboard";
return NextResponse.redirect(url);
}
return supabaseResponse;
}
export const config = {
matcher: [
"/((?!_next/static|_next/image|favicon.ico|.*\.(?:svg|png|jpg|jpeg|gif|webp)$).*)",
],
};
```
## Email/Password Authentication
Implement sign up and sign in with email:
```typescript
// app/actions/auth.ts
"use server";
import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import { createClient } from "@/lib/supabase/server";
export async function signUp(formData: FormData) {
const supabase = await createClient();
const email = formData.get("email") as string;
const password = formData.get("password") as string;
const name = formData.get("name") as string;
const { error } = await supabase.auth.signUp({
email,
password,
options: {
data: {
full_name: name,
},
emailRedirectTo: `${process.env.NEXT_PUBLIC_SITE_URL}/auth/callback`,
},
});
if (error) {
return { error: error.message };
}
return { message: "Check your email to confirm your account" };
}
export async function signIn(formData: FormData) {
const supabase = await createClient();
const email = formData.get("email") as string;
const password = formData.get("password") as string;
const { error } = await supabase.auth.signInWithPassword({
email,
password,
});
if (error) {
return { error: error.message };
}
revalidatePath("/", "layout");
redirect("/dashboard");
}
export async function signOut() {
const supabase = await createClient();
await supabase.auth.signOut();
revalidatePath("/", "layout");
redirect("/");
}
```
## OAuth Provider Authentication
Add social login with Google, GitHub, etc:
```typescript
// app/actions/oauth.ts
"use server";
import { redirect } from "next/navigation";
import { createClient } from "@/lib/supabase/server";
export async function signInWithGoogle() {
const supabase = await createClient();
const { data, error } = await supabase.auth.signInWithOAuth({
provider: "google",
options: {
redirectTo: `${process.env.NEXT_PUBLIC_SITE_URL}/auth/callback`,
queryParams: {
access_type: "offline",
prompt: "consent",
},
},
});
if (error) {
return { error: error.message };
}
redirect(data.url);
}
export async function signInWithGitHub() {
const supabase = await createClient();
const { data, error } = await supabase.auth.signInWithOAuth({
provider: "github",
options: {
redirectTo: `${process.env.NEXT_PUBLIC_SITE_URL}/auth/callback`,
},
});
if (error) {
return { error: error.message };
}
redirect(data.url);
}
```
## OAuth Callback Handler
Handle the OAuth callback:
```typescript
// app/auth/callback/route.ts
import { createClient } from "@/lib/supabase/server";
import { NextResponse } from "next/server";
export async function GET(request: Request) {
const { searchParams, origin } = new URL(request.url);
const code = searchParams.get("code");
const next = searchParams.get("next") ?? "/dashboard";
if (code) {
const supabase = await createClient();
const { error } = await supabase.auth.exchangeCodeForSession(code);
if (!error) {
return NextResponse.redirect(`${origin}${next}`);
}
}
return NextResponse.redirect(`${origin}/auth/error`);
}
```
## Auth Context for Client Components
Create a client-side auth context:
```typescript
// contexts/AuthContext.tsx
"use client";
import { createContext, useContext, useEffect, useState } from "react";
import { User, Session } from "@supabase/supabase-js";
import { createClient } from "@/lib/supabase/client";
interface AuthContextType {
user: User | null;
session: Session | null;
loading: boolean;
}
const AuthContext = createContext<AuthContextType>({
user: null,
session: null,
loading: true,
});
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [user, setUser] = useState<User | null>(null);
const [session, setSession] = useState<Session | null>(null);
const [loading, setLoading] = useState(true);
const supabase = createClient();
useEffect(() => {
const {
data: { subscription },
} = supabase.auth.onAuthStateChange((event, session) => {
setSession(session);
setUser(session?.user ?? null);
setLoading(false);
});
return () => subscription.unsubscribe();
}, [supabase.auth]);
return (
<AuthContext.Provider value={{ user, session, loading }}>
{children}
</AuthContext.Provider>
);
}
export const useAuth = () => useContext(AuthContext);
```
## Login Form Component
Build a complete login form:
```typescript
// components/LoginForm.tsx
"use client";
import { useState } from "react";
import { signIn, signInWithGoogle, signInWithGitHub } from "@/app/actions/auth";
export function LoginForm() {
const [error, setError] = useState<string | null>(null);
const [loading, setLoading] = useState(false);
const handleSubmit = async (formData: FormData) => {
setLoading(true);
setError(null);
const result = await signIn(formData);
if (result?.error) {
setError(result.error);
setLoading(false);
}
};
return (
<div className="max-w-md mx-auto">
<form action={handleSubmit} className="space-y-4">
{error && (
<div className="p-3 bg-red-100 text-red-700 rounded">
{error}
</div>
)}
<div>
<label htmlFor="email">Email</label>
<input
type="email"
name="email"
id="email"
required
className="w-full px-3 py-2 border rounded"
/>
</div>
<div>
<label htmlFor="password">Password</label>
<input
type="password"
name="password"
id="password"
required
className="w-full px-3 py-2 border rounded"
/>
</div>
<button
type="submit"
disabled={loading}
className="w-full py-2 bg-blue-600 text-white rounded"
>
{loading ? "Signing in..." : "Sign In"}
</button>
</form>
<div className="mt-6 space-y-2">
<button
onClick={() => signInWithGoogle()}
className="w-full py-2 border rounded flex items-center justify-center gap-2"
>
Continue with Google
</button>
<button
onClick={() => signInWithGitHub()}
className="w-full py-2 border rounded flex items-center justify-center gap-2"
>
Continue with GitHub
</button>
</div>
</div>
);
}
```
## Best Practices
1. **Always validate on server** - Never trust client-side auth state alone
2. **Use httpOnly cookies** - Supabase SSR handles this automatically
3. **Implement proper redirects** - Handle callback URLs securely
4. **Refresh sessions proactively** - Use middleware to keep sessions fresh
5. **Add rate limiting** - Protect auth endpoints from brute force
Supabase Auth with Google Antigravity enables secure, scalable authentication with intelligent code generation and best practices.This supabase prompt is ideal for developers working on:
By using this prompt, you can save hours of manual coding and ensure best practices are followed from the start. It's particularly valuable for teams looking to maintain consistency across their supabase implementations.
Yes! All prompts on Antigravity AI Directory are free to use for both personal and commercial projects. No attribution required, though it's always appreciated.
This prompt works excellently with Claude, ChatGPT, Cursor, GitHub Copilot, and other modern AI coding assistants. For best results, use models with large context windows.
You can modify the prompt by adding specific requirements, constraints, or preferences. For supabase projects, consider mentioning your framework version, coding style, and any specific libraries you're using.