Skip to main content
Toolshed uses Better Auth for OAuth social providers with built-in support for GitHub, Google, Slack, and Linear. Additional providers (QuickBooks, GCP, DocuSign, Carta) use the Generic OAuth plugin.

Supported OAuth providers

ProviderMechanismPKCEUsed for
GitHubSocialNoUser login + repos/issues
GoogleSocialYesUser login + Gmail/Calendar/Drive
SlackSocialNoTeam messaging
LinearSocialYesIssue tracking
QuickBooksgenericOAuthNoAccounting
GCPgenericOAuthYesGoogle Cloud (Compute, Storage, BigQuery, IAM)
DocuSigngenericOAuthNoDocument signing
CartagenericOAuthYesEquity management
The two mechanisms register at different paths and use different frontend APIs — see Auth Routes. The connector availability endpoint reports which ones are wired up: GET /api/connectors/availability.

Environment variables

OAuth providers are configured conditionally — only providers with both CLIENT_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:
# Required for auth
BETTER_AUTH_SECRET=your-secret-min-32-chars
TOOLSHED_API_SECRET=your-api-secret

# Database
DATABASE_URL=postgresql://...

# Google (for user login + workspace tools)
GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...

# Add others as needed
GITHUB_CLIENT_ID=...
GITHUB_CLIENT_SECRET=...

Connecting from the web app

  1. Sign in at http://localhost:5173 with email/password or Google
  2. Go to the Tools tab
  3. Click Connect on any tool to initiate the OAuth flow or enter an API key
  4. For team tools, an admin connects once and the tool becomes available to all users

Connecting from the CLI

toolshed login --server http://localhost:3000
toolshed connect github
toolshed connect google
toolshed status

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/oauth2/callback/${providerId}
Social providers (GitHub / Google / Slack / Linear) use ${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’s accountLinking 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:
  1. Scope: use https://www.googleapis.com/auth/cloud-platform.read-only rather than per-API scopes (compute.readonly, iam.readonly, etc.). The IAM scope in particular is not real and Google will reject the consent request.
  2. OIDC scopes: include openid, email, profile so Better Auth can fetch user identity for account-linking. Without these, the callback fails with user_info_is_missing.
  3. userInfoUrl: set to https://openidconnect.googleapis.com/v1/userinfo.
  4. 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_KEY env vars on the server. The third source in resolveToken() (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 call ctx.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.