Integrations & OAuth

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.com

Both 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-drive

Scopes 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>.

Google

One OAuth client in Google Cloud Console covers all of these. Enable the matching API for each connector you use.

Environment variablesProvider IDs
GOOGLE_CLIENT_ID
GOOGLE_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 variablesProvider IDs
MICROSOFT_CLIENT_ID
MICROSOFT_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".

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-repositories

Replace <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 settingValue for Sim Search
Allow wildcard matchingDisabled
Expire user authorization tokensEnabled
Request user authorization (OAuth) during installationDisabled
Enable Device FlowDisabled
Post installation → Setup URL<NEXT_PUBLIC_APP_URL>/api/knowledge/github/setup/callback
Post installation → Redirect on updateEnabled
Webhook → ActiveDisabled

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 areaPermissionAccess
RepositoryContentsRead-only
RepositoryMetadataRead-only
AccountEmail addressesRead-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

ServiceEnvironment variablesProvider ID
SlackSLACK_CLIENT_ID / SLACK_CLIENT_SECRETslack
NotionNOTION_CLIENT_ID / NOTION_CLIENT_SECRETnotion
JiraJIRA_CLIENT_ID / JIRA_CLIENT_SECRETjira
ConfluenceCONFLUENCE_CLIENT_ID / CONFLUENCE_CLIENT_SECRETconfluence
LinearLINEAR_CLIENT_ID / LINEAR_CLIENT_SECRETlinear
AsanaASANA_CLIENT_ID / ASANA_CLIENT_SECRETasana
ClickUpCLICKUP_CLIENT_ID / CLICKUP_CLIENT_SECRETclickup
MondayMONDAY_CLIENT_ID / MONDAY_CLIENT_SECRETmonday
AirtableAIRTABLE_CLIENT_ID / AIRTABLE_CLIENT_SECRETairtable
BitbucketBITBUCKET_CLIENT_ID / BITBUCKET_CLIENT_SECRETbitbucket
HubSpotHUBSPOT_CLIENT_ID / HUBSPOT_CLIENT_SECREThubspot
SalesforceSALESFORCE_CLIENT_ID / SALESFORCE_CLIENT_SECRETsalesforce
PipedrivePIPEDRIVE_CLIENT_ID / PIPEDRIVE_CLIENT_SECRETpipedrive
AttioATTIO_CLIENT_ID / ATTIO_CLIENT_SECRETattio
Zoho DeskZOHO_CLIENT_ID / ZOHO_CLIENT_SECRETzoho-desk
WealthboxWEALTHBOX_CLIENT_ID / WEALTHBOX_CLIENT_SECRETwealthbox
BoxBOX_CLIENT_ID / BOX_CLIENT_SECRETbox
DropboxDROPBOX_CLIENT_ID / DROPBOX_CLIENT_SECRETdropbox
DocuSignDOCUSIGN_CLIENT_ID / DOCUSIGN_CLIENT_SECRETdocusign
ZoomZOOM_CLIENT_ID / ZOOM_CLIENT_SECRETzoom
Cal.comCALCOM_CLIENT_ID only — PKCE public client, no secretcalcom
WebflowWEBFLOW_CLIENT_ID / WEBFLOW_CLIENT_SECRETwebflow
WordPressWORDPRESS_CLIENT_ID / WORDPRESS_CLIENT_SECRETwordpress
LinkedInLINKEDIN_CLIENT_ID / LINKEDIN_CLIENT_SECRETlinkedin
XX_CLIENT_ID / X_CLIENT_SECRETx
RedditREDDIT_CLIENT_ID / REDDIT_CLIENT_SECRETreddit
SpotifySPOTIFY_CLIENT_ID / SPOTIFY_CLIENT_SECRETspotify
TikTokTIKTOK_CLIENT_ID / TIKTOK_CLIENT_SECRETtiktok

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

ServiceConfigurationNotes
InstagramINSTAGRAM_CLIENT_ID / INSTAGRAM_CLIENT_SECRETInstagram 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.
ShopifySHOPIFY_CLIENT_ID / SHOPIFY_CLIENT_SECRETRedirect URI: /api/auth/oauth2/callback/shopify. Per-shop install flow.
TrelloTRELLO_API_KEYAPI-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:

VariableService
EXA_API_KEY (or EXA_API_KEY_COUNT + EXA_API_KEY_1..N)Exa search
SERPER_API_KEYSerper search
BROWSERBASE_API_KEY / BROWSERBASE_PROJECT_IDBrowserbase
HUNTER_API_KEY_COUNT + HUNTER_API_KEY_1..NHunter.io
PEOPLEDATALABS_API_KEY_COUNT + PEOPLEDATALABS_API_KEY_1..NPeople Data Labs
CONTEXT_DEV_API_KEY_COUNT + CONTEXT_DEV_API_KEY_1..NContext.dev
FALAI_API_KEYfal.ai
TWILIO_ACCOUNT_SID / TWILIO_AUTH_TOKEN / TWILIO_PHONE_NUMBERTwilio
AGENTMAIL_API_KEY / AGENTMAIL_DOMAINAgentMail

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:

VariableNeeded for
SLACK_SIGNING_SECRETVerifying Slack event and slash-command signatures
SLACK_EXTENDED_SCOPES / NEXT_PUBLIC_SLACK_EXTENDED_SCOPESEnabling 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.

Common Questions

Only for OAuth integrations your team uses. API-key integrations do not require an OAuth application. If an OAuth provider's credentials are unset, its connector cannot be connected. One Google app covers 15 connectors and one Microsoft app covers 9, so most deployments need only a handful of registrations.
Almost always NEXT_PUBLIC_APP_URL does not match the URI registered with the provider. Check for http vs https, a trailing slash, an apex-vs-www difference, or a port. The URI Sim sends is built from NEXT_PUBLIC_APP_URL at request time.
Yes, if the provider allows multiple redirect URIs on one app — register both hosts. Providers that allow only one URI need a separate app per environment.
Meta fetches media from a public HTTPS URL rather than accepting an upload, so published files must live in S3, Azure Blob, or GCS. Local-disk storage cannot serve them. Gmail attachments and other integrations do not have this constraint.