Supported OAuth providers
| Provider | Mechanism | PKCE | Used for |
|---|---|---|---|
| GitHub | Social | No | User login + repos/issues |
| Social | Yes | User login + Gmail/Calendar/Drive | |
| Slack | Social | No | Team messaging |
| Linear | Social | Yes | Issue tracking |
| QuickBooks | genericOAuth | No | Accounting |
| GCP | genericOAuth | Yes | Google Cloud (Compute, Storage, BigQuery, IAM) |
| DocuSign | genericOAuth | No | Document signing |
| Carta | genericOAuth | Yes | Equity management |
GET /api/connectors/availability.
Environment variables
OAuth providers are configured conditionally — only providers with bothCLIENT_ID and CLIENT_SECRET set will be registered. This prevents startup errors in dev.
Copy apps/server/.env.example to apps/server/.env.local and fill in your credentials:
Connecting from the web app
- Sign in at
http://localhost:5173with email/password or Google - Go to the Tools tab
- Click Connect on any tool to initiate the OAuth flow or enter an API key
- For team tools, an admin connects once and the tool becomes available to all users
Connecting from the CLI
Generic OAuth callback URI
genericOAuth providers (QuickBooks / GCP / DocuSign / Carta) use a different callback path than social providers. When registering an OAuth client with the upstream provider, add the redirect URI:
${AUTH_BASE_URL}/api/auth/callback/${provider} instead. If you reuse the same OAuth client for both flows (e.g. mirroring GOOGLE_CLIENT_ID into GCP_CLIENT_ID to share the client between Google Workspace social-sign-in and GCP scopes), register both URIs.
Account linking
Toolshed enables Better Auth’saccountLinking so a user can connect multiple OAuth providers to one account by email match. This requires every provider to be in accountLinking.trustedProviders — otherwise the second sign-in fails with account_not_linked. The auth config lists every shipped OAuth provider as trusted.
GCP-specific notes
GCP OAuth requires a few extra steps to keep Better Auth happy:- Scope: use
https://www.googleapis.com/auth/cloud-platform.read-onlyrather than per-API scopes (compute.readonly,iam.readonly, etc.). The IAM scope in particular is not real and Google will reject the consent request. - OIDC scopes: include
openid,email,profileso Better Auth can fetch user identity for account-linking. Without these, the callback fails withuser_info_is_missing. userInfoUrl: set tohttps://openidconnect.googleapis.com/v1/userinfo.- Enable APIs in the Cloud project: the OAuth client’s underlying GCP project must have the relevant APIs enabled (Gmail API, Calendar API, etc.) —
gcloud services enable gmail.googleapis.com calendar-json.googleapis.com drive.googleapis.com --project=<id>.
API key tools
Tools that use API keys instead of OAuth fall into two groups:- User-supplied (Granola personal/enterprise) — entered via the dashboard’s API-key dialog, encrypted with AES-256-GCM, stored in
tool_connections. See Connections API. - Server env vars (Attio, Browserbase, Firecrawl, Perplexity) — set as
${UPPER}_API_KEYenv vars on the server. The third source inresolveToken()(see Token Vending). For Attio, create a workspace access token in Attio → Settings → Developers; OAuth (build.attio.com) is only needed if you intend to distribute an app to other Attio workspaces.
Token vending
Plugins callctx.auth.getToken(provider) to get a usable token. The runtime checks three sources in order: per-user tool_connections, then Better Auth’s stored OAuth token (auto-refreshing), then ${UPPER}_API_KEY env. See Token Vending.