client_id and client_secret from appearing in server logs or other persistent logging.
Review the sections below on how to use these endpoints to initiate OAuth access, manage access tokens, and retrieve token metadata.
Token types
The OAuth authorization flow involves three distinct token types:- Authorization code: a temporary, single-use code that’s provided in the redirect URL as a query parameter when the user approves the installation of your app. Your app then has a short window to exchange it for an access token and a refresh token, after which the authorization code cannot be reused.
- Access token: your app’s authentication credential used for every API request made on behalf of the user and the account where they installed your app. This token is provided as a Bearer token in the request, and expires after 30 minutes.
- Refresh token: your app’s long-term authentication credential that you can use to generate a new access token after the previous one expires.
If you’re using the webhooks journal API, you can also generate access tokens using the
client_credentials grant type, which has a different authorization flow. Tokens with this grant type authenticate as your app rather than on behalf of a specific user, and can be used for managing webhook journal subscription configuration or process journal data.Initiate OAuth access
After you create your app, a user can install it into their HubSpot account using the install URL located in your app’s settings, which will include theclient_id, redirect_uri, and scopes as query parameters. You may also include optional_scopes and state, if needed.
For example, the Node.js code block below demonstrates how to construct this authorization URL:
code query parameter, which you can use to generate an access token and a refresh token. The access token will be used to authenticate requests that your app makes, while the refresh token will be used to get a new access token when the current one expires.
Generate initial access and refresh tokens
After a user authorizes your app, the response will include acode value as a query parameter. Using this code, you’ll generate the initial access token and refresh token. Access tokens are short-lived (30 minutes), and you can check the expires_in parameter when generating an access token to determine its lifetime (in seconds).
To get OAuth access and refresh tokens, make a URL-form encoded POST request to /oauth/2026-03/token. In the request body, you’ll specify various auth parameters, such as client_id and client_secret, along with the code passed back through the redirect URL.
For example, your request may look similar to the following:
| Parameter | Type | Description |
|---|---|---|
grant_type | String | Must be authorization_code for the request to generate initial access and refresh tokens. |
code | String | The code returned in the redirect URL after the user installs the app. |
redirect_uri | String | The app’s set redirect URL. |
client_id | String | The app’s client ID. |
client_secret | String | The app’s client secret. |
expires_in field specifies how long the access token will last (in seconds).
Refresh an access token
Using a refresh token, you can generate a new access token by making a URL-form encodedPOST request to /oauth/2026-03/token. In the request body, you’ll specify the grant_type, client_id, client_secret, and refresh_token.
| Parameter | Type | Description |
|---|---|---|
grant_type | String | Must be refresh_token for the request to generate new access tokens from the refresh token. |
refresh_token | String | The refresh token value. |
client_id | String | The app’s client ID. |
client_secret | String | The app’s client secret. |
Generate a client credentials access token
Theclient_credentials grant type authenticates as your app rather than on behalf of a specific user. Unlike the authorization_code flow, client credentials tokens are app-level tokens used for the webhooks journal API.
To generate a client credentials access token, make a URL-form encoded POST request to /oauth/2026-03/token with grant_type=client_credentials.
| Parameter | Type | Description |
|---|---|---|
grant_type | String | Must be client_credentials. |
client_id | String | The app’s client ID. |
client_secret | String | The app’s client secret. |
scope | String | A space-separated list of scopes to request for the token. Must include at least one valid scope (e.g., developer.webhooks_journal.read). |
client_credentials grant type doesn’t require one for generating the access token.
Retrieve access token metadata
To get information about an OAuth access token, including the user that the token was created for and their corresponding Hub ID, make aPOST request to /oauth/2026-03/token/introspect, providing the following form URL-encoded properties in the request body:
| Property | Type | Description |
|---|---|---|
client_id | String | The app’s client ID. |
client_secret | String | The app’s client secret. |
token_type_hint | String | The type of token you’re querying, which can be either access_token or refresh_token. |
refresh_token | String | If you specified refresh_token as the token_type_hint, then provide the refresh_token as an additional property in your request. |
token | String | The access_token or refresh_token value, based on the token type you specified in the token_type_hint property above. |
refresh_token of na1-aaaa-bbbb-cccc-dddd-eeeeeeeeeeee, your form URL-encoded request body would include:
access_token and refresh_token grant types.
- Access token metadata
- Refresh token metadata
Error handling
When querying for access or refresh tokens, if an OAuth error occurs, the response will resemble the following:status and message fields that were included in previous versions of the OAuth token API endpoints are still available for backwards compatibility.