OAuth2

Here are all details about configuring Connectors to authenticate with OAuth2

Introduction

Before diving into configuration details, it is useful to first understand at a high level how OAuth2 works. This helps with troubleshooting and understanding the process flow.

Redirect URI

The redirect URI is always https://api.locoia.com/v1/oauth2/callback/connectorname

  • For one-word Connectors, use the lowercase connector name

  • For multi-word Connectors, replace spaces with %20

Examples:

  • HubSpot:

    https://api.locoia.com/v1/oauth2/callback/hubspot

  • Teamwork CRM:

    https://api.locoia.com/v1/oauth2/callback/teamwork%20crm

The OAuth2 access token is typically sent in the header using this format:

{
  "encode": false,
  "token_in_header": true,
  "content_type": "application/json",
  "header_key": "Authorization",
  "token_format": "{{token}}",
  "token_prefix": "Bearer {{token_format}}"
}

Authentication Configuration (Standard)

For APIs following the standard OAuth2 flow, the configuration looks like:

{
  "oauth2": {
    "auth_form": [],
    "config": {
      "client_id": "CLIENT_ID for OAuth2 app",
      "client_secret": "CLIENT_SECRET for OAuth2 app",
      "extra_authorization_url": {
        "response_type": "code"
      },
      "extra_access_url": {
        "grant_type": "authorization_code"
      },
      "step1_authorize_url": "https://.../authorize",
      "step3_access_url": "https://.../token",
      "token_refresh_url": "https://.../token"
    }
  }
}

OAuth2 URLs Explained

  • step1_authorize_url URL for user authorization page (GET request)

  • step3_access_url URL for exchanging the code for an access token (POST by default with content-type application/x-www-form-urlencoded)

  • token_refresh_url Used for token refresh if different from the regular step3_access_url (Deprecated for standard flows)

Additional Query/Body Parameters

  • extra_authorization_url: Add query parameters to the authorization request.

  • extra_access_url: Add body parameters to the token exchange request.

"scope": "scope1 scope2"

If scopes are required, add them in the extra_authorization_url:

Dynamic base domains

To handle dynamic subdomains or environments (like production/sandbox), use Jinja rendering inside URLs as needed.

Example
https://{{ environment }}.example.com/oauth/token

Handling OAuth2 deviations

For APIs that deviate from the standard OAuth2 flow, additional config options are available:

client_id_and_secret_in_headers

Send client credentials as Basic Auth instead of body.

alternative_code_key

Rename the key for the authorization code.

alternative_client_id_key

Rename the key for client ID.

alternative_client_secret_key

Rename the key for client secret.

grant_type

Add custom grant_type (Deprecated).

accept_header

Set a custom Accept header.

content_type

Change Content-Type (e.g., to application/json).

request_method

Force GET instead of POST for token request.

access_token_path

Define a custom JSON path to find the access token in the response.

Deprecated auth_form Fields

Additional fields that can be exposed to users:

alternative_scope

User-defined scope input (overwrites default scopes).

client_id

Allows user to provide their own Client ID, overriding config.

client_secret

Allows user to provide their own Client Secret, overriding config.

Other custom fields can also be added manually if required.


Examples

HubSpot - Standard with Scopes

The Authentication Configuration is the standard one, with specific scopes:

{
  "oauth2": {
    "auth_form": [
      {
        "name": "scope",
        "title": "Additional scopes",
        "type": "text",
        "required": false,
        "hideInEmbed": true,
        "placeholder": "crm.schemas.companies.write crm.schemas.contacts.write",
        "info": "Adds scopes to the default: crm.schemas.companies.write crm.schemas.contacts.write crm.schemas.deals.read crm.schemas.deals.write files crm.objects.contacts.write e-commerce crm.objects.companies.write crm.objects.companies.read crm.objects.deals.read crm.schemas.contacts.read crm.objects.deals.write crm.objects.contacts.read crm.schemas.companies.read communication_preferences.read_write crm.objects.owners.read crm.lists.write crm.lists.read"
      }
    ],
    "config": {
      "client_id": "CLIENT_ID for OAuth2 app",
      "client_secret": "CLIENT_SECRET for OAuth2 app",
      "exchange_request_body_type": "json",
      "extra_access_url": {
        "grant_type": "authorization_code"
      },
      "extra_authorization_url": {
        "response_type": "code",
        "scope": "communication_preferences.read_write crm.lists.read crm.lists.write crm.objects.companies.read crm.objects.companies.write crm.objects.contacts.read crm.objects.contacts.write crm.objects.deals.read crm.objects.deals.write crm.objects.owners.read crm.schemas.companies.read crm.schemas.companies.write crm.schemas.contacts.read crm.schemas.contacts.write crm.schemas.deals.read crm.schemas.deals.write e-commerce files settings.users.read tickets{% if scope is defined %} {{ scope }}{% endif %}"
      },
      "or_exchange_request_body_type": "data",
      "step1_authorize_url": "https://app.hubspot.com/oauth/authorize",
      "step3_access_url": "https://api.hubapi.com/oauth/v1/token",
      "token_refresh_url": "https://api.hubapi.com/oauth/v1/token"
    }
  }
}

The header is the standard header.

TikTok - Alternative client keys and access token path

TikTok has a few deviations from the OAuth2 standard:

  • The client id key is app_id instead of client_id, thus alternative_client_id_key needs to be set accordingly

  • The client id key is secret instead of client_secret, thus alternative_client_secret_key needs to be set accordingly

  • The access token is returned inside a dictionary called data, instead of in the 'root' dictionary, thus access_token_path needs to be set accordingly

  • The base domain for the access url, is always https://business-api.tiktok.com/, even though the base domain for the endpoints itself is based on the environment: https://{% if environment is defined and environment == 'Sandbox' %}sandbox{% else %}business{% endif %}-api.tiktok.com/open_api/v1.2/

The Authentication Configuration thus needs to be setup like this:

{
  "oauth2": {
    "auth_form": [
      {
        "name": "environment",
        "title": "Environment",
        "type": "select",
        "required": false,
        "default": "Production",
        "enum": [
          "Production",
          "Sandbox"
        ]
      }
    ],
    "config": {
      "access_token_path": "data.access_token",
      "alternative_client_id_key": "app_id",
      "alternative_client_secret_key": "secret",
      "alternative_code_key": "auth_code",
      "client_id": "CLIENT_ID for OAuth2 app",
      "client_secret": "CLIENT_SECRET for OAuth2 app",
      "exchange_request_body_type": "json",
      "extra_access_url": {
        "grant_type": "authorization_code"
      },
      "extra_authorization_url": {
        "response_type": "code"
      },
      "or_exchange_request_body_type": "data",
      "step1_authorize_url": "https://ads.tiktok.com/marketing_api/auth",
      "step3_access_url": "https://business-api.tiktok.com/open_api/v1.2/oauth2/access_token/",
      "token_refresh_url": "https://business-api.tiktok.com/open_api/v1.2/oauth2/access_token/"
    }
  }
}

Last updated

Was this helpful?