OAuth integrations need your own provider application on a self-hosted deployment. Configure the OAuth services your team uses; API-key integrations can instead use keys supplied in their blocks. Users will see the connector in the UI, click "Connect", and get an error from the provider until the corresponding *_CLIENT_ID and *_CLIENT_SECRET are set.
You only need to register the services your team actually uses. One OAuth app covers every Sim connector that shares its credential — a single Google app serves Gmail, Drive, Sheets, Calendar, Docs, Forms, BigQuery, and more.
How it works
Each connector has a provider ID. When a user connects an account, Sim redirects them to the provider, and the provider redirects back to:
https://<your-sim-domain>/api/auth/oauth2/callback/<provider-id>That URL is derived from NEXT_PUBLIC_APP_URL, so set it correctly before registering anything — the redirect URI you register with the provider must match byte for byte, including scheme and the absence of a trailing slash.
Most providers let you register several redirect URIs on one app. Register your production URL and any staging URL together so one OAuth app serves both environments.
Setup
Confirm your public URL
NEXT_PUBLIC_APP_URL=https://sim.yourdomain.com
BETTER_AUTH_URL=https://sim.yourdomain.comBoth must be your real public origin. If these are wrong, every OAuth round-trip fails with a redirect-URI mismatch.
Register an app with the provider
In the provider's developer console, create an OAuth 2.0 application. Register the redirect URI(s) for every Sim connector you want from that provider — one line per provider ID from the tables below.
For a Google app covering Gmail and Drive, for example, you register both:
https://sim.yourdomain.com/api/auth/oauth2/callback/google-email
https://sim.yourdomain.com/api/auth/oauth2/callback/google-driveScopes are requested by Sim at authorization time; you generally do not need to pre-declare them, but Google and Microsoft require you to enable the corresponding APIs on the project/app first (for example Gmail API, Drive API, Calendar API).
Set the credentials
Add the client ID and secret to the app's environment. In Kubernetes they go under app.env — the chart writes every key there into a chart-managed Secret — but supply the values through External Secrets or a pre-created Secret rather than committing them to a values file:
app:
env:
GOOGLE_CLIENT_ID: "..."
GOOGLE_CLIENT_SECRET: "..."
SLACK_CLIENT_ID: "..."
SLACK_CLIENT_SECRET: "..."Restart the app. Credentials are read at startup — a running pod will not pick up new ones.
Verify
Open a workflow, add the integration's block, and connect an account. A successful round-trip returns you to Sim with the account listed. A redirect-URI mismatch is the failure you will hit most; compare the registered URI against NEXT_PUBLIC_APP_URL character by character.
Provider reference
Every provider ID below maps to the redirect URI https://<your-domain>/api/auth/oauth2/callback/<provider-id>.
One OAuth client in Google Cloud Console covers all of these. Enable the matching API for each connector you use.
| Environment variables | Provider IDs |
|---|---|
GOOGLE_CLIENT_IDGOOGLE_CLIENT_SECRET | google-email, google-drive, google-sheets, google-docs, google-calendar, google-contacts, google-forms, google-tasks, google-meet, google-groups, google-chat, google-ads, google-bigquery, google-vault, vertex-ai |
The same variables also power "Sign in with Google". See Authentication.
Microsoft
One app registration in Entra ID covers all of these.
| Environment variables | Provider IDs |
|---|---|
MICROSOFT_CLIENT_IDMICROSOFT_CLIENT_SECRET | outlook, onedrive, sharepoint, microsoft-teams, microsoft-excel, microsoft-word, microsoft-planner, microsoft-dataverse, microsoft-ad |
The same variables also power "Sign in with Microsoft".
GitHub Search
Self-hosted GitHub Search uses a GitHub App for account connections and organization installation indexing. Register your own App and configure the server variables below. Sim Cloud users use the GitHub Search setup flow directly.
Register the App
For a team, open Your organizations → Settings for the organization that will own the App. For a personal App, open your account's Settings. Then choose Developer settings → GitHub Apps → New GitHub App.
Give the App a unique, recognizable name, such as Your Company Sim Search, and set Homepage URL to your Sim URL.
Under Identifying and authorizing users → Redirect URI (callback URL), enter:
<NEXT_PUBLIC_APP_URL>/api/auth/oauth2/callback/github-repositoriesReplace <NEXT_PUBLIC_APP_URL> with your configured public origin, such as https://sim.example.com, without a trailing slash. The scheme, hostname, port, and path must match exactly; www and non-www hosts are different. See GitHub's callback matching rules.
| GitHub setting | Value for Sim Search |
|---|---|
| Allow wildcard matching | Disabled |
| Expire user authorization tokens | Enabled |
| Request user authorization (OAuth) during installation | Disabled |
| Enable Device Flow | Disabled |
| Post installation → Setup URL | <NEXT_PUBLIC_APP_URL>/api/knowledge/github/setup/callback |
| Post installation → Redirect on update | Enabled |
| Webhook → Active | Disabled |
Authorization starts from Sim so the callback can finish the pending connection. The Setup URL returns installation approval to that same setup attempt. Keep Request user authorization (OAuth) during installation disabled: Sim starts account authorization when it is needed, before installation. See GitHub's Setup URL guide.
For an existing deployment, deploy the application with the setup callback before changing the App registration. Use a separate GitHub App for each deployment origin, such as staging and production, so installation approval returns to the instance that started it. Keep the existing user authorization callback above unchanged.
The connector polls GitHub's API and does not need a webhook.
Set read permissions
Expand Permissions → Repository permissions. Set Contents → Access: Read-only; leave the mandatory Metadata permission at Read-only.
Expand Account permissions and set Email addresses → Access: Read-only.
| Permission area | Permission | Access |
|---|---|---|
| Repository | Contents | Read-only |
| Repository | Metadata | Read-only |
| Account | Email addresses | Read-only |
Leave every other permission at No access. Sim does not need issue, pull-request, administration, or write permissions. GitHub's registration guide explains these settings.
GitHub App user tokens use these permissions rather than OAuth scopes. An empty scope value in the token response is expected; see GitHub's user token reference.
Set Where can this GitHub App be installed? → Any account to support connections from accounts outside the App owner. This lets any GitHub account install and authorize the App, subject to that account's organization policies. Making the App public does not make repositories public or grant anyone Search access. See GitHub's App visibility rules.
Select Create GitHub App.
Configure Sim
On the App's General settings page, copy its numeric App ID and Client ID, select Generate a new client secret, and generate a Private key. The App slug is the final part of its public URL: https://github.com/apps/<app-slug>.
Set all five variables using values from your GitHub App, then restart Sim:
GITHUB_APP_ID=<numeric App ID>
GITHUB_APP_SLUG=<app-slug>
GITHUB_APP_CLIENT_ID=<Client ID>
GITHUB_APP_CLIENT_SECRET=<Client secret>
GITHUB_APP_PRIVATE_KEY=<complete RSA PEM private key>The private key must include its PEM header, footer, and contents. Sim accepts actual newlines or escaped \n sequences. When storing it in a JSON secret, use the plaintext JSON editor and encode each line break as \n inside the string. Single-line key/value fields can remove line breaks; replacing them with spaces makes the PEM invalid. Restart Sim after saving configuration changes.
Keep the private key and client secret in the deployment's server configuration; organization admins select installations in Sim without entering these secrets.
If you run Search indexing on Trigger.dev, configure the same five variables in its matching environment. The app server and indexing worker both need the App credentials; updating the app's secret store alone does not update a separately configured worker.
The Client ID is different from the numeric App ID. Use credentials from Developer settings → GitHub Apps. GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET belong to the separate GitHub sign-in integration and remain unchanged. Search does not read GITHUB_REPO_CLIENT_ID or GITHUB_REPO_CLIENT_SECRET.
Keep Expire user authorization tokens enabled so Sim receives the refresh token it needs to renew personal connections.
Complete the installation through the GitHub Search source setup.
If you replace a deployment's GitHub App, an organization admin selects Settings → Sources → More → Refresh connection settings. When Search is disabled, use Connected accounts → Providers → Update configurations in organization settings. This applies the deployment's current App configuration to all existing providers while preserving their option IDs. Accounts whose App configuration changed must reconnect. Then reconnect personal GitHub accounts and connect an installation of the new App. Reconnecting alone cannot update the organization's saved App configuration.
If GitHub rejects redirect_uri, compare the App's registered callback with NEXT_PUBLIC_APP_URL followed by /api/auth/oauth2/callback/github-repositories. Keep wildcard matching disabled. If installation indexing is unavailable, confirm all five GITHUB_APP_* variables belong to the same App and include a complete RSA private key.
GitHub workflow blocks and knowledge-base token connections continue to use personal access tokens.
Everything else
| Service | Environment variables | Provider ID |
|---|---|---|
| Slack | SLACK_CLIENT_ID / SLACK_CLIENT_SECRET | slack |
| Notion | NOTION_CLIENT_ID / NOTION_CLIENT_SECRET | notion |
| Jira | JIRA_CLIENT_ID / JIRA_CLIENT_SECRET | jira |
| Confluence | CONFLUENCE_CLIENT_ID / CONFLUENCE_CLIENT_SECRET | confluence |
| Linear | LINEAR_CLIENT_ID / LINEAR_CLIENT_SECRET | linear |
| Asana | ASANA_CLIENT_ID / ASANA_CLIENT_SECRET | asana |
| ClickUp | CLICKUP_CLIENT_ID / CLICKUP_CLIENT_SECRET | clickup |
| Monday | MONDAY_CLIENT_ID / MONDAY_CLIENT_SECRET | monday |
| Airtable | AIRTABLE_CLIENT_ID / AIRTABLE_CLIENT_SECRET | airtable |
| Bitbucket | BITBUCKET_CLIENT_ID / BITBUCKET_CLIENT_SECRET | bitbucket |
| HubSpot | HUBSPOT_CLIENT_ID / HUBSPOT_CLIENT_SECRET | hubspot |
| Salesforce | SALESFORCE_CLIENT_ID / SALESFORCE_CLIENT_SECRET | salesforce |
| Pipedrive | PIPEDRIVE_CLIENT_ID / PIPEDRIVE_CLIENT_SECRET | pipedrive |
| Attio | ATTIO_CLIENT_ID / ATTIO_CLIENT_SECRET | attio |
| Zoho Desk | ZOHO_CLIENT_ID / ZOHO_CLIENT_SECRET | zoho-desk |
| Wealthbox | WEALTHBOX_CLIENT_ID / WEALTHBOX_CLIENT_SECRET | wealthbox |
| Box | BOX_CLIENT_ID / BOX_CLIENT_SECRET | box |
| Dropbox | DROPBOX_CLIENT_ID / DROPBOX_CLIENT_SECRET | dropbox |
| DocuSign | DOCUSIGN_CLIENT_ID / DOCUSIGN_CLIENT_SECRET | docusign |
| Zoom | ZOOM_CLIENT_ID / ZOOM_CLIENT_SECRET | zoom |
| Cal.com | CALCOM_CLIENT_ID only — PKCE public client, no secret | calcom |
| Webflow | WEBFLOW_CLIENT_ID / WEBFLOW_CLIENT_SECRET | webflow |
| WordPress | WORDPRESS_CLIENT_ID / WORDPRESS_CLIENT_SECRET | wordpress |
LINKEDIN_CLIENT_ID / LINKEDIN_CLIENT_SECRET | linkedin | |
| X | X_CLIENT_ID / X_CLIENT_SECRET | x |
REDDIT_CLIENT_ID / REDDIT_CLIENT_SECRET | reddit | |
| Spotify | SPOTIFY_CLIENT_ID / SPOTIFY_CLIENT_SECRET | spotify |
| TikTok | TIKTOK_CLIENT_ID / TIKTOK_CLIENT_SECRET | tiktok |
For Bitbucket, create an OAuth consumer and register
https://<your-domain>/api/auth/oauth2/callback/bitbucket as its callback URL. Bitbucket fixes
permissions on the consumer instead of narrowing them per authorization request. Enable exactly
Account read, Repositories read/write, Pull requests read/write, Pipelines read/write, and Webhooks
read/write (account, repository, repository:write, pullrequest, pullrequest:write,
pipeline, pipeline:write, and webhook). The webhook permission is required for automatic
trigger subscription management.
Services with a different flow
| Service | Configuration | Notes |
|---|---|---|
INSTAGRAM_CLIENT_ID / INSTAGRAM_CLIENT_SECRET | Instagram App ID/Secret from the Meta App Dashboard (Instagram → API setup with Instagram login). Redirect URI: /api/auth/oauth2/callback/instagram. Publishing requires cloud object storage — Meta fetches a public HTTPS URL, so local-disk storage will not work. | |
| Shopify | SHOPIFY_CLIENT_ID / SHOPIFY_CLIENT_SECRET | Redirect URI: /api/auth/oauth2/callback/shopify. Per-shop install flow. |
| Trello | TRELLO_API_KEY | API-key based, not OAuth 2.0. Callback: /api/auth/trello/callback. |
Non-OAuth integration credentials
Many blocks authenticate with an API key the user pastes into the block, and need nothing from you.
Sim also has a "hosted key" mechanism, configured with the {PREFIX}_API_KEY_COUNT + {PREFIX}_API_KEY_1..N variables below, that lets the platform supply a key so users do not have to. The injection path is gated on the deployment being Sim's hosted platform (isHosted, derived from the app hostname), so on a self-hosted instance these variables do not remove the need for users to bring their own key. Set them only if you are running a fork that has adapted that gate.
The variables, for reference:
| Variable | Service |
|---|---|
EXA_API_KEY (or EXA_API_KEY_COUNT + EXA_API_KEY_1..N) | Exa search |
SERPER_API_KEY | Serper search |
BROWSERBASE_API_KEY / BROWSERBASE_PROJECT_ID | Browserbase |
HUNTER_API_KEY_COUNT + HUNTER_API_KEY_1..N | Hunter.io |
PEOPLEDATALABS_API_KEY_COUNT + PEOPLEDATALABS_API_KEY_1..N | People Data Labs |
CONTEXT_DEV_API_KEY_COUNT + CONTEXT_DEV_API_KEY_1..N | Context.dev |
FALAI_API_KEY | fal.ai |
TWILIO_ACCOUNT_SID / TWILIO_AUTH_TOKEN / TWILIO_PHONE_NUMBER | Twilio |
AGENTMAIL_API_KEY / AGENTMAIL_DOMAIN | AgentMail |
Providers that take a _COUNT plus numbered keys distribute requests round-robin across them.
Triggers that need extra configuration
Webhook triggers receive callbacks from the provider and must be able to verify them:
| Variable | Needed for |
|---|---|
SLACK_SIGNING_SECRET | Verifying Slack event and slash-command signatures |
SLACK_EXTENDED_SCOPES / NEXT_PUBLIC_SLACK_EXTENDED_SCOPES | Enabling the native Sim-app trigger and its broader Slack scope set; set both to the same value |
When enabling the native Sim Slack trigger, configure all three variables together. Enable the extended-scope flags only after Slack approves the app for assistant:write, app_mentions:read, and im:history; otherwise Slack rejects OAuth authorization. Slack OAuth actions can use SLACK_CLIENT_ID and SLACK_CLIENT_SECRET without enabling the native trigger or supplying a signing secret.
Your deployment must also be reachable from the provider's servers for webhook triggers to fire — a Sim instance on a private network can use polling triggers but not webhook triggers. Polling triggers additionally require the scheduler; see Background Jobs.