Skip to main content

OAuth Providers

This guide walks through registering OAuth 2.0 / OpenID Connect apps for the four providers Orkestra supports out of the box: Google, Apple, GitHub, and Discord. Email/password login works without any of these — OAuth is opt-in.

:::info Where credentials live As of the auth-module ConfigService refactor (PR-C), OAuth client IDs, secrets, and redirect URLs are runtime configuration owned by the auth module. The recommended workflow:

  1. (Optional) Seed env vars on a fresh install — the auth module reads OAUTH_<PROVIDER>_* on first boot and writes them into module_configs in MongoDB.
  2. Manage them from then on at /admin/modules/auth in the operator console. Secrets are AES-256-GCM encrypted at rest.

Env-var names follow the convention OAUTH_<PROVIDER>_<FIELD> (e.g. OAUTH_GOOGLE_CLIENT_ID). Older docs that show GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET without the OAUTH_ prefix are stale.

See backend/internal/core/auth/CLAUDE.md for the canonical field-by-field schema. :::

Prerequisites

  • Access to the respective provider developer portals (Google Cloud Console, Apple Developer, GitHub, Discord)
  • Orkestra backend running and reachable at your operator and client hosts. Set ALLOW_LOCALHOST_REDIRECTS=true in docker/.env for development; do not ship that to production.

Google OAuth setup

Step 1: access Google Cloud Console

  1. Go to Google Cloud Console.
  2. Sign in with your Google account.
  3. Create a new project or select an existing one.

Step 2: enable required APIs

  1. Navigate to APIs & ServicesLibrary.
  2. Search for and enable:
    • Google+ API
    • Google Identity Toolkit API
  1. Go to APIs & ServicesOAuth consent screen.
  2. Choose External user type (unless for internal organization).
  3. Fill in the required information:
    • App name: Orkestra
    • User support email: your support email
    • App logo: upload your logo (optional)
    • Application home page: https://yourdomain.com
    • Authorized domains: add your domain(s)
    • Developer contact information: your email
  4. Add scopes: openid, email, profile.
  5. Save and continue.

Step 4: create OAuth 2.0 credentials

  1. Navigate to APIs & ServicesCredentials.
  2. Click Create CredentialsOAuth client ID.
  3. Select Web application as the application type.
  4. Configure:
    • Name: Orkestra Web Client
    • Authorized JavaScript origins:
      • https://console.orkestra.com (operator, prod)
      • https://api.orkestra.com (client, prod)
      • http://console.localhost:8080 (dev, operator)
      • http://client.localhost:8081 (dev, client)
    • Authorized redirect URI (one callback, on the operator backend, not the frontend):
      • https://console.orkestra.com/v1/auth/oauth/google/callback
      • http://console.localhost:3000/v1/auth/oauth/google/callback (dev, operator) The signed OAuth state selects the operator or client auth service after this callback, so client-tier flows do not need a client-host callback URI.
  5. Click Create.
  6. Save the Client ID and Client Secret — paste them into /admin/modules/auth under the Google group (or set OAUTH_GOOGLE_CLIENT_ID / OAUTH_GOOGLE_CLIENT_SECRET as seed env vars on first boot).

Step 5: mobile app configuration (if needed)

  1. Create another OAuth client ID.
  2. Select iOS or Android as the application type.
  3. For iOS: enter your Bundle ID.
  4. For Android: enter your Package name and your SHA-1 certificate fingerprint.
  5. Save the configuration.

Apple Sign In setup

Step 1: access Apple Developer account

  1. Go to Apple Developer.
  2. Sign in with your Apple ID.
  3. Ensure you have an active Developer Program membership.

Step 2: register App ID

  1. Navigate to Certificates, Identifiers & Profiles.
  2. Click Identifiers+ button.
  3. Select App IDs and click Continue.
  4. Select App and click Continue.
  5. Fill in:
    • Description: Orkestra
    • Bundle ID: Choose Explicit and enter com.yourdomain.orkestra
  6. Under Capabilities, enable Sign In with Apple.
  7. Click Continue and Register.

Step 3: create Service ID (for Web)

  1. In Identifiers, click + button.
  2. Select Services IDs and click Continue.
  3. Fill in:
    • Description: Orkestra Web Service
    • Identifier: com.yourdomain.orkestra.web
  4. Click Continue and Register.
  5. Click on the created Service ID to configure.
  6. Enable Sign In with Apple.
  7. Click Configure next to Sign In with Apple.
  8. Set:
    • Primary App ID: select your App ID from Step 2.
    • Domains and Subdomains: add the operator callback host (for example, console.orkestra.com). Apple does not accept localhost; use ngrok for local development.
    • Return URL (one callback on the operator backend):
      • https://console.orkestra.com/v1/auth/oauth/apple/callback The signed OAuth state dispatches the completed flow to the client tier when that is where it started; do not register a client-host callback.
  9. Click Next, Done, and Continue.
  10. Click Save.

Step 4: create private key

  1. Navigate to Keys+ button.
  2. Enter a Key Name: Orkestra Auth Key.
  3. Enable Sign In with Apple.
  4. Click Continue and Register.
  5. Download the private key (.p8 file).
    • IMPORTANT: save this file securely — you can't download it again.
  6. Note the Key ID shown on the page.

Step 5: gather required information

You'll need:

  • Team ID: found in your Apple Developer account (top right corner).
  • Service ID: the identifier created in Step 3 (e.g. com.yourdomain.orkestra.web).
  • Key ID: from Step 4.
  • Private Key: the .p8 file downloaded in Step 4.

Apple private-key incident response

Treat a suspected Apple .p8 private-key exposure as an incident. In order:

  1. Identify every affected environment and the Apple configuration each uses.
  2. Restrict access to, and sanitize where retention policy permits, local and OTLP log records that could contain the key or related credential material. Preserve only the incident evidence required by policy.
  3. In Apple Developer, rotate the key and invalidate the exposed key.
  4. Update the encrypted auth module configuration with the replacement Apple key and its matching key ID.
  5. Do not restart a service unless the live configuration behavior requires it; the application does not rotate an external Apple key for you.
  6. Force reauthentication for affected users and monitor OAuth failures while the replacement is in use.

GitHub OAuth setup

  1. Go to GitHub Developer Settings → OAuth Apps.
  2. Click New OAuth App and fill in:
    • Application name: Orkestra
    • Homepage URL: https://console.orkestra.com (or your operator host)
    • Authorization callback URL: https://console.orkestra.com/v1/auth/oauth/github/callback
  3. Register the app, then click Generate a new client secret.
  4. Save the Client ID and Client Secret — paste them into /admin/modules/auth under the GitHub group (or use OAUTH_GITHUB_CLIENT_ID / OAUTH_GITHUB_CLIENT_SECRET as seed env vars).
  5. Register the single operator-host callback above. The signed OAuth state dispatches a completed client-tier flow to the client auth service, so a second client-host callback or provider app is not required for the audience split.

Discord OAuth setup

  1. Go to the Discord Developer Portal and create a New Application.
  2. Open OAuth2 → General. Add the single operator-host redirect:
    • https://console.orkestra.com/v1/auth/oauth/discord/callback
    • http://console.localhost:3000/v1/auth/oauth/discord/callback (dev) The signed OAuth state dispatches client-tier flows after the callback; do not add a client-host callback.
  3. Click Reset Secret to generate a client secret.
  4. Save the Client ID and Client Secret — paste them into /admin/modules/auth under the Discord group (or OAUTH_DISCORD_CLIENT_ID / OAUTH_DISCORD_CLIENT_SECRET).
  5. Required scopes Orkestra requests: identify email.

Environment configuration

Backend (seed env vars, optional)

These env vars are read only on first boot of a fresh install to seed module_configs. After that, manage values from /admin/modules/auth. Secrets are AES-256-GCM encrypted at rest by ConfigService.

# Google OAuth
OAUTH_GOOGLE_CLIENT_ID=your-google-client-id.apps.googleusercontent.com
OAUTH_GOOGLE_CLIENT_SECRET=your-google-client-secret
OAUTH_GOOGLE_REDIRECT_URL=https://console.orkestra.com/v1/auth/oauth/google/callback

# Apple Sign In
OAUTH_APPLE_TEAM_ID=your-team-id
OAUTH_APPLE_CLIENT_ID=com.yourdomain.orkestra.web # Apple Service ID
OAUTH_APPLE_KEY_ID=your-key-id
OAUTH_APPLE_PRIVATE_KEY=-----BEGIN PRIVATE KEY-----\n... # inline PEM (preferred)
OAUTH_APPLE_PRIVATE_KEY_PATH=/app/keys/AuthKey_XXXXXX.p8 # OR file fallback
OAUTH_APPLE_REDIRECT_URL=https://console.orkestra.com/v1/auth/oauth/apple/callback

# GitHub
OAUTH_GITHUB_CLIENT_ID=your-github-client-id
OAUTH_GITHUB_CLIENT_SECRET=your-github-client-secret
OAUTH_GITHUB_REDIRECT_URL=https://console.orkestra.com/v1/auth/oauth/github/callback

# Discord
OAUTH_DISCORD_CLIENT_ID=your-discord-client-id
OAUTH_DISCORD_CLIENT_SECRET=your-discord-client-secret
OAUTH_DISCORD_REDIRECT_URL=https://console.orkestra.com/v1/auth/oauth/discord/callback

# JWT — Orkestra uses RS256 (asymmetric), NOT a shared HMAC secret.
# `make init` generates these for you under docker/keys/ — see init.sh.
JWT_PRIVATE_KEY_PATH=/app/keys/jwt-private.pem
JWT_PUBLIC_KEY_PATH=/app/keys/jwt-public.pem

Frontend

The browser never talks to OAuth providers directly — it starts at the tier-specific backend endpoint POST /v1/auth/{tier}/oauth/login, which returns the provider authorization URL with state, scopes, and the configured single operator-host callback. So the frontend does not need provider client IDs.

# frontend-admin (operator console) — .env.production
VITE_API_URL=https://console.orkestra.com

# frontend-client (Tier-2 client SPA) — .env.production
VITE_API_BASE=https://api.orkestra.com

Mobile

For the Flutter mobile app, update:

iOSios/Runner/Info.plist:

<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>com.googleusercontent.apps.YOUR_GOOGLE_IOS_CLIENT_ID</string>
</array>
</dict>
</array>

Android — add the Google services configuration file to android/app/google-services.json.

Testing OAuth integration

Local development

  1. Ensure your backend is running and reachable as both http://console.localhost:3000 (operator) and http://api.localhost:3000 (client) — the host mux dispatches on Host. Add entries to /etc/hosts if needed:

    127.0.0.1 console.localhost api.localhost client.localhost
  2. Start the frontends — operator on http://console.localhost:8080, client SPA on http://client.localhost:8081.

  3. From the operator login page, start Google OAuth through POST /v1/auth/operator/oauth/login. The browser follows the returned authorization URL to Google, then returns to http://console.localhost:3000/v1/auth/oauth/google/callback, the single operator-host callback.

  4. Repeat from the client SPA through POST /v1/auth/client/oauth/login; its signed state makes the same operator-host callback dispatch to the client auth service, which issues aud=client and the client-tier refresh cookie.

Production

  1. Deploy your application to your domain.
  2. Ensure HTTPS is properly configured.
  3. Test both authentication flows (operator + client).
  4. Verify tokens are properly generated and stored.

Security best practices

  1. Never commit secrets to version control.
  2. Use environment variables (or, better, ConfigService) for all sensitive configuration.
  3. Implement HTTPS for production deployments.
  4. Rotate keys periodically.
  5. Implement rate limiting on authentication endpoints (built in — RATE_LIMIT_REQUESTS_PER_MINUTE / RATE_LIMIT_BURST).
  6. Log authentication attempts for security monitoring (built in — see compliance addon).
  7. Use secure session management with JWT tokens (built in — RS256, refresh-token rotation).
  8. Implement refresh token rotation (built in — see backend/internal/core/auth/).

Troubleshooting

Common Google OAuth issues

Error: redirect_uri_mismatch

  • Ensure the redirect URI in your request matches exactly with configured URIs.
  • Check for trailing slashes and protocol (http vs https).

Error: invalid_client

  • Verify Client ID and Client Secret are correct.
  • Check if the OAuth consent screen is properly configured.

Common Apple Sign In issues

Error: invalid_grant

  • Ensure the authorization code is used only once.
  • Verify the redirect URI matches exactly.

Error: invalid_client

  • Check Team ID, Service ID, and Key ID are correct.
  • Verify the private key file is accessible and valid.

JWT token issues

  • Ensure the private key file has correct permissions.
  • Verify the key hasn't expired.
  • Check the algorithm matches (ES256 for Apple).

Support

Pre-production checklist

  • Google OAuth credentials created and configured for the intended audiences
  • Apple Sign In credentials created and configured (operator callback host; ngrok used for local)
  • GitHub OAuth app created with the operator-host callback
  • Discord OAuth credentials created and configured
  • Credentials stored in /admin/modules/auth (ConfigService), not in plain .env in prod
  • Each provider's redirect URI is registered on the operator host (console.orkestra.com in these examples)
  • RS256 keys (jwt-private.pem / jwt-public.pem) generated and JWT_PRIVATE_KEY_PATH / JWT_PUBLIC_KEY_PATH set
  • HTTPS enabled on production
  • OAuth tested in development environment (both operator and client tiers)
  • OAuth tested in production environment
  • Security best practices implemented
  • Monitoring and logging configured
  • Documentation shared with team