--- title: "OAuth" description: "Sign in with Google, GitHub, and other OAuth providers." publishedAt: 2024-04-11 order: 3 status: "published" --- > **Note:** This is mock/placeholder content for demonstration purposes. Allow users to sign in with their existing accounts from Google, GitHub, and other providers. ## Supported Providers Supabase supports many OAuth providers: - Google - GitHub - GitLab - Bitbucket - Azure - Facebook - Twitter - Discord - Slack - And more... ## Setting Up OAuth ### Configure in Supabase Dashboard 1. Go to **Authentication** → **Providers** 2. Enable your desired provider (e.g., Google) 3. Add your OAuth credentials: - **Client ID** - **Client Secret** - **Redirect URL**: `https://your-project.supabase.co/auth/v1/callback` ### Google OAuth Setup 1. Go to [Google Cloud Console](https://console.cloud.google.com) 2. Create a new project or select existing 3. Enable Google+ API 4. Create OAuth 2.0 credentials 5. Add authorized redirect URIs: - Production: `https://your-project.supabase.co/auth/v1/callback` - Development: `http://localhost:54321/auth/v1/callback` ### GitHub OAuth Setup 1. Go to GitHub Settings → Developer Settings → OAuth Apps 2. Click "New OAuth App" 3. Fill in details: - **Application name**: Your App - **Homepage URL**: `https://yourapp.com` - **Authorization callback URL**: `https://your-project.supabase.co/auth/v1/callback` 4. Copy Client ID and Client Secret to Supabase ## Implementation ### OAuth Sign In Button ```tsx 'use client'; import { signInWithOAuthAction } from '../_lib/actions'; export function OAuthButtons() { const handleGoogleSignIn = async () => { await signInWithOAuthAction('google'); }; const handleGitHubSignIn = async () => { await signInWithOAuthAction('github'); }; return (
); } ``` ### Server Action ```typescript 'use server'; import { enhanceAction } from '@kit/next/actions'; import { getSupabaseServerClient } from '@kit/supabase/server-client'; import { z } from 'zod'; const OAuthProviderSchema = z.enum([ 'google', 'github', 'gitlab', 'azure', 'facebook', ]); export const signInWithOAuthAction = enhanceAction( async (provider) => { const client = getSupabaseServerClient(); const origin = process.env.NEXT_PUBLIC_SITE_URL!; const { data, error } = await client.auth.signInWithOAuth({ provider, options: { redirectTo: `${origin}/auth/callback`, }, }); if (error) throw error; // Redirect to OAuth provider redirect(data.url); }, { schema: OAuthProviderSchema, } ); ``` ### OAuth Callback Handler ```typescript // app/auth/callback/route.ts import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs'; import { cookies } from 'next/headers'; import { NextResponse } from 'next/server'; export async function GET(request: Request) { const requestUrl = new URL(request.url); const code = requestUrl.searchParams.get('code'); if (code) { const cookieStore = cookies(); const supabase = createRouteHandlerClient({ cookies: () => cookieStore }); await supabase.auth.exchangeCodeForSession(code); } // Redirect to home page return NextResponse.redirect(new URL('/home', request.url)); } ``` ## Customizing OAuth Flow ### Scopes Request specific permissions: ```typescript await client.auth.signInWithOAuth({ provider: 'google', options: { scopes: 'email profile https://www.googleapis.com/auth/calendar', }, }); ``` ### Query Parameters Pass custom parameters: ```typescript await client.auth.signInWithOAuth({ provider: 'azure', options: { queryParams: { prompt: 'consent', access_type: 'offline', }, }, }); ``` ### Skip Browser Redirect For mobile apps or custom flows: ```typescript const { data } = await client.auth.signInWithOAuth({ provider: 'google', options: { skipBrowserRedirect: true, }, }); // data.url contains the OAuth URL // Handle redirect manually ``` ## Account Linking ### Linking Additional Providers Allow users to link multiple OAuth accounts: ```typescript export const linkOAuthProviderAction = enhanceAction( async (provider) => { const client = getSupabaseServerClient(); const user = await requireAuth(); const { data, error } = await client.auth.linkIdentity({ provider, }); if (error) throw error; redirect(data.url); }, { schema: OAuthProviderSchema, auth: true } ); ``` ### Unlinking Providers ```typescript export const unlinkOAuthProviderAction = enhanceAction( async ({ provider, identityId }) => { const client = getSupabaseServerClient(); const { error } = await client.auth.unlinkIdentity({ identity_id: identityId, }); if (error) throw error; revalidatePath('/settings/security'); }, { schema: z.object({ provider: z.string(), identityId: z.string(), }), auth: true, } ); ``` ### Viewing Linked Identities ```typescript import { getSupabaseServerClient } from '@kit/supabase/server-client'; export async function getLinkedIdentities() { const client = getSupabaseServerClient(); const { data: { user } } = await client.auth.getUser(); return user?.identities || []; } ``` ## User Data from OAuth ### Accessing Provider Data ```typescript const { data: { user } } = await client.auth.getUser(); // User metadata from provider const { full_name, avatar_url, email, } = user.user_metadata; // Provider-specific data const identities = user.identities || []; const googleIdentity = identities.find(i => i.provider === 'google'); console.log(googleIdentity?.identity_data); ``` ### Storing Additional Data ```typescript export const completeOAuthProfileAction = enhanceAction( async (data) => { const client = getSupabaseServerClient(); const user = await requireAuth(); // Update user metadata await client.auth.updateUser({ data: { username: data.username, bio: data.bio, }, }); // Update profile in database await client.from('profiles').upsert({ id: user.id, username: data.username, bio: data.bio, avatar_url: user.user_metadata.avatar_url, }); redirect('/home'); }, { schema: ProfileSchema, auth: true } ); ``` ## Configuration ### Enable OAuth in Config ```typescript // config/auth.config.ts export const authConfig = { providers: { emailPassword: true, oAuth: ['google', 'github'], }, }; ``` ### Conditional Rendering ```tsx import { authConfig } from '~/config/auth.config'; export function AuthProviders() { return ( <> {authConfig.providers.emailPassword && } {authConfig.providers.oAuth?.includes('google') && ( )} {authConfig.providers.oAuth?.includes('github') && ( )} ); } ``` ## Troubleshooting ### Redirect URI Mismatch Ensure redirect URIs match exactly: - Check Supabase Dashboard → Authentication → URL Configuration - Verify OAuth app settings in provider console - Use exact URLs (including http/https) ### Missing Email Some providers don't share email by default: ```typescript const { data: { user } } = await client.auth.getUser(); if (!user.email) { // Request email separately or prompt user redirect('/auth/complete-profile'); } ``` ### Rate Limiting OAuth providers may rate limit requests: - Cache OAuth tokens appropriately - Don't make excessive authorization requests - Handle rate limit errors gracefully ## Best Practices 1. **Request minimum scopes** - Only ask for what you need 2. **Handle errors gracefully** - OAuth can fail for many reasons 3. **Verify email addresses** - Some providers don't verify emails 4. **Support account linking** - Let users connect multiple providers 5. **Provide fallback** - Always offer email/password as backup 6. **Log OAuth events** - Track sign-ins and linking attempts 7. **Test thoroughly** - Test with real provider accounts