HubSpot connects through Pipes. Authdog runs the OAuth consent flow, stores that user's tokens encrypted, and refreshes them. Your backend asks for a fresh access token when it needs to write a contact or read CRM data. There is no separate "sync every sign-up" switch. Your app performs the HubSpot call with the token Authdog returns.

## Create the HubSpot app

1. In HubSpot, create a public app and note the client ID and client secret.
2. Set the redirect URL to the callback your backend owns, for example `https://app.example.com/pipes/callback`.
3. Request only the scopes you will use, such as `crm.objects.contacts.read`.

## Register the provider

In the [Authdog console](https://console.authdog.com), open **Pipes** for the environment and create a provider:

| Field | Value |
| --- | --- |
| **Provider slug** | `hubspot` |
| **Display name** | HubSpot |
| **Client ID** | From the HubSpot app |
| **Client secret** | From the HubSpot app. Leave blank on later edits to keep the stored secret |
| **Authorize URL** | `https://app.hubspot.com/oauth/authorize` |
| **Token URL** | `https://api.hubapi.com/oauth/v1/token` |
| **Scopes** | Space-separated, for example `crm.objects.contacts.read` |

Turn **Enabled** on and save. The client secret is encrypted at rest.

## Send a user through consent

Call the Pipes API from your backend with the environment API secret (`adenv_…`). Never put that secret in a browser.

```bash
curl -X POST https://api.authdog.com/pipes/v1/authorize \
  -H "Authorization: Bearer $AUTHDOG_ENV_API_SECRET" \
  -H "Content-Type: application/json" \
  -d '{ "provider": "hubspot", "userId": "user_123", "redirectUri": "https://app.example.com/pipes/callback" }'
```

Redirect the user to `authorizeUrl`. When HubSpot returns `code` and `state`, exchange them:

```bash
curl -X POST https://api.authdog.com/pipes/v1/exchange \
  -H "Authorization: Bearer $AUTHDOG_ENV_API_SECRET" \
  -H "Content-Type: application/json" \
  -d '{ "code": "…", "state": "…", "redirectUri": "https://app.example.com/pipes/callback" }'
```

Pass `state` back unchanged. Later, ask for a fresh token:

```bash
curl -X POST https://api.authdog.com/pipes/v1/token \
  -H "Authorization: Bearer $AUTHDOG_ENV_API_SECRET" \
  -H "Content-Type: application/json" \
  -d '{ "userId": "user_123", "provider": "hubspot" }'
```

The response is `{ accessToken, expiresAt }`. Authdog never returns the refresh token. Use the access token to create or update the HubSpot contact for that user.

## Test it

1. Connect a test HubSpot account from a development environment.
2. Confirm `GET /pipes/v1/connections?userId=…` lists the connection.
3. Call HubSpot with the access token and confirm the contact write.
4. Revoke with `POST /pipes/v1/revoke` and confirm the stored tokens are gone. Also revoke the app in HubSpot when a user disconnects.

## Related

| Read | To learn how to |
| --- | --- |
| [Pipes](/docs/pipes) | Authorize, exchange, token, and revoke |
| [Marketplace](/marketplace/hubspot) | The listing for this integration |
