Appnigma

HubSpot OAuth and Scopes: Complete Reference for App Builders (2026)

hubspot oauth

Jun 25, 2026

10 min read

HubSpot OAuth and Scopes: Complete Reference for App Builders (2026)

Updated June 18, 2026 by Sunny Chauhan.

Every HubSpot Marketplace app submission I've reviewed in 2026 has the same first failure mode: the app requests more scopes than it actually uses. The certification reviewer checks scope usage in the trailing 30 days, finds three or four scopes that no API call ever touched, and asks the team to either justify them or remove them. The principle of least privilege isn't a nice-to-have for HubSpot Marketplace apps; it's a certification line item. Here's the complete reference: every scope category, the install flow, the 30-day active-use rule, and how to design your scope list so it survives review the first time.

Pro Tip

TL;DR HubSpot OAuth scopes are permission strings your app requests when a customer installs it (e.g., crm.objects.contacts.read, automation, oauth). The customer sees them in the consent screen. HubSpot's May 2026 certification review checks that every scope your app requests has been actively used in API calls within the last 30 days. Unused scopes get flagged. Design your scope list as a minimum viable set, expand later only if a real feature needs it. The OAuth install flow: build the authorize URL, customer approves, your server exchanges the code for tokens, you store them encrypted.

Why scopes matter more in 2026 than they used to

Scopes have always been part of OAuth. What changed in 2026 is HubSpot's enforcement. Two things:

1/ The May 2026 certification questionnaire introduced explicit checks on active scope usage. Reviewers see which scopes your app declared and which were exercised by API calls in the last 30 days. If a scope was declared but never used, you have to justify it or drop it.

2/ Customers have become noticeably more careful about scope grants. A consent screen showing 12 scopes will see more drop-off than one showing 4. Founders I've talked to report measurable install-rate differences between minimal-scope and maximalist-scope apps.

The right pattern: start with the absolute minimum. Add scopes only when a new feature requires it. Never request scopes "in case we need them later."

How the OAuth install flow works

HubSpot's OAuth follows the standard Authorization Code grant. Five steps:

1/ Build the authorize URL. Construct a URL pointing to HubSpot's authorize endpoint with your client_id, the scopes you want, and your redirect_uri.

2/ Customer clicks install. They land on the consent screen showing the scopes you requested. They approve (or decline).

3/ HubSpot redirects with a code. On approval, HubSpot redirects to your redirect_uri with ?code=<authorization_code>&state=<your_state>.

4/ Your server exchanges the code for tokens. POST to HubSpot's token endpoint with the code, your client_id, and your client_secret. Response: access token, refresh token, expiration.

5/ Store and use. Store the tokens encrypted, indexed by portalId. Every subsequent API call carries the access token in the Authorization: Bearer <token> header.

The authorize URL pattern:

`` https://app.hubspot.com/oauth/authorize ?client_id=YOUR_CLIENT_ID &scope=crm.objects.contacts.read%20crm.objects.deals.read &redirect_uri=https://yourdomain.com/oauth/callback &state=RANDOM_STATE_STRING ``

The token exchange:

```javascript const response = await fetch('https://api.hubapi.com/oauth/v1/token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ grant_type: 'authorization_code', client_id: process.env.HUBSPOT_CLIENT_ID, client_secret: process.env.HUBSPOT_CLIENT_SECRET, redirect_uri: 'https://yourdomain.com/oauth/callback', code: receivedCode }) });

const { access_token, refresh_token, expires_in, portal_id } = await response.json(); ```

Worth flagging: the state parameter is your CSRF protection. Generate a random string, store it in the user's session before redirecting to HubSpot, verify it matches when HubSpot redirects back. Skipping this is a security audit failure.

The scope categories you actually need

HubSpot scopes are namespaced by category. Most apps need scopes from one or two of these:

CRM object scopes

Granular per-object read/write. These are the most common scopes:

crm.objects.contacts.read / crm.objects.contacts.writecrm.objects.companies.read / crm.objects.companies.writecrm.objects.deals.read / crm.objects.deals.writecrm.objects.line_items.read / crm.objects.line_items.writecrm.objects.quotes.read / crm.objects.quotes.writecrm.objects.custom.read / crm.objects.custom.write (for custom objects) → crm.objects.owners.read

Pattern: request reads first. If your app never writes, don't request writes. The consent screen shows write permissions as more sensitive and customers notice.

CRM schema scopes

For querying object definitions and properties:

crm.schemas.contacts.readcrm.schemas.companies.readcrm.schemas.deals.readcrm.schemas.custom.read

Needed if your app dynamically discovers custom properties or custom objects.

Conversations and tickets

ticketsconversations.readconversations.write

For service-desk integrations and helpdesk-adjacent products.

Marketing scopes

contentformsforms-uploaded-filesbusiness-intelligence

For marketing-tooling integrations.

Automation and timeline

automation (workflow triggers and actions) → timeline (event timeline writes)

Useful for products that want to write structured events onto contact / deal records.

App-level scopes

oauth (required for the OAuth flow itself)

This one is implicit but worth knowing.

The 30-day active-use rule, explained

HubSpot's certification reviewer pulls a usage report on your declared scopes. The rule: every scope you declare must have at least one API call exercising it in the last 30 days.

The implication: don't declare scopes for hypothetical future features. If your roadmap says "we'll add deal write support in Q3," don't request crm.objects.deals.write now. Request it when Q3 lands and the feature actually writes deals.

Two failure modes I've seen:

1/ The "we might need it" trap. Founder requests a wide scope set thinking it'll save a future re-approval cycle. The reviewer flags the unused scopes. Founder removes them and resubmits. Net effect: the resubmission delay was worse than the future addition would have been.

2/ The "we used to use it" trap. App removed a feature six months ago but still declares the scope. Reviewer flags the now-unused scope. Founder forgot it was there.

The fix is hygiene: every time your codebase removes a feature, audit whether any scope is now unused, and drop it from your app's declared list.

Designing a minimal scope list

A three-question filter for every scope you're considering:

1/ Does my app actually call an API that requires this scope today? 2/ If yes, does the feature that uses this scope ship in this submission? 3/ If yes, will it be exercised in production within 30 days?

If any answer is no, drop the scope. You can add it later. HubSpot supports scope addition through re-authorization without re-listing your app from scratch.

The pattern I'd recommend for a typical CRM integration:

  • oauth

  • crm.objects.contacts.read

  • crm.objects.deals.read

  • crm.schemas.contacts.read (only if you need to discover custom properties)

Add more as features demand. For most v1 Marketplace apps, three to five scopes is the right size.

How this maps to Salesforce-side experience

Salesforce ISVs are used to Permission Sets and Connected App OAuth scopes (api, refresh_token, openid, etc.). HubSpot's scope system is more granular per-object than Salesforce's, which has a smaller standard scope set but pushes object-level access into Profile / Permission Set Groups inside the customer's org.

The mental model that transfers: the principle of least privilege. Salesforce's Security Review checks for over-broad sharing and CRUD/FLS bypasses. HubSpot's certification checks for over-requested scopes. Different mechanisms, same underlying concern: don't ask for more access than you'll use.

At Appnigma we generate 2GP Managed Packages where every CRUD operation respects sharing rules and FLS by default. The HubSpot equivalent is requesting only the scopes your app's API calls actually need, and only writing to objects whose write scope you declared.

Pre-flight checklist before declaring your scope list

  • [ ] Listed every API call your app makes → Yes / No

  • [ ] Mapped each API call to the scope it requires → Yes / No

  • [ ] Dropped scopes that no current API call needs → Yes / No

  • [ ] Confirmed each declared scope will be exercised within 30 days → Yes / No

  • [ ] Audited for scopes left over from removed features → Yes / No

  • [ ] state parameter implemented for CSRF protection → Yes / No

  • [ ] redirect_uri matches what you registered in Developer Account → Yes / No

  • [ ] Token exchange uses client_secret from a secrets manager (not env file) → Yes / No

  • [ ] Documented why each scope is needed (for the cert questionnaire) → Yes / No

Real-world scenario: trimming a scope list from 11 to 4

A demand-gen ISV's first HubSpot Marketplace submission requested 11 scopes. The reviewer flagged 6 as never-used. The team rebuilt their requested scope list:

→ Original: 11 scopes including write permissions on contacts, companies, deals, tickets, and full schema reads on everything.

→ Trimmed: 4 scopes (oauth, crm.objects.contacts.read, crm.objects.companies.read, crm.objects.deals.read).

The features that needed write permissions had been deprioritized but the scopes were still declared. Trimming the list took 30 minutes. Resubmission passed. As a bonus, the install-screen consent text was less alarming and install rate ticked up.

Frequently Asked Questions

What is a HubSpot OAuth scope?

A HubSpot OAuth scope is a permission string your app requests during installation that defines what data and actions the app can access in the customer's portal. Examples: crm.objects.contacts.read, automation, tickets. The customer sees the requested scopes on the consent screen and approves or declines.

Why does HubSpot check scope usage in the last 30 days?

The May 2026 certification update introduced active scope-use enforcement. HubSpot's reviewer wants to confirm that every scope your app declared is actually needed, not requested speculatively. Unused scopes get flagged and you must justify or remove them (HubSpot Marketplace Certification Requirements).

What scopes does a typical HubSpot Marketplace app need?

For most CRM-integration apps: oauth, crm.objects.contacts.read, and one or two object scopes specific to what the app does (e.g., crm.objects.deals.read if it reads deal data). Add write scopes only when a real feature writes data. Three to five total is typical.

What is the HubSpot OAuth install flow?

Five steps: 1/ Construct the authorize URL with your client_id, scopes, redirect_uri. 2/ Customer approves on consent screen. 3/ HubSpot redirects to your redirect_uri with an authorization code. 4/ Your server exchanges the code for access and refresh tokens. 5/ Store tokens encrypted, use the access token in Authorization: Bearer <token> headers.

What is the state parameter in HubSpot OAuth?

A random string you generate before redirecting to HubSpot and verify on the redirect back. It's your CSRF protection. Without it, an attacker can trick a victim into authorizing an attacker's app installation. The state parameter should be unguessable and tied to the user's session.

How do I add a new scope to an existing HubSpot app?

Update the scope list in your app settings in the Developer Account. Customers who already installed your app will see a re-authorization prompt the next time they trigger an OAuth flow, showing the new scopes. They have to approve to upgrade their installation.

Does HubSpot require scopes to be requested at install time only?

Yes. HubSpot OAuth uses the Authorization Code grant, not the incremental authorization flow. You declare scopes upfront in the authorize URL; the customer approves the full set at once. There's no mid-session "request additional scope" prompt.

About the author

Sunny Chauhan is the founder and CEO of Appnigma AI, a no-code platform that generates Salesforce AppExchange-ready Managed Packages from natural-language prompts. He holds Salesforce certifications in Platform Developer II, Platform App Builder, Administrator, Data Cloud Consultant, and AI Associate. The principle of least privilege Appnigma enforces on Salesforce Connected Apps (minimal OAuth scopes, no over-broad object access) transfers directly to HubSpot scope design.

Originally published June 18, 2026. Last reviewed June 18, 2026. Scope definitions and OAuth flow verified against HubSpot's OAuth quickstart documentation and Marketplace certification requirements current as of the published date.

Sources

1/ HubSpot Developers, OAuth Quickstart Guide 2/ HubSpot Developers, Scopes Reference 3/ HubSpot Marketplace Certification Requirements 4/ HubSpot Developers, Introduction to Authentication

How many scopes does your app request today, and which ones could you actually drop without breaking a feature?

Ready to transform your Salesforce experience?

Start exploring the Salesforce Exchange today and discover apps that can take your CRM efficiency to the next level.

decorative section tag

Blog and News

Our Recent Updates