Documentation
OAuth
Sign in with Google, GitHub, and other OAuth providers.
Page type
Product documentation
Best for
Setup, workflow, and implementation details
Next action
Copy, export, or continue deeper into the doc tree
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
