Configure Social Login (OAuth) Providers
Set up social login (OAuth/OIDC) providers for self-hosted Supabase with Docker.
This guide covers the server-side configuration required to enable social login providers on a self-hosted Supabase instance running with Docker Compose. This applies to all OAuth and OIDC-based providers, including third-party identity providers like Keycloak.
Before you begin#
You need:
- A working self-hosted Supabase installation. See Self-Hosting with Docker.
API_EXTERNAL_URLset to the publicly reachable URL of your Supabase instance (e.g.,https://<your-domain>).
HTTPS is strongly recommended in production. Most OAuth providers reject http:// callback URLs (except localhost).
Your OAuth callback URL is built from API_EXTERNAL_URL. For example, if API_EXTERNAL_URL is https://<your-domain>, the callback URL will become:
1https://<your-domain>/auth/v1/callbackYou will have to register this URL with each OAuth provider.
OAuth request flow#
When a user signs in with an OAuth provider, the following flow occurs:
- Your app calls
supabase.auth.signInWithOAuth()and the browser redirects to the Auth service - API gateway (Kong) routes the request to the Auth container (
/auth/v1/authorize) - Auth redirects the user to the OAuth provider (e.g., Google) for consent
- The provider redirects back to
https://<your-domain>/auth/v1/callback - Auth exchanges the authorization code for tokens and redirects the user to your
SITE_URLor an allowed redirect URL
Auth environment variables#
The Auth service (GoTrue) uses the prefix GOTRUE_EXTERNAL_ followed by a provider name for all OAuth configuration. For example, when using Google:
GOTRUE_EXTERNAL_GOOGLE_ENABLEDGOTRUE_EXTERNAL_GOOGLE_CLIENT_IDGOTRUE_EXTERNAL_GOOGLE_SECRETGOTRUE_EXTERNAL_GOOGLE_REDIRECT_URI
Step-by-step configuration#
The default .env.example and docker-compose.yml include commented-out placeholders for Google, GitHub, and Azure.
Step 1: Register your app with the provider#
- Go to the OAuth provider's developer console and create an application.
- Set the authorized redirect URL, e.g.,
https://<your-domain>/auth/v1/callback - Copy the client ID and client secret into your
.envfile.
Step 2: Configure variables in the .env file#
Uncomment the lines for your provider in .env and add your client ID and secret, e.g., for Google:
1GOOGLE_ENABLED=true2GOOGLE_CLIENT_ID=your-client-id3GOOGLE_SECRET=your-client-secretStep 3: Enable the matching lines in docker-compose.yml#
Uncomment the corresponding GOTRUE_EXTERNAL_ lines in the auth service's environment:
1GOTRUE_EXTERNAL_GOOGLE_ENABLED: ${GOOGLE_ENABLED}2GOTRUE_EXTERNAL_GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID}3GOTRUE_EXTERNAL_GOOGLE_SECRET: ${GOOGLE_SECRET}4GOTRUE_EXTERNAL_GOOGLE_REDIRECT_URI: ${API_EXTERNAL_URL}/auth/v1/callbackFor providers not pre-configured in the files (see the full provider list below), add the lines manually following the same pattern: variables in .env, passthrough with GOTRUE_EXTERNAL_PROVIDER_ in docker-compose.yml.
Step 4: Restart the auth service#
1docker compose up -d --force-recreate --no-deps authStep 5: Verify the configuration#
Check that the provider is enabled:
1curl https://<your-domain>/auth/v1/settingsThe response should include your provider under external:
1{2 "external": {3 "google": true4 }5}Provider-specific setup#
Google Cloud Console setup:
- Go to Google Cloud Console
- Create or select a project
- Select Solutions > All products in the navigation menu on the left
- Go to APIs & services > OAuth consent screen and click Get started
- Follow the configuration steps and add an External app
- Go to APIs & Services > Credentials
- Click Create Credentials > OAuth client ID
- Set application type to Web application
- Under Authorized redirect URIs, add:
https://<your-domain>/auth/v1/callback - Click Create and copy the client ID and client secret
.env:
1GOOGLE_ENABLED=true2GOOGLE_CLIENT_ID=your-google-client-id.apps.googleusercontent.com3GOOGLE_SECRET=your-google-client-secretdocker-compose.yml:
1GOTRUE_EXTERNAL_GOOGLE_ENABLED: ${GOOGLE_ENABLED}2GOTRUE_EXTERNAL_GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID}3GOTRUE_EXTERNAL_GOOGLE_SECRET: ${GOOGLE_SECRET}4GOTRUE_EXTERNAL_GOOGLE_REDIRECT_URI: ${API_EXTERNAL_URL}/auth/v1/callbackOther supported providers#
Supabase Auth supports the following OAuth providers:
| Provider | Env prefix | Additional variables | Docs |
|---|---|---|---|
| Apple | APPLE_ | - | Login with Apple |
| Azure (Microsoft) | AZURE_ | URL (tenant URL) | Login with Azure |
| Bitbucket | BITBUCKET_ | - | Login with Bitbucket |
| Discord | DISCORD_ | - | Login with Discord |
FACEBOOK_ | - | Login with Facebook | |
| Figma | FIGMA_ | - | Login with Figma |
| GitHub | GITHUB_ | URL (for GitHub Enterprise) | Login with GitHub |
| GitLab | GITLAB_ | URL (for self-hosted GitLab) | Login with GitLab |
GOOGLE_ | - | Login with Google | |
| Kakao | KAKAO_ | - | Login with Kakao |
| Keycloak (OIDC) | KEYCLOAK_ | URL (realm URL, required) | Login with Keycloak |
| LinkedIn (OIDC) | LINKEDIN_OIDC_ | - | Login with LinkedIn |
| Notion | NOTION_ | - | Login with Notion |
| Slack (OIDC) | SLACK_OIDC_ | - | Login with Slack |
| Snapchat | SNAPCHAT_ | - | - |
| Spotify | SPOTIFY_ | - | Login with Spotify |
| Twitch | TWITCH_ | - | Login with Twitch |
TWITTER_ | - | Login with Twitter | |
| WorkOS | WORKOS_ | - | Login with WorkOS |
| Zoom | ZOOM_ | - | Login with Zoom |
For each provider, you need at minimum ENABLED, CLIENT_ID, SECRET, and REDIRECT_URI in .env and docker-compose.yml.
LinkedIn (OIDC) and Slack (OIDC) use multi-word env prefixes. The full Docker Compose variables are GOTRUE_EXTERNAL_LINKEDIN_OIDC_CLIENT_ID and GOTRUE_EXTERNAL_SLACK_OIDC_CLIENT_ID respectively - not LINKEDIN_CLIENT_ID or SLACK_CLIENT_ID.
Test the login flow#
You can test OAuth with the following minimal index.html served, e.g., via python -m http.server 3000:
1<!doctype html>2<html>3 <body>4 <h1>Supabase OAuth Test</h1>5 <button id="loginBtn">Sign in with Google</button>6 <pre id="result"></pre>78 <script src="https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2"></script>9 <script>10 document.addEventListener('DOMContentLoaded', function () {11 const SUPABASE_URL = 'https://<your-domain>'12 const SUPABASE_ANON_KEY = 'your-anon-key'1314 const supabase = window.supabase.createClient(SUPABASE_URL, SUPABASE_ANON_KEY)1516 const button = document.getElementById('loginBtn')1718 button.addEventListener('click', async () => {19 const { error } = await supabase.auth.signInWithOAuth({20 provider: 'google',21 })2223 if (error) {24 document.getElementById('result').textContent = JSON.stringify(error, null, 2)25 }26 })2728 supabase.auth.getSession().then(({ data }) => {29 if (data.session) {30 document.getElementById('result').textContent =31 'Logged in as: ' + data.session.user.email32 }33 })34 })35 </script>36 </body>37</html>Make sure SITE_URL or ADDITIONAL_REDIRECT_URLS includes the URL where you open this test page. Otherwise the Auth service will reject the redirect after login.
For detailed client-side integration, see Social Login.
Troubleshooting#
"Provider not enabled" or provider shows false in /auth/v1/settings#
- Check that
GOTRUE_EXTERNAL_*_ENABLEDis set totrueindocker-compose.yml - Verify the
.envvariable is not empty, e.g., check withdocker compose exec auth env | grep GOOGLE
Variables added to .env but provider still not working#
Configuration variables from .env are not automatically available inside the container unless there's a matching passthrough definition in docker-compose.yml. Check, e.g., for:
1GOTRUE_EXTERNAL_GOOGLE_ENABLED: ${GOOGLE_ENABLED}Run docker compose exec auth env | grep GOTRUE_EXTERNAL to verify the variables are reaching the container.
SITE_URL or redirect URL errors after login#
After a successful OAuth login, the Auth service redirects to SITE_URL or a URL from ADDITIONAL_REDIRECT_URLS. Ensure:
SITE_URLin.envis set to your application's URL- If your app uses a different redirect URL, add it to
ADDITIONAL_REDIRECT_URLS(comma-separated)
Nonce check failure on mobile (Google Sign In)#
When using Google Sign In on mobile with ID tokens, nonce verification may fail because mobile SDKs don't always support the nonce flow that the Auth service expects.
GOTRUE_EXTERNAL_SKIP_NONCE_CHECK disables nonce validation on ID tokens, which weakens replay-attack protection. Treat it as a short-lived troubleshooting workaround, not a permanent fix:
- Enable it only in the environment where you're debugging the issue.
- Revert it as soon as the issue is resolved.
- Prefer fixing the client-side nonce handling or switching to an OAuth flow (authorization code with PKCE) that avoids ID-token nonce issues entirely.
To enable it, uncomment the following line in docker-compose.yml:
1GOTRUE_EXTERNAL_SKIP_NONCE_CHECK: trueAuth service fails to start#
Check the auth container logs:
1docker compose logs authCommon causes:
- Missing required environment variable (e.g.,
CLIENT_IDorSECRETis empty) - Invalid
API_EXTERNAL_URL(must be a valid URL with protocol)
Environment variable reference#
All OAuth-related environment variables for the auth service in docker-compose.yml:
| Variable | Description | Required |
|---|---|---|
GOTRUE_EXTERNAL_*_ENABLED | Enable the provider (true/false) | Yes |
GOTRUE_EXTERNAL_*_CLIENT_ID | OAuth client ID from the provider | Yes |
GOTRUE_EXTERNAL_*_SECRET | OAuth client secret from the provider | Yes |
GOTRUE_EXTERNAL_*_REDIRECT_URI | Callback URL: ${API_EXTERNAL_URL}/auth/v1/callback | Yes |
GOTRUE_SITE_URL | Default redirect URL after authentication (set via SITE_URL in .env) | Yes |
Additional resources#
- Redirect URLs
- Auth server on GitHub (check README and
example.env)