> ## Documentation Index
> Fetch the complete documentation index at: https://docs.toolshed.philo.ventures/llms.txt
> Use this file to discover all available pages before exploring further.

# OAuth Setup

> Configure OAuth providers and API key connections for Toolshed tools.

Toolshed uses [Better Auth](https://better-auth.com) 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

| Provider   | Mechanism      | PKCE | Used for                                       |
| ---------- | -------------- | ---- | ---------------------------------------------- |
| GitHub     | Social         | No   | User login + repos/issues                      |
| Google     | 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                              |

The two mechanisms register at different paths and use different frontend APIs — see [Auth Routes](/server/auth#oauth-providers-split-into-two-flows). The connector availability endpoint reports which ones are wired up: [`GET /api/connectors/availability`](/server/connectors).

## 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:

```bash theme={null}
# 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

```bash theme={null}
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/connections).
* **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](/server/tokens)). 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](/server/tokens).
