# 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](/docs/guides/self-hosting/docker).
- `API_EXTERNAL_URL` set to the publicly reachable URL of your Supabase instance (e.g., `https://<your-domain>`).

HTTPS is required by most OAuth providers - `http://` callback URLs are rejected (except `localhost`). See the HTTPS [how-to guide](/docs/guides/self-hosting/self-hosted-proxy-https) for setup instructions.

Your **OAuth callback URL** should look like the following:

```
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. The API gateway 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:

```sh
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 name=docker-compose.yml
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
```

For providers **not** pre-configured in the files (see the [full provider list](#other-supported-providers) 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

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

```json
{
  "external": {
    "google": true
  }
}
```

## Provider-specific setup

**Google Cloud Console setup:**

1. Go to [Google Cloud Console](https://console.cloud.google.com/)
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

```sh name=.env
GOOGLE_ENABLED=true
GOOGLE_CLIENT_ID=your-google-client-id.apps.googleusercontent.com
GOOGLE_SECRET=your-google-client-secret
```

```yaml name=docker-compose.yml
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
```

**GitHub setup:**

1. Go to [GitHub Developer Settings](https://github.com/settings/developers)
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

```sh name=.env
GITHUB_ENABLED=true
GITHUB_CLIENT_ID=your-github-client-id
GITHUB_SECRET=your-github-client-secret
```

```yaml name=docker-compose.yml
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
```

**Azure Portal setup:**

1. Go to [Azure Portal](https://portal.azure.com/)
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")

```sh name=.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
```

```yaml name=docker-compose.yml
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}
```

**Apple Developer setup:**

1. Refer to [Apple Developer documentation](https://developer.apple.com/documentation/signinwithapple/configuring-your-environment-for-sign-in-with-apple) 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](https://developer.apple.com/documentation/accountorganizationaldatasharing/creating-a-client-secret) for details.

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

```yaml name=docker-compose.yml
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
```

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

**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**

```sh name=.env
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
```

```yaml name=docker-compose.yml
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}
```

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

## Other supported providers

Supabase Auth supports the following OAuth providers:

| Provider          | Env prefix       | Additional variables            | Docs                                                                  |
| ----------------- | ---------------- | ------------------------------- | --------------------------------------------------------------------- |
| Apple             | `APPLE_`         | -                               | [Login with Apple](/docs/guides/auth/social-login/auth-apple)         |
| Azure (Microsoft) | `AZURE_`         | `URL` (tenant URL)              | [Login with Azure](/docs/guides/auth/social-login/auth-azure)         |
| Bitbucket         | `BITBUCKET_`     | -                               | [Login with Bitbucket](/docs/guides/auth/social-login/auth-bitbucket) |
| Discord           | `DISCORD_`       | -                               | [Login with Discord](/docs/guides/auth/social-login/auth-discord)     |
| Facebook          | `FACEBOOK_`      | -                               | [Login with Facebook](/docs/guides/auth/social-login/auth-facebook)   |
| Figma             | `FIGMA_`         | -                               | [Login with Figma](/docs/guides/auth/social-login/auth-figma)         |
| GitHub            | `GITHUB_`        | `URL` (for GitHub Enterprise)   | [Login with GitHub](/docs/guides/auth/social-login/auth-github)       |
| GitLab            | `GITLAB_`        | `URL` (for self-hosted GitLab)  | [Login with GitLab](/docs/guides/auth/social-login/auth-gitlab)       |
| Google            | `GOOGLE_`        | -                               | [Login with Google](/docs/guides/auth/social-login/auth-google)       |
| Kakao             | `KAKAO_`         | -                               | [Login with Kakao](/docs/guides/auth/social-login/auth-kakao)         |
| Keycloak (OIDC)   | `KEYCLOAK_`      | `URL` (realm URL, **required**) | [Login with Keycloak](/docs/guides/auth/social-login/auth-keycloak)   |
| LinkedIn (OIDC)   | `LINKEDIN_OIDC_` | -                               | [Login with LinkedIn](/docs/guides/auth/social-login/auth-linkedin)   |
| Notion            | `NOTION_`        | -                               | [Login with Notion](/docs/guides/auth/social-login/auth-notion)       |
| Slack (OIDC)      | `SLACK_OIDC_`    | -                               | [Login with Slack](/docs/guides/auth/social-login/auth-slack)         |
| Snapchat          | `SNAPCHAT_`      | -                               | -                                                                     |
| Spotify           | `SPOTIFY_`       | -                               | [Login with Spotify](/docs/guides/auth/social-login/auth-spotify)     |
| Twitch            | `TWITCH_`        | -                               | [Login with Twitch](/docs/guides/auth/social-login/auth-twitch)       |
| Twitter           | `TWITTER_`       | -                               | [Login with Twitter](/docs/guides/auth/social-login/auth-twitter)     |
| WorkOS            | `WORKOS_`        | -                               | [Login with WorkOS](/docs/guides/auth/social-login/auth-workos)       |
| Zoom              | `ZOOM_`          | -                               | [Login with Zoom](/docs/guides/auth/social-login/auth-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 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](/docs/guides/auth/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:

```yaml name=docker-compose.yml
auth:
  environment:
    # ... existing variables ...
    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.

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

```yaml name=docker-compose.yml
auth:
  environment:
    # ... existing variables ...
    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`:

| 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](/docs/guides/auth/redirect-urls)
- [Auth server on GitHub](https://github.com/supabase/auth) (check README and `example.env`)