This guide covers the server-side configuration required to enable social login providers on a self-hosted Zuvo 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 Zuvo installation. See Self-Hosting with Docker.
API_EXTERNAL_URLset to the publicly reachable URL of your Zuvo instance (e.g.,https://<your-domain>/auth/v1).
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:
- Your app calls
supabase.auth.signInWithOAuth()and the browser redirects to the Auth service - The API gateway 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 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:
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}/callback
Step 4: Restart the auth service
sh run.sh recreate auth
Step 5: Verify the configuration
Check that the provider is enabled:
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
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
GOOGLE_ENABLED=true
GOOGLE_CLIENT_ID=your-google-client-id.apps.googleusercontent.com
GOOGLE_SECRET=your-google-client-secret
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}/callback
GitHub setup:
- Go to GitHub Developer Settings
- Click New OAuth app
- Fill in Homepage URL, e.g.,
https://<your-domain> - Set Authorization callback URL to:
https://<your-domain>/auth/v1/callback - Click Register application
- Copy the client ID, generate and copy a client secret
GITHUB_ENABLED=true
GITHUB_CLIENT_ID=your-github-client-id
GITHUB_SECRET=your-github-client-secret
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}/callback
Azure Portal setup:
- Go to Azure Portal
- Go to All services > Identity > App registrations via the navigation menu on the left
- Click New registration
- Add application Name
- Under Redirect URI, select Web and enter:
https://<your-domain>/auth/v1/callback - Click Register
- Copy the Application (client) ID
- Click on Client credentials > Add a certificate or secret
- Click on New client secret and add a client secret
- Copy the secret value (not "secret ID")
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
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}/callback
## Optional: uncomment for tenant-specific Azure login
# GOTRUE_EXTERNAL_AZURE_URL: ${AZURE_URL}
Apple Developer setup:
- Refer to Apple Developer documentation to learn how to enable App ID and create a Services ID
- Create a private key for sign in with Apple
- Generate a client secret JWT from your private key. See Apple Developer documentation for details.
APPLE_ENABLED=true
APPLE_CLIENT_ID=com.example.your-services-id
APPLE_SECRET=your-generated-jwt-client-secret
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}/callback
Keycloak setup:
- Open your Keycloak admin console
- Select (or create) the realm you want to use
- Go to Clients > Create client
- Set Client type to OpenID Connect
- Set Client ID (e.g.,
supabase) - On the next screen, enable Client authentication
- Under Valid redirect URIs, add:
https://<your-domain>/auth/v1/callback - Save, then go to the Credentials tab and copy the Client secret
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
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}/callback
GOTRUE_EXTERNAL_KEYCLOAK_URL: ${KEYCLOAK_URL}
Other supported providers
Zuvo 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.
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 3000in the same directory - Make sure
SITE_URLis set tohttp://localhost:3000in your self-hosted Zuvo.envconfiguration - Open your browser and go to
http://localhost:3000
<!doctype html>
<html>
<body>
<h1>Zuvo 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_*_ENABLEDis set totrueindocker-compose.yml - Verify the
.envvariable is not empty, e.g., check withsh run.sh printenv auth | 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:
auth:
environment:
# ... existing variables ...
GOTRUE_EXTERNAL_GOOGLE_ENABLED: ${GOOGLE_ENABLED}
Run sh run.sh printenv auth | 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.
To enable it, uncomment the following line in docker-compose.yml:
auth:
environment:
# ... existing variables ...
GOTRUE_EXTERNAL_SKIP_NONCE_CHECK: 'true'
Auth service fails to start
Check the auth container logs:
docker compose logs auth
Common causes:
- Missing required environment variable (e.g.,
CLIENT_IDorSECRETis empty) - Invalid
API_EXTERNAL_URL(must be a valid URL - including protocol and ending with/auth/v1)
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}/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)