Back to Supabase

Configure Social Login (OAuth) Providers

apps/docs/content/guides/self-hosting/self-hosted-oauth.mdx

1.26.0417.9 KB
Original Source

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_URL set to the publicly reachable URL of your Supabase instance (e.g., https://<your-domain>).
<Admonition type="danger">

HTTPS is strongly recommended in production. Most OAuth providers reject http:// callback URLs (except localhost).

</Admonition>

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:

https://<your-domain>/auth/v1/callback

You 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:

  1. Your app calls supabase.auth.signInWithOAuth() and the browser redirects to the Auth service
  2. API gateway (Kong) routes the request to the Auth container (/auth/v1/authorize)
  3. Auth redirects the user to the OAuth provider (e.g., Google) for consent
  4. The provider redirects back to https://<your-domain>/auth/v1/callback
  5. Auth exchanges the authorization code for tokens and redirects the user to your SITE_URL or 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_ENABLED
  • GOTRUE_EXTERNAL_GOOGLE_CLIENT_ID
  • GOTRUE_EXTERNAL_GOOGLE_SECRET
  • GOTRUE_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

  1. Go to the OAuth provider's developer console and create an application.
  2. Set the authorized redirect URL, e.g., https://<your-domain>/auth/v1/callback
  3. Copy the client ID and client secret into your .env file.

Step 2: Configure environment variables

Uncomment the lines for your provider in .env and add your client ID and secret, e.g., for Google:

GOOGLE_ENABLED=true
GOOGLE_CLIENT_ID=your-client-id
GOOGLE_SECRET=your-client-secret

Step 3: Enable the matching lines in Docker Compose configuration

Uncomment the corresponding GOTRUE_EXTERNAL_ lines in the auth service's environment:

yaml
auth:
  environment:
    # ... existing variables ...
    GOTRUE_EXTERNAL_GOOGLE_ENABLED: ${GOOGLE_ENABLED}
    GOTRUE_EXTERNAL_GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID}
    GOTRUE_EXTERNAL_GOOGLE_SECRET: ${GOOGLE_SECRET}
    GOTRUE_EXTERNAL_GOOGLE_REDIRECT_URI: ${API_EXTERNAL_URL}/auth/v1/callback
<Admonition type="note">

For 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.

</Admonition>

Step 4: Restart the auth service

sh
docker compose up -d --force-recreate --no-deps auth

Step 5: Verify the configuration

Check that the provider is enabled:

sh
curl -H 'apikey: your-anon-key' https://<your-domain>/auth/v1/settings

The response should include your provider under external:

{
  "external": {
    "google": true
  }
}

Provider-specific setup

<Tabs scrollable size="small" type="underlined" defaultActiveId="google"

<TabPanel id="google" label="Google">

Google Cloud Console setup:

  1. Go to Google Cloud Console
  2. Create or select a project
  3. Select Solutions > All products in the navigation menu on the left
  4. Go to APIs & services > OAuth consent screen and click Get started
  5. Follow the configuration steps and add an External app
  6. Go to APIs & Services > Credentials
  7. Click Create Credentials > OAuth client ID
  8. Set application type to Web application
  9. Under Authorized redirect URIs, add: https://<your-domain>/auth/v1/callback
  10. Click Create and copy the client ID and client secret

.env:

GOOGLE_ENABLED=true
GOOGLE_CLIENT_ID=your-google-client-id.apps.googleusercontent.com
GOOGLE_SECRET=your-google-client-secret

docker-compose.yml:

yaml
auth:
  environment:
    # ... existing variables ...
    GOTRUE_EXTERNAL_GOOGLE_ENABLED: ${GOOGLE_ENABLED}
    GOTRUE_EXTERNAL_GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID}
    GOTRUE_EXTERNAL_GOOGLE_SECRET: ${GOOGLE_SECRET}
    GOTRUE_EXTERNAL_GOOGLE_REDIRECT_URI: ${API_EXTERNAL_URL}/auth/v1/callback
</TabPanel> <TabPanel id="github" label="GitHub">

GitHub setup:

  1. Go to GitHub Developer Settings
  2. Click New OAuth app
  3. Fill in Homepage URL, e.g., https://<your-domain>
  4. Set Authorization callback URL to: https://<your-domain>/auth/v1/callback
  5. Click Register application
  6. Copy the client ID, generate and copy a client secret

.env:

GITHUB_ENABLED=true
GITHUB_CLIENT_ID=your-github-client-id
GITHUB_SECRET=your-github-client-secret

docker-compose.yml:

yaml
auth:
  environment:
    # ... existing variables ...
    GOTRUE_EXTERNAL_GITHUB_ENABLED: ${GITHUB_ENABLED}
    GOTRUE_EXTERNAL_GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID}
    GOTRUE_EXTERNAL_GITHUB_SECRET: ${GITHUB_SECRET}
    GOTRUE_EXTERNAL_GITHUB_REDIRECT_URI: ${API_EXTERNAL_URL}/auth/v1/callback
</TabPanel> <TabPanel id="azure" label="Azure">

Azure Portal setup:

  1. Go to Azure Portal
  2. Go to All services > Identity > App registrations via the navigation menu on the left
  3. Click New registration
  4. Add application Name
  5. Under Redirect URI, select Web and enter: https://<your-domain>/auth/v1/callback
  6. Click Register
  7. Copy the Application (client) ID
  8. Click on Client credentials > Add a certificate or secret
  9. Click on New client secret and add a client secret
  10. Copy the secret value (not "secret ID")

.env:

AZURE_ENABLED=true
AZURE_CLIENT_ID=your-azure-application-client-id
AZURE_SECRET=your-azure-client-secret
## Optional: restrict to a specific tenant (defaults to 'common')
# AZURE_URL=https://login.microsoftonline.com/your-tenant-id

docker-compose.yml:

yaml
auth:
  environment:
    # ... existing variables ...
    GOTRUE_EXTERNAL_AZURE_ENABLED: ${AZURE_ENABLED}
    GOTRUE_EXTERNAL_AZURE_CLIENT_ID: ${AZURE_CLIENT_ID}
    GOTRUE_EXTERNAL_AZURE_SECRET: ${AZURE_SECRET}
    GOTRUE_EXTERNAL_AZURE_REDIRECT_URI: ${API_EXTERNAL_URL}/auth/v1/callback
    ## Optional: uncomment for tenant-specific Azure login
    # GOTRUE_EXTERNAL_AZURE_URL: ${AZURE_URL}
</TabPanel> <TabPanel id="apple" label="Apple">

Apple Developer setup:

  1. Refer to Apple Developer documentation to learn how to enable App ID and create a Services ID
  2. Create a private key for sign in with Apple
  3. Generate a client secret JWT from your private key. See Apple Developer documentation for details.

.env:

APPLE_ENABLED=true
APPLE_CLIENT_ID=com.example.your-services-id
APPLE_SECRET=your-generated-jwt-client-secret

docker-compose.yml:

yaml
auth:
  environment:
    # ... existing variables ...
    GOTRUE_EXTERNAL_APPLE_ENABLED: ${APPLE_ENABLED}
    GOTRUE_EXTERNAL_APPLE_CLIENT_ID: ${APPLE_CLIENT_ID}
    GOTRUE_EXTERNAL_APPLE_SECRET: ${APPLE_SECRET}
    GOTRUE_EXTERNAL_APPLE_REDIRECT_URI: ${API_EXTERNAL_URL}/auth/v1/callback
<Admonition type="note">

Apple uses response_mode=form_post for its OAuth flow. The Auth service handles this automatically - no additional configuration is needed.

</Admonition> </TabPanel> <TabPanel id="keycloak" label="Keycloak">

Keycloak setup:

  1. Open your Keycloak admin console
  2. Select (or create) the realm you want to use
  3. Go to Clients > Create client
  4. Set Client type to OpenID Connect
  5. Set Client ID (e.g., supabase)
  6. On the next screen, enable Client authentication
  7. Under Valid redirect URIs, add: https://<your-domain>/auth/v1/callback
  8. Save, then go to the Credentials tab and copy the Client secret

.env variables:

KEYCLOAK_ENABLED=true
KEYCLOAK_CLIENT_ID=supabase
KEYCLOAK_SECRET=your-keycloak-client-secret
## Required: your Keycloak realm URL
KEYCLOAK_URL=https://keycloak.example.com/realms/myrealm

docker-compose.yml passthrough:

yaml
auth:
  environment:
    # ... existing variables ...
    GOTRUE_EXTERNAL_KEYCLOAK_ENABLED: ${KEYCLOAK_ENABLED}
    GOTRUE_EXTERNAL_KEYCLOAK_CLIENT_ID: ${KEYCLOAK_CLIENT_ID}
    GOTRUE_EXTERNAL_KEYCLOAK_SECRET: ${KEYCLOAK_SECRET}
    GOTRUE_EXTERNAL_KEYCLOAK_REDIRECT_URI: ${API_EXTERNAL_URL}/auth/v1/callback
    GOTRUE_EXTERNAL_KEYCLOAK_URL: ${KEYCLOAK_URL}
<Admonition type="danger">

KEYCLOAK_URL is required. It must be the full realm URL (e.g., https://keycloak.example.com/realms/myrealm). The Auth service uses this to discover the OIDC endpoints (.well-known/openid-configuration). Without it, Keycloak login will not work.

</Admonition> </TabPanel> </Tabs>

Other supported providers

Supabase Auth supports the following OAuth providers:

ProviderEnv prefixAdditional variablesDocs
AppleAPPLE_-Login with Apple
Azure (Microsoft)AZURE_URL (tenant URL)Login with Azure
BitbucketBITBUCKET_-Login with Bitbucket
DiscordDISCORD_-Login with Discord
FacebookFACEBOOK_-Login with Facebook
FigmaFIGMA_-Login with Figma
GitHubGITHUB_URL (for GitHub Enterprise)Login with GitHub
GitLabGITLAB_URL (for self-hosted GitLab)Login with GitLab
GoogleGOOGLE_-Login with Google
KakaoKAKAO_-Login with Kakao
Keycloak (OIDC)KEYCLOAK_URL (realm URL, required)Login with Keycloak
LinkedIn (OIDC)LINKEDIN_OIDC_-Login with LinkedIn
NotionNOTION_-Login with Notion
Slack (OIDC)SLACK_OIDC_-Login with Slack
SnapchatSNAPCHAT_--
SpotifySPOTIFY_-Login with Spotify
TwitchTWITCH_-Login with Twitch
TwitterTWITTER_-Login with Twitter
WorkOSWORKOS_-Login with WorkOS
ZoomZOOM_-Login with Zoom

For each provider, you need at minimum ENABLED, CLIENT_ID, SECRET, and REDIRECT_URI in .env and docker-compose.yml.

<Admonition type="caution">

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.

</Admonition>

Test the login flow

You can test OAuth with the following minimal HTML page:

  • Save the code below to index.html
  • Start python -m http.server 3000 in the same directory
  • Make sure SITE_URL is set to http://localhost:3000 in your self-hosted Supabase .env configuration
  • Open your browser and go to http://localhost:3000
html
<!doctype html>
<html>
  <body>
    <h1>Supabase OAuth Test</h1>
    <button id="loginBtn">Sign in with Google</button>
    <pre id="result"></pre>

    <script src="https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2"></script>
    <script>
      document.addEventListener('DOMContentLoaded', function () {
        const SUPABASE_URL = 'https://<your-domain>'
        const SUPABASE_ANON_KEY = 'your-anon-key'

        const supabase = window.supabase.createClient(SUPABASE_URL, SUPABASE_ANON_KEY)

        const button = document.getElementById('loginBtn')

        button.addEventListener('click', async () => {
          const { error } = await supabase.auth.signInWithOAuth({
            provider: 'google',
          })

          if (error) {
            document.getElementById('result').textContent = JSON.stringify(error, null, 2)
          }
        })

        supabase.auth.getSession().then(({ data }) => {
          if (data.session) {
            document.getElementById('result').textContent =
              'Logged in as: ' + data.session.user.email
          }
        })
      })
    </script>
  </body>
</html>

For detailed client-side integration, see Social Login.

Troubleshooting

"Provider not enabled" or provider seen as false in settings

  • Check that GOTRUE_EXTERNAL_*_ENABLED is set to true in docker-compose.yml
  • Verify the .env variable is not empty, e.g., check with docker compose exec auth env | grep GOOGLE

Variables added to the environment 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:

GOTRUE_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_URL in .env is 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.

<Admonition type="caution">

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.
</Admonition>

To enable it, uncomment the following line in docker-compose.yml:

GOTRUE_EXTERNAL_SKIP_NONCE_CHECK: true

Auth service fails to start

Check the auth container logs:

sh
docker compose logs auth

Common causes:

  • Missing required environment variable (e.g., CLIENT_ID or SECRET is 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:

VariableDescriptionRequired
GOTRUE_EXTERNAL_*_ENABLEDEnable the provider (true/false)Yes
GOTRUE_EXTERNAL_*_CLIENT_IDOAuth client ID from the providerYes
GOTRUE_EXTERNAL_*_SECRETOAuth client secret from the providerYes
GOTRUE_EXTERNAL_*_REDIRECT_URICallback URL: ${API_EXTERNAL_URL}/auth/v1/callbackYes
GOTRUE_SITE_URLDefault redirect URL after authentication (set via SITE_URL in .env)Yes

Additional resources