OAuth
Sign in with Google, GitHub, and other OAuth providers.
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:
- GitHub
- GitLab
- Bitbucket
- Azure
- Discord
- Slack
- And more...
Setting Up OAuth
Configure in Supabase Dashboard
- Go to Authentication → Providers
- Enable your desired provider (e.g., Google)
- Add your OAuth credentials:
- Client ID
- Client Secret
- Redirect URL:
https://your-project.supabase.co/auth/v1/callback
Google OAuth Setup
- Go to Google Cloud Console
- Create a new project or select existing
- Enable Google+ API
- Create OAuth 2.0 credentials
- Add authorized redirect URIs:
- Production:
https://your-project.supabase.co/auth/v1/callback - Development:
http://localhost:54321/auth/v1/callback
- Production:
GitHub OAuth Setup
- Go to GitHub Settings → Developer Settings → OAuth Apps
- Click "New OAuth App"
- Fill in details:
- Application name: Your App
- Homepage URL:
https://yourapp.com - Authorization callback URL:
https://your-project.supabase.co/auth/v1/callback
- Copy Client ID and Client Secret to Supabase
Implementation
OAuth Sign In Button
'use client';
import { signInWithOAuthAction } from '../_lib/actions';
export function OAuthButtons() {
const handleGoogleSignIn = async () => {
await signInWithOAuthAction('google');
};
const handleGitHubSignIn = async () => {
await signInWithOAuthAction('github');
};
return (
<div className="space-y-2">
<button
onClick={handleGoogleSignIn}
className="w-full flex items-center justify-center gap-2 border rounded-lg p-2"
>
<GoogleIcon />
Continue with Google
</button>
<button
onClick={handleGitHubSignIn}
className="w-full flex items-center justify-center gap-2 border rounded-lg p-2"
>
<GitHubIcon />
Continue with GitHub
</button>
</div>
);
}
Server Action
'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
// 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:
await client.auth.signInWithOAuth({
provider: 'google',
options: {
scopes: 'email profile https://www.googleapis.com/auth/calendar',
},
});
Query Parameters
Pass custom parameters:
await client.auth.signInWithOAuth({
provider: 'azure',
options: {
queryParams: {
prompt: 'consent',
access_type: 'offline',
},
},
});
Skip Browser Redirect
For mobile apps or custom flows:
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:
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
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
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
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
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
// config/auth.config.ts
export const authConfig = {
providers: {
emailPassword: true,
oAuth: ['google', 'github'],
},
};
Conditional Rendering
import { authConfig } from '~/config/auth.config';
export function AuthProviders() {
return (
<>
{authConfig.providers.emailPassword && <EmailPasswordForm />}
{authConfig.providers.oAuth?.includes('google') && (
<GoogleSignInButton />
)}
{authConfig.providers.oAuth?.includes('github') && (
<GitHubSignInButton />
)}
</>
);
}
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:
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
- Request minimum scopes - Only ask for what you need
- Handle errors gracefully - OAuth can fail for many reasons
- Verify email addresses - Some providers don't verify emails
- Support account linking - Let users connect multiple providers
- Provide fallback - Always offer email/password as backup
- Log OAuth events - Track sign-ins and linking attempts
- Test thoroughly - Test with real provider accounts