Integrations OAuth Administration Runbook

Tenant-scoped integrations authenticate through the platform OAuth2 authorization-code broker (/api/bots/:bot_id/integrations/oauth/:provider/start and /callback). The broker never embeds client secrets in code: each branch supplies its own provider application credentials, stored strictly in Vault. This runbook is the administrator checklist for enabling a provider family.

1. Register the platform application with the vendor

For every provider family below, create one developer application on the vendor console. Register the callback exactly as shown, replacing chat.generalbots.org when operating another domain.

FamilyVendor consoleCallback URL
HubSpotapp.hubspot.com β†’ App Marketplace β†’ Develop an apphttps://chat.generalbots.org/api/bots/*/integrations/oauth/hubspot/callback (register per-bot exact path)
Intercomapp.intercom.io β†’ Developer Hub.../integrations/oauth/intercom/callback
Todoistdeveloper.todoist.com β†’ Apps.../integrations/oauth/todoist/callback
Zoommarketplace.zoom.us β†’ Server-to-server is NOT used here; build OAuth app.../integrations/oauth/zoom/callback
Notionnotion.so/my-integrations β†’ External OAuth.../integrations/oauth/notion/callback
Google (Drive, Calendar, Sheets, Tasks, Photos, Forms, YouTube Analytics)console.cloud.google.com β†’ OAuth consent screen + OAuth client (Web)One client may serve all: .../integrations/oauth/<google_slug>/callback for every slug in use; add scopes listed in Β§3 to the consent screen and mark the app production
Microsoft (Outlook, Outlook Calendar, OneDrive, SharePoint)portal.azure.com β†’ App registrations β†’ Web redirect URI.../integrations/oauth/<ms_slug>/callback; enable offline_access
Meta (Instagram, Facebook Pages)developers.facebook.com β†’ My Apps β†’ Facebook Login β†’ Settings.../integrations/oauth/<slug>/callback; one app serves both slugs. Add the Facebook Page and the Instagram Business/Creator account linked to it as app testers while the app is in Development mode

The botserver builds redirect_uri from the incoming request host, so stage and production environments are registered separately.

2. Store client credentials in Vault (per branch)

Path contract:

gbo/{org_id}/{branch_id}/{bot_id}/integrations/oauth/{provider}

Keys: client_id, client_secret. Example:

vault kv put secret/gbo/<org>/<branch>/<bot>/integrations/oauth/hubspot \
    client_id=<id> client_secret=<secret>

Google/Microsoft families repeat the command once per concrete slug that the workspace will authorize (google_drive, outlook, …). A missing envelope makes the Authorize button answer HTTP 412 with an explanatory message.

3. Scopes requested by the built-in flow

ProviderScope string
hubspotcrm.objects.contacts.write crm.objects.deals.read
todoistdata:read_write
google_drivehttps://www.googleapis.com/auth/drive.readonly
google_calendarhttps://www.googleapis.com/auth/calendar.events
google_photoshttps://www.googleapis.com/auth/photoslibrary.readonly
google_formshttps://www.googleapis.com/auth/forms.body
youtube_analyticshttps://www.googleapis.com/auth/yt-analytics.readonly
outlook / outlook_calendar / onedrive / sharepointoffline_access https://graph.microsoft.com/.default
instagraminstagram_basic,instagram_content_publish,pages_show_list,pages_read_engagement,business_management
facebook_pagespages_show_list,pages_read_engagement,pages_manage_posts

Least privilege: request only what enabled actions need; rotate client secrets on the vendor console and update Vault in the same window.

4. Token lifecycle

Access tokens, rotated refresh tokens and expiry are persisted automatically (token_refresh worker runs hourly and refreshes anything expiring within two hours). No administrator action is required after initial configuration other than keeping the Vault envelope current when vendors rotate secrets.

Meta (Instagram, Facebook Pages)

The Meta code exchange answers with a user token that expires in about one hour, which is far shorter than any publishing workflow. The callback upgrades it in place with grant_type=fb_exchange_token and stores the resulting long-lived token (about 60 days); if the upgrade call fails the short-lived token is kept and the connection simply needs re-authorizing sooner.

Instagram publishing additionally requires a Facebook Page token rather than the user token. The adapter resolves it at call time from /me/accounts?fields=instagram_business_account,access_token, so:

  • the authorized user must manage the Page the Instagram account is linked to;
  • the Instagram account must be a Business or Creator account (personal accounts cannot publish through the Graph API);
  • a system-user token, or an envelope carrying ig_user_id together with page_access_token, bypasses the discovery call.

5. Troubleshooting

  • 412 at start: Vault envelope missing or lacks keys β€” recheck Β§2 path.
  • state signature mismatch: INTERNAL_API_TOKEN differs between nodes.
  • Vendor invalid_grant: refresh token revoked β€” disconnect and reconnect.