Migrating from OAuth1 to OAuth 2.0

These are the key points to keep in mind when updating your existing app to work with the new OAuth 2.0 system.

You can use your existing HubSpot apps

Any apps that you've already created in HubSpot will work for OAuth 2.0, and the client IDs and client secrets for those apps are forward compatible with OAuth 2.0.

Access tokens are passed in an Authorization header, and not in the access_token= query parameter

When making an API request using an OAuth 2.0 access token, the token must be included in the Authorization HTTP header in the request.  The access_token= query parameter must not be included.

The format of the header is:
Authorization: Bearer {token}

See this page for more details on making requests using OAuth 2.0 access tokens.

Note: The Authorization header will also support OAuth 1 tokens, so you can use this single method to authenticate requests.

Refreshing an access token takes additional fields

Refreshing an access token still requires the grant_type, client_id, and refresh_token, but also additionally requires the client_secret from your app, as well as the redirect_uri that was originally used when first authorizing the connection.

Full details for using the refresh token to generate a new access token can be found here.

Note: You may use your existing OAuth 1 refresh tokens with the OAuth 2.0 refresh endpoint, which will allow you to have a single process for refreshing your access tokens. Using an OAuth 1 refresh token to generate a new access token will generate an OAuth 1 access token, regardless of the method used to refresh the token.

Users will need to re-authenticate your app

While existing OAuth 1 refresh tokens and access tokens can be used with the new OAuth 2 refresh and authentication methods, the OAuth 1 system will eventually be shut down, and those existing OAuth 1 tokens will stop working.

  • You will be able to update your app to work with OAuth 2.0 tokens without disrupting existing users.
    • Any existing OAuth 1 refresh tokens you currently have will be able to generate OAuth 1 access tokens using the new OAuth 2.0 refresh method
    • Both OAuth 1 and OAuth 2.0 access tokens can be used in the Authorization header.
  • Once you have updated your app to work with OAuth 2.0, any new users should be directed to authorize your app using the OAuth 2.0 authorization process. Continue reading for details about the differences between the old authentication process and the new process for OAuth 2.0.
  • Existing users should be directed to re-authorize your app using OAuth 2.0 to prevent any disruption when the OAuth 1 system is shut down, as any OAuth 1 refresh tokens you have will no longer be able to generate access tokens once the system is shut down.

You'll need to update the URL used to initiate the OAuth connection

OAuth 2.0 uses a different URL to authenticate: https://app.hubspot.com/oauth/authorize

Full details for how the new authorization URL works can be found here: http://developers.hubspot.com/docs/methods/OAuth2/initiate-OAuth-integration

The client_id and redirect_uri parameters you're already using work the same way that they did for the old OAuth system.  The portalId parameter is no longer required, as user will be able to select the portal they want to integrate with after you direct them to the authorize URL.

You'll need to update the scopes you're using

The scopes supported by OAuth2 are different than the scopes supported by the old system.  See the full listing of scopes for more details on the specific scopes available for OAuth 2.0.

In addition to the different scopes, OAuth 2.0 also has two types of scopes: required scopes and optional scopes.

Required scopes are similar to the scopes used with the previous OAuth system, and are used with the &scope= parameter when authorizing your app. When you're viewing the settings for your app, any scopes you have checked in those settings will be treated as required scopes, and you'll need to include those scopes in the authorization URL or the user will get an error message indicating that the scopes are not configured correctly.

As an example, if your app has the "Read from and write to my Contacts" scope and the "Read from and write to my Forms" scope checked, you would need to include both the contacts and forms scopes in your authorization URL: &scope=contacts%20forms

Optional scopes allow you to specify scopes that your app can optionally use, but that aren't required for your app's core functionality. This would allow your app to be authorized with the various types of HubSpot accounts that may not have access to all tools or scopes. Optional scopes are specified in the &optional_scope= parameter of your authorization URL.

As an example, say your app works with contacts and forms, but your app can work without forms as well.  You would set the contacts scope as required, and the forms scope as optional: &scope=contacts&optional_scope=forms

Setting the forms scope as an optional scope would allow your app to work with Marketing accounts, which would include both the contacts and forms tools, as well as working with CRM accounts, which would have only contacts. Since CRM accounts don't support forms, the optional forms scope would be dropped during the authorization so the user would only authorize the contacts scope. If you include both the contacts and forms scopes as required scopes, CRM accounts would not be able to authorize your app, and the user would see an error.

If you're using optional scopes, you'll need to check the details for the access token you get to see which scopes were actually authorized for your app.

More details for scopes and optional scopes can be found in the full listing of scopes.

After the authorization and redirect back to your app, you'll need to generate the initial access token

Instead of including the access_token as a query parameter when being redirected to the redirect_uri, you'll now get a code= parameter.  You'll use that code, along with your client ID and client secret, to generate the access token using a separate (server-side) request.  This extra step adds another layer of security, ensuring that your app's client secret is required to generate the access token.  As was mentioned above, you'll automatically get both an access_token and a refresh_token token when generating the initial access token.

Full details for generating the initial access and refresh tokens can be found here.

Access tokens have a shorter lifetime

OAuth 2.0 access tokens have a lifetime of 6 hours, indicated by the expires_in field returned when generating or refreshing an access token.