OAuth Authentication
Overview
OAuth authentication in ClawPlate is seamlessly integrated with Supabase Auth, providing secure and easy-to-implement social login functionality. The OAuthButtons component handles all the UI interactions while Supabase manages the authentication flow behind the scenes.
How It Works
1. Supabase Integration
ClawPlate uses Supabase Auth as the authentication backend, which provides:
- Built-in OAuth providers (GitHub, Google, Apple, X/Twitter)
- Secure token management with automatic refresh
- User session handling across your application
- Database integration for user profiles and metadata
2. OAuthButtons Component
The OAuthButtons component provides:
- Provider-specific styling with brand colors
- Loading states during authentication
- Error handling with user feedback
- Responsive design for all devices
Setup Guide
Step 1: Configure Supabase
First, enable OAuth providers in your Supabase dashboard:
- Go to Authentication > Providers in your Supabase dashboard
- Enable the providers you want to use:
- GitHub: Requires GitHub OAuth App
- Google: Requires Google Cloud Console setup
- Apple: Requires Apple Developer account
- X (Twitter): Requires X Developer account
Step 2: Environment Variables
Add your OAuth credentials to your Supabase dashboard
Step 3: Use OAuthButtons Component
Simply import and use the component in your authentication pages:
<!-- OAuth automatique avec Supabase -->
<OAuthButton provider="github" @error="handleError" />
<OAuthButton provider="google" @error="handleError" />
<OAuthButton provider="apple" @error="handleError" />
<OAuthButton provider="x" @error="handleError" />
<!-- With Custom Methods -->
<OAuthButton
provider="github"
:onClick="customSignIn"
@error="handleError"
/>
<!-- Manage your errors -->
<OAuthButton
provider="google"
@error="(message) => showToast({ title: 'Error', description: message, variant: 'error' })"
/>Supported Providers
GitHub
- Setup: Create a GitHub OAuth App
- Scopes:
user:email,read:user - User Data: Username, email, avatar, profile URL
Google
- Setup: Configure Google Cloud Console
- Scopes:
email,profile - User Data: Name, email, profile picture, locale
Apple
- Setup: Apple Developer account required
- Scopes:
name,email - User Data: Name, email (if provided by user)
X (Twitter)
- Setup: X Developer account required
- Scopes:
tweet.read,users.read - User Data: Username, display name, profile picture
Authentication Flow
1. User Clicks OAuth Button
<OAuthButtons
provider="github"
@click="handleGitHubAuth"
/>2. Supabase Redirects to Provider
const { error } = await supabase.auth.signInWithOAuth({
provider: 'github',
options: {
redirectTo: `${window.location.origin}/auth/callback`
}
})3. User Authorizes on Provider Site
- User is redirected to GitHub/Google/etc.
- User grants permissions to your app
- Provider redirects back to your callback URL
4. Supabase Handles the Callback
<!-- pages/auth/callback.vue -->
<template>
<div>Processing authentication...</div>
</template>
<script setup>
const supabase = useSupabaseClient()
onMounted(async () => {
const { data, error } = await supabase.auth.getSession()
if (error) {
console.error('Auth error:', error)
await navigateTo('/login?error=auth_failed')
} else if (data.session) {
await navigateTo('/dashboard')
}
})
</script>5. User Session is Created
- Supabase creates a user session
- User data is stored in your database
- User is redirected to your app
User Data Structure
After successful authentication, Supabase provides user data in this format:
interface User {
id: string
email: string
user_metadata: {
full_name?: string
avatar_url?: string
provider_id?: string
provider?: string
}
app_metadata: {
provider?: string
providers?: string[]
}
}Advanced Configuration
Custom Redirect URLs
const { error } = await supabase.auth.signInWithOAuth({
provider: 'github',
options: {
redirectTo: `${window.location.origin}/auth/callback`,
queryParams: {
access_type: 'offline',
prompt: 'consent'
}
}
})Scopes Configuration
Configure additional scopes in your Supabase dashboard:
- Go to Authentication > Providers
- Select your provider
- Add custom scopes in the Additional Scopes field
User Profile Updates
// Update user profile after authentication
const updateUserProfile = async (userData) => {
const { error } = await supabase.auth.updateUser({
data: {
full_name: userData.full_name,
avatar_url: userData.avatar_url
}
})
if (error) {
console.error('Profile update error:', error)
}
}Error Handling
Common Errors
const handleAuthError = (error) => {
switch (error.message) {
case 'Invalid login credentials':
// Handle invalid credentials
break
case 'Email not confirmed':
// Handle unconfirmed email
break
case 'Too many requests':
// Handle rate limiting
break
default:
// Handle generic errors
console.error('Authentication error:', error)
}
}User Feedback
<template>
<div class="auth-container">
<OAuthButtons
provider="github"
:loading="isLoading"
@click="signInWithGitHub"
/>
<div v-if="error" class="error-message">
{{ error }}
</div>
</div>
</template>
<script setup>
const isLoading = ref(false)
const error = ref('')
const signInWithGitHub = async () => {
isLoading.value = true
error.value = ''
try {
const { error: authError } = await supabase.auth.signInWithOAuth({
provider: 'github',
options: {
redirectTo: `${window.location.origin}/auth/callback`
}
})
if (authError) {
error.value = 'Authentication failed. Please try again.'
}
} catch (err) {
error.value = 'An unexpected error occurred.'
} finally {
isLoading.value = false
}
}
</script>Security Considerations
1. HTTPS Required
OAuth providers require HTTPS in production. Ensure your domain uses SSL certificates.
2. Redirect URL Validation
Always validate redirect URLs in your Supabase dashboard to prevent open redirect attacks.
3. State Parameter
Supabase automatically handles the state parameter for CSRF protection.
4. Token Storage
Supabase securely stores tokens in HTTP-only cookies, preventing XSS attacks.
Testing
Development Testing
// Test OAuth flow in development
const testOAuth = async () => {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'github',
options: {
redirectTo: 'http://localhost:3000/auth/callback'
}
})
console.log('OAuth test result:', { data, error })
}Production Checklist
- [ ] HTTPS enabled
- [ ] Redirect URLs configured
- [ ] OAuth apps created for all providers
- [ ] Environment variables set
- [ ] Error handling implemented
- [ ] User feedback provided
Troubleshooting
Common Issues
OAuth button not working
- Check if provider is enabled in Supabase
- Verify environment variables
- Ensure redirect URLs are configured
User not created in database
- Check if user is created in Supabase Auth
- Verify database policies
- Check for RLS (Row Level Security) issues
Redirect loop
- Verify callback URL configuration
- Check for infinite redirects in callback handler
- Ensure proper error handling
Debug Mode
Enable debug mode in your Supabase client:
const supabase = createClient(
process.env.SUPABASE_URL,
process.env.SUPABASE_ANON_KEY,
{
auth: {
debug: true
}
}
)Best Practices
- Always handle errors gracefully with user feedback
- Use loading states to improve user experience
- Validate redirect URLs for security
- Test thoroughly in development before production
- Monitor authentication metrics in Supabase dashboard
- Keep tokens secure by letting Supabase handle storage
- Provide fallback options for users who prefer email/password
Example Implementation
Here's a complete authentication page example:
<template>
<div class="min-h-screen flex items-center justify-center bg-gray-50">
<div class="max-w-md w-full space-y-8">
<div>
<h2 class="mt-6 text-center text-3xl font-extrabold text-gray-900">
Sign in to your account
</h2>
<p class="mt-2 text-center text-sm text-gray-600">
Choose your preferred authentication method
</p>
</div>
<div class="space-y-4">
<OAuthButtons
provider="github"
size="lg"
:loading="isGitHubLoading"
@click="signInWithGitHub"
/>
<OAuthButtons
provider="google"
size="lg"
:loading="isGoogleLoading"
@click="signInWithGoogle"
/>
<OAuthButtons
provider="apple"
size="lg"
:loading="isAppleLoading"
@click="signInWithApple"
/>
</div>
<div v-if="error" class="bg-red-50 border border-red-200 rounded-md p-4">
<p class="text-sm text-red-600">{{ error }}</p>
</div>
<div class="text-center">
<p class="text-sm text-gray-600">
By continuing, you agree to our Terms of Service and Privacy Policy
</p>
</div>
</div>
</div>
</template>
<script setup>
const supabase = useSupabaseClient()
const router = useRouter()
const isGitHubLoading = ref(false)
const isGoogleLoading = ref(false)
const isAppleLoading = ref(false)
const error = ref('')
const signInWithProvider = async (provider) => {
const loadingRef = {
github: isGitHubLoading,
google: isGoogleLoading,
apple: isAppleLoading
}[provider]
if (loadingRef) {
loadingRef.value = true
}
error.value = ''
try {
const { error: authError } = await supabase.auth.signInWithOAuth({
provider: provider,
options: {
redirectTo: `${window.location.origin}/auth/callback`
}
})
if (authError) {
error.value = 'Authentication failed. Please try again.'
}
} catch (err) {
error.value = 'An unexpected error occurred.'
} finally {
if (loadingRef) {
loadingRef.value = false
}
}
}
const signInWithGitHub = () => signInWithProvider('github')
const signInWithGoogle = () => signInWithProvider('google')
const signInWithApple = () => signInWithProvider('apple')
</script>OAuth authentication in ClawPlate is powered by Supabase Auth and the OAuthButtons component, providing a secure and user-friendly authentication experience.