Skip to content
TriedDocs
Integrations

OAuth connections

Connect CRMs, Cal.com and document stores with the provider's own consent screen, with PKCE, encrypted token storage and automatic refresh.

OAuth lets you connect a provider by signing in to it, instead of pasting an API token. Tried runs the authorization code flow, stores the tokens encrypted with the connection, and refreshes them before they expire.

Providers#

Provider Used for PKCE Scopes requested
hubspot CRM sync, apps No crm.objects.contacts.read crm.objects.contacts.write crm.schemas.contacts.read
salesforce CRM sync, apps Yes api refresh_token
dynamics365 CRM sync, apps Yes <instance_url>/user_impersonation offline_access
zoho CRM sync, apps No ZohoCRM.modules.ALL,ZohoCRM.settings.fields.READ,ZohoCRM.users.READ
gohighlevel CRM sync, apps No contacts.readonly contacts.write locations.readonly locations/customFields.readonly
cal_com Apps Yes READ_BOOKING WRITE_BOOKING READ_PROFILE
google_drive Synced sources Yes https://www.googleapis.com/auth/drive.readonly
onedrive Synced sources Yes Files.Read.All offline_access
notion Synced sources No none (Notion asks the user which pages to share)

Calendly and Zendesk connect with pasted credentials only.

Deployment setup Needs keys#

Each provider needs an OAuth client registered with the vendor, and its id and secret in the API's environment:

Provider Environment variables
HubSpot HUBSPOT_OAUTH_CLIENT_ID, HUBSPOT_OAUTH_CLIENT_SECRET
Salesforce SALESFORCE_OAUTH_CLIENT_ID, SALESFORCE_OAUTH_CLIENT_SECRET
Dynamics 365 DYNAMICS365_OAUTH_CLIENT_ID, DYNAMICS365_OAUTH_CLIENT_SECRET
Zoho ZOHO_OAUTH_CLIENT_ID, ZOHO_OAUTH_CLIENT_SECRET
GoHighLevel GOHIGHLEVEL_OAUTH_CLIENT_ID, GOHIGHLEVEL_OAUTH_CLIENT_SECRET
Cal.com CALCOM_OAUTH_CLIENT_ID, CALCOM_OAUTH_CLIENT_SECRET
Google Drive GOOGLE_DRIVE_OAUTH_CLIENT_ID, GOOGLE_DRIVE_OAUTH_CLIENT_SECRET
OneDrive ONEDRIVE_OAUTH_CLIENT_ID, ONEDRIVE_OAUTH_CLIENT_SECRET
Notion NOTION_OAUTH_CLIENT_ID, NOTION_OAUTH_CLIENT_SECRET

Optional per provider: <PREFIX>_OAUTH_AUTHORIZE_URL and <PREFIX>_OAUTH_TOKEN_URL override the vendor endpoints.

Register this redirect URI with every vendor app:

https://api.tried.com.au/oauth/callback

GET /oauth/providers returns the exact redirect URI for your deployment.

Without a client id, a provider uses the built-in mock OAuth provider. Its consent page says "Mock OAuth provider" and "No real account is used". Connections created through it stay in mock mode.

Connect from the dashboard#

CRM: Settings, Integrations, CRM sync, then Connect on the provider's card. After a successful connection the card shows Reconnect.

Apps: Connect app, choose the App, then Connect with HubSpot account (the label names the chosen app). For an existing app, open it and press Connect with OAuth (or Reconnect with OAuth).

Synced sources: in a knowledge base, Connect a folder, pick the provider, then Connect Google Drive (or OneDrive, Notion).

For Dynamics 365 the dashboard first asks for your organisation URL, for example https://contoso.crm.dynamics.com.

After consent, you return to the page you started from with a toast: "HubSpot connected" or "Couldn't connect HubSpot" (named after the provider), with the vendor's error.

Connect with the API#

POST /oauth/start returns the URL to send the user's browser to. Admin or developer role.

Field Type Required Description
target string Yes crm, app or kb_sync
provider string Yes One of the providers above. Must be valid for the target
app_id string No app only: reconnect this existing app. Without it a new app is created
name string No app only: name for the new app
knowledge_base_id string kb_sync The knowledge base to sync into
sync_config object kb_sync {"folder_id"} for Google Drive (required), {"drive_id", "folder_id"} for OneDrive (optional), {"page_id"} for Notion (required)
sync_id string No kb_sync only: reconnect an existing sync instead of creating one
options.instance_url string Dynamics 365 Organisation URL
options.tenant string No Microsoft tenant id or domain for Dynamics 365 and OneDrive
options.login_url string No Salesforce login host, for example https://test.salesforce.com for sandboxes
options.accounts_url string No Zoho accounts host for your data centre, for example https://accounts.zoho.com.au
return_to string No Dashboard path to return to. Default /settings/integrations (or /knowledge-base for kb_sync)
curl -X POST https://api.tried.com.au/oauth/start \
  -H "Authorization: Bearer $TRIED_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"target": "crm", "provider": "salesforce", "options": {"login_url": "https://test.salesforce.com"}}'
{
  "authorize_url": "https://test.salesforce.com/services/oauth2/authorize?response_type=code&client_id=3MVG9...&redirect_uri=https%3A%2F%2Fapi.tried.com.au%2Foauth%2Fcallback&state=...&scope=api+refresh_token&code_challenge=...&code_challenge_method=S256",
  "mock": false,
  "provider": "salesforce",
  "pkce": true
}

After consent the vendor redirects to /oauth/callback, which stores the tokens and redirects the browser to the dashboard with query parameters:

Parameter When
oauth=success or oauth=error Always
provider Always
message On error
app_id App connections
sync_id, knowledge_base_id Synced source connections

What a successful connection creates#

Target Result
crm The provider's CRM connection is created or updated, enabled, with sync_calls and sync_contacts on
app A new integration app (or the app_id you passed) with status connected
kb_sync A new synced source (or the sync_id you passed). The first sync starts right away

Values the vendor returns with the token are kept with it: Salesforce instance_url, Zoho api_domain, GoHighLevel location_id, Notion workspace id.

Security#

  • State: the state parameter is encrypted, expires after 10 minutes and can be used once.
  • PKCE: S256 for the providers marked above (and always for the mock provider).
  • Storage: tokens are encrypted inside the connection's credentials and never returned by the API.

Token refresh#

  • Before each use, a token with less than 5 minutes left is refreshed first. Only one refresh runs per connection at a time, across API instances.
  • Every minute, connections expiring within 10 minutes are refreshed in the background.
  • Notion tokens do not expire and have no refresh token.

Force a refresh with POST /oauth/refresh:

curl -X POST https://api.tried.com.au/oauth/refresh \
  -H "Authorization: Bearer $TRIED_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"target": "crm", "provider": "hubspot"}'
{ "refreshed": true, "expires_at": 1760690400000 }

Pass {"target": "app", "app_id": "app_..."} for an app. A connection that was set up with a pasted token returns 400 "This connection does not use OAuth".