Fix HubSpot optional scopes for workspace OAuth - #1898
Conversation
|
Final CI is green on Live ASI NZ verification also confirms the reason for the expanded patch: this workspace app classifies its contact, company, deal, and ticket permissions as optional. With |
|
Verdict: needs a decision from Rhys — the template-declared Ran on the branch (all green, tree clean, no bun.lock churn): Blocking issue —
Suggested fix, keeping the design: make the template authoritative and drop the provider default for workspace clients — const workspaceOptionalScopes = firstPartyFlow
? []
: dedupeScopes(scopePolicy.kind === "scopes" ? (scopePolicy.optionalScopes ?? []) : []);and revert the Non-blocking: Nothing pushed. |
Summary
optional_scopeparameter for workspace-owned OAuth clientsoptional_scopevalues embedded in an OAuth auth template, remove those values from the RFCscopeparameter, and record the complete requested set for callback fallbackWhy
HubSpot decides whether each app permission is required or optional in the app registration. Optional permissions are ignored when sent only in the RFC
scopeparameter; they must be sent through HubSpot's non-standardoptional_scopeparameter.The ASI NZ workspace app demonstrates why this classification must be integration-specific: its contacts, companies, deals, and tickets permissions are configured as optional, while Executor's shared first-party app has a different required/optional split. Hard-coding one larger global optional set would break apps with another registration contract.
An OpenAPI OAuth auth template can already carry provider query parameters on its authorization URL. This change makes the selected template authoritative for
optional_scope: any matching declared scopes are moved out ofscope, provider defaults are merged, and first-party configuration still overrides the workspace path.Live verification against the ASI NZ workspace confirmed that
scope=oauthplus the app's optional CRM scopes completed consent and produced HTTP 200 account-info, company, contact, and deal reads on the intended production portal. The previous generated request left those CRM permissions inscopeand returned HubSpotMISSING_SCOPES.Test plan
bun run --cwd packages/core/sdk test -- src/oauth-helpers.test.ts src/oauth-scope-union.test.ts(95 passed)bun run --cwd apps/cloud test -- src/engine/first-party-oauth-clients.test.ts(6 passed)bun run formatbun run lintbun run typecheck(45 packages)