# OAuth2

### Introduction <a href="#introduction" id="introduction"></a>

Before diving into configuration details, it is useful to first understand at a [high level how OAuth2 works](https://youtu.be/CPbvxxslDTU).\
This helps with troubleshooting and understanding the process flow.

### Redirect URI <a href="#redirect-uri" id="redirect-uri"></a>

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`

### OAuth2 Header <a href="#header" id="header"></a>

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

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

### Authentication Configuration (Standard) <a href="#authentication-configuration" id="authentication-configuration"></a>

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

```json
{
  "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.

```json
"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.

{% code title="Example" %}

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

{% endcode %}

### Handling OAuth2 deviations <a href="#handling-oauth2-deviations" id="handling-oauth2-deviations"></a>

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 <a href="#examples-1" id="examples-1"></a>

#### HubSpot - Standard with Scopes <a href="#hubspot-standard-with-scopes" id="hubspot-standard-with-scopes"></a>

The Authentication Configuration is [the standard one](#authentication-configuration), with specific scopes:

```json
{
  "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](#header).

#### TikTok - Alternative client keys and access token path <a href="#tiktok-alternative-client-keys-and-access-token-path" id="tiktok-alternative-client-keys-and-access-token-path"></a>

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:

```json
{
  "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/"
    }
  }
}
```

[<br>](https://locoia.gitbook.io/connectors/authentication-types)
