Bỏ qua

OAuth Providers

OAuth Flow trong Supabase

Redirect Flow

┌─────────────────────────────────────────────────────────────┐
│                      OAUTH FLOW                              │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  1. User clicks "Sign in with Google"                       │
│     │                                                        │
│     ▼                                                        │
│  2. signInWithOAuth({ provider: 'google' })                 │
│     │                                                        │
│     ▼                                                        │
│  3. Redirect to Google consent screen                       │
│     │                                                        │
│     ▼                                                        │
│  4. User authorizes, Google redirects back                  │
│     │                                                        │
│     ▼                                                        │
│  5. Supabase exchanges code for tokens                      │
│     │                                                        │
│     ▼                                                        │
│  6. User created/logged in, redirect to app                 │
│                                                              │
└─────────────────────────────────────────────────────────────┘

Supported Providers

Available OAuth Providers

┌─────────────────────────────────────────────────────────────┐
│                   OAUTH PROVIDERS                            │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  Popular:                                                    │
│  ├── Google       (google)                                  │
│  ├── GitHub       (github)                                  │
│  ├── Facebook     (facebook)                                │
│  ├── Twitter/X    (twitter)                                 │
│  └── Apple        (apple)                                   │
│                                                              │
│  Enterprise:                                                 │
│  ├── Azure AD     (azure)                                   │
│  ├── Okta         (okta)                                    │
│  ├── Keycloak     (keycloak)                                │
│  └── SAML 2.0     (custom)                                  │
│                                                              │
│  Other:                                                      │
│  ├── Discord      (discord)                                 │
│  ├── Slack        (slack)                                   │
│  ├── Spotify      (spotify)                                 │
│  ├── Twitch       (twitch)                                  │
│  └── + many more...                                         │
│                                                              │
└─────────────────────────────────────────────────────────────┘

Setup Google OAuth

1. Google Cloud Console

1. Go to console.cloud.google.com
2. Create new project (or select existing)
3. APIs & Services → OAuth consent screen
   - App name
   - User support email
   - Scopes: email, profile, openid
4. APIs & Services → Credentials → Create OAuth client ID
   - Application type: Web application
   - Authorized redirect URIs:
     https://<your-project>.supabase.co/auth/v1/callback

2. Supabase Dashboard

Dashboard → Authentication → Providers → Google
- Enable: ON
- Client ID: (from Google)
- Client Secret: (from Google)

Setup GitHub OAuth

1. GitHub Developer Settings

1. GitHub → Settings → Developer settings
2. OAuth Apps → New OAuth App
   - Application name: Your App
   - Homepage URL: https://yourapp.com
   - Authorization callback URL:
     https://<your-project>.supabase.co/auth/v1/callback
3. Copy Client ID and generate Client Secret

2. Supabase Dashboard

Dashboard → Authentication → Providers → GitHub
- Enable: ON
- Client ID: (from GitHub)
- Client Secret: (from GitHub)

Implementation

Basic OAuth Sign In

const { data, error } = await supabase.auth.signInWithOAuth({
  provider: 'google',
});

// User is redirected to Google
// After authorization, redirected back to your app

With Options

const { data, error } = await supabase.auth.signInWithOAuth({
  provider: 'google',
  options: {
    // Redirect sau khi login thành công
    redirectTo: 'https://myapp.com/dashboard',

    // Request additional scopes
    scopes: 'https://www.googleapis.com/auth/calendar.readonly',

    // Additional query params
    queryParams: {
      access_type: 'offline',  // Get refresh token
      prompt: 'consent',       // Always show consent
    },
  },
});

OAuth in Next.js

Login Button Component

'use client';

import { createClient } from '@/lib/supabase/client';

export function OAuthButtons() {
  const supabase = createClient();

  const handleOAuthLogin = async (provider: 'google' | 'github') => {
    const { error } = await supabase.auth.signInWithOAuth({
      provider,
      options: {
        redirectTo: `${location.origin}/auth/callback`,
      },
    });

    if (error) {
      console.error('OAuth error:', error.message);
    }
  };

  return (
    <div className="oauth-buttons">
      <button onClick={() => handleOAuthLogin('google')}>
        <GoogleIcon />
        Sign in with Google
      </button>
      <button onClick={() => handleOAuthLogin('github')}>
        <GitHubIcon />
        Sign in with GitHub
      </button>
    </div>
  );
}

Callback Handler

// 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();

    // Exchange code for session
    const { error } = await supabase.auth.exchangeCodeForSession(code);

    if (!error) {
      return NextResponse.redirect(`${origin}${next}`);
    }
  }

  // OAuth error
  return NextResponse.redirect(`${origin}/auth/error`);
}

Access Provider Data

User Metadata

const { data: { user } } = await supabase.auth.getUser();

if (user) {
  // Identity info
  const googleIdentity = user.identities?.find(
    (i) => i.provider === 'google'
  );

  // User metadata from provider
  console.log('Email:', user.email);
  console.log('Name:', user.user_metadata.full_name);
  console.log('Avatar:', user.user_metadata.avatar_url);

  // Provider-specific data
  console.log('Google ID:', googleIdentity?.id);
}

Store in Profile Table

-- Trigger to sync OAuth data to profiles
CREATE OR REPLACE FUNCTION sync_user_profile()
RETURNS TRIGGER AS $$
BEGIN
  INSERT INTO public.profiles (id, email, full_name, avatar_url)
  VALUES (
    NEW.id,
    NEW.email,
    NEW.raw_user_meta_data->>'full_name',
    NEW.raw_user_meta_data->>'avatar_url'
  )
  ON CONFLICT (id) DO UPDATE SET
    full_name = EXCLUDED.full_name,
    avatar_url = EXCLUDED.avatar_url,
    updated_at = NOW();

  RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

Linking Multiple Providers

// User đã đăng nhập bằng email
// Muốn link thêm Google

const { data, error } = await supabase.auth.linkIdentity({
  provider: 'google',
});

// User redirected to Google
// After auth, Google linked to existing account
// Get user's identities
const { data: { user } } = await supabase.auth.getUser();
const googleIdentity = user?.identities?.find(i => i.provider === 'google');

if (googleIdentity) {
  const { error } = await supabase.auth.unlinkIdentity(googleIdentity);
}

Check Linked Providers

const { data: { user } } = await supabase.auth.getUser();

const providers = user?.identities?.map(i => i.provider) ?? [];
console.log('Linked providers:', providers);
// ['email', 'google', 'github']

Provider-specific Scopes

Google Scopes

// Request Google Calendar access
await supabase.auth.signInWithOAuth({
  provider: 'google',
  options: {
    scopes: [
      'https://www.googleapis.com/auth/calendar.readonly',
      'https://www.googleapis.com/auth/drive.readonly',
    ].join(' '),
  },
});

GitHub Scopes

// Request repo access
await supabase.auth.signInWithOAuth({
  provider: 'github',
  options: {
    scopes: 'repo read:user user:email',
  },
});

Access Provider Token

// After OAuth, get provider token for API calls
const { data: { session } } = await supabase.auth.getSession();

const providerToken = session?.provider_token;
const providerRefreshToken = session?.provider_refresh_token;

// Use token to call provider APIs
const response = await fetch('https://api.github.com/user', {
  headers: {
    Authorization: `Bearer ${providerToken}`,
  },
});

Error Handling

Common OAuth Errors

const { error } = await supabase.auth.signInWithOAuth({
  provider: 'google',
});

if (error) {
  switch (error.message) {
    case 'Provider not enabled':
      // Provider chưa được setup trong dashboard
      break;
    case 'Email already registered':
      // Email đã dùng với provider khác
      break;
    case 'access_denied':
      // User từ chối authorization
      break;
    default:
      console.error('OAuth error:', error.message);
  }
}

Best Practices

Security

✅ Always use HTTPS
✅ Validate redirect URLs
✅ Store tokens securely (Supabase handles this)
✅ Request minimum necessary scopes
✅ Handle token refresh properly

UX

✅ Show which providers are linked
✅ Allow unlinking (but keep at least one)
✅ Clear error messages
✅ Loading states during redirect

Tổng kết

OAuth Setup Checklist

  1. Create OAuth app with provider
  2. Add callback URL: https://<project>.supabase.co/auth/v1/callback
  3. Copy Client ID & Secret to Supabase
  4. Enable provider in Dashboard
  5. Implement signInWithOAuth in frontend
  6. Handle callback route

Common Providers

Provider Scopes Common Use
Google email, profile Most apps
GitHub user, email Dev tools
Facebook email, public_profile Social apps
Apple email, name iOS apps

Q&A

  1. Cần support những providers nào?
  2. Có cần link multiple providers?
  3. Provider-specific data cần access không?