Skip to content
BoringStack
Star

OAuth provider setup

3 min read

Set up OAuth with Google, GitHub, and/or LinkedIn so users can sign in with their existing accounts. This runbook walks through each provider console.

Before creating OAuth apps, decide your domain and set these env vars. The app lives on app.<domain>. The public site on the apex does not handle sign-in, so OAuth callbacks, FRONTEND_URL and PUBLIC_API_URL all use the app host:

Terminal window
FRONTEND_URL=https://app.example.com
PUBLIC_API_URL=https://app.example.com # origin only; the API appends /api/v1

All three providers will ask for redirect URIs. The pattern is:

https://app.example.com/api/v1/auth/oauth/{provider}/callback

Where {provider} is google, github, or linkedin.

During development, the UI runs on localhost:7331 and proxies /api to the API. Register these additional redirect URIs in each provider console:

http://localhost:7331/api/v1/auth/oauth/google/callback
http://localhost:7331/api/v1/auth/oauth/github/callback
http://localhost:7331/api/v1/auth/oauth/linkedin/callback

Credentials go in infra/compose/compose/.env with the same variable names as production.

OAuth buttons render on the login page only when the API has credentials for a provider. The UI reads GET /api/v1/capabilities/ to determine which buttons to show. No UI-side OAuth client IDs are needed.

After changing env, restart the API:

Terminal window
./dev.sh restart api
  1. Google Cloud Console → APIs & Services → Credentials.

  2. Create OAuth client ID → Web application.

  3. Authorized redirect URIs: add:

https://app.example.com/api/v1/auth/oauth/google/callback
  1. Note the Client ID and Client secret.

  2. Add to compose/.env:

Terminal window
echo 'GOOGLE_OAUTH_CLIENT_ID=your-client-id.apps.googleusercontent.com' >> compose/.env
echo 'GOOGLE_OAUTH_CLIENT_SECRET=your-secret' >> compose/.env
  1. Restart the API.

Google requests scopes openid, email, and profile automatically. BoringStack handles the flow.

  1. GitHub → Settings → Developer settings → OAuth Apps → New OAuth App.

  2. Homepage URL: https://app.example.com

  3. Authorization callback URL:

https://app.example.com/api/v1/auth/oauth/github/callback
  1. Generate a Client secret.

  2. Add to compose/.env:

Terminal window
echo 'GITHUB_OAUTH_CLIENT_ID=your-github-client-id' >> compose/.env
echo 'GITHUB_OAUTH_CLIENT_SECRET=your-secret' >> compose/.env
  1. Restart the API.

BoringStack requests read:user and user:email scopes.

  1. LinkedIn Developer Portal → Create app.

  2. Under Auth → OAuth 2.0 settings → Authorized redirect URLs:

https://app.example.com/api/v1/auth/oauth/linkedin/callback
  1. Request the Sign In with LinkedIn using OpenID Connect product (required for the openid scope).

  2. Add credentials to compose/.env:

Terminal window
echo 'LINKEDIN_OAUTH_CLIENT_ID=your-linkedin-client-id' >> compose/.env
echo 'LINKEDIN_OAUTH_CLIENT_SECRET=your-secret' >> compose/.env
  1. Restart the API.

BoringStack requests openid, profile, and email scopes.

  1. Ensure Valkey is running (OAuth state storage).
  2. Hit GET /api/v1/capabilities/ and check that oauth.providers lists your configured providers.
  3. Open the login page. OAuth buttons appear only for providers with valid credentials.
  4. Try logging in. Successful flow: redirects to OAuth provider → redirects back → redirects to /dashboard.

If you’re using Provisioning with OpenTofu, add the same credentials to terraform.tfvars:

google_oauth_client_id = "op://Production/Google-OAuth/client_id"
google_oauth_client_secret = "op://Production/Google-OAuth/client_secret"
github_oauth_client_id = "op://Production/GitHub-OAuth/client_id"
github_oauth_client_secret = "op://Production/GitHub-OAuth/client_secret"
linkedin_oauth_client_id = "op://Production/LinkedIn-OAuth/client_id"
linkedin_oauth_client_secret = "op://Production/LinkedIn-OAuth/client_secret"

See terraform.tfvars.example for the complete example.