Configure HubSpot enterprise access control with OAuth scopes and team permissions. Use when implementing role-based access, configuring per-team HubSpot scopes, or setting up multi-user access patterns for HubSpot integrations. Trigger with phrases like "hubspot RBAC", "hubspot roles", "hubspot enterprise", "hubspot permissions", "hubspot team access", "hubspot OAuth scopes".
Scanned 9/12/2026
Install to Claude Code
npx -y skills add aibot88/sec_skill_store --skill hubspot-enterprise-rbac --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Hubspot Enterprise Rbac?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/aibot88-hubspot-enterprise-rbac)More formats (shields.io, HTML) on the badges page.
---
name: hubspot-enterprise-rbac
description: |
Configure HubSpot enterprise access control with OAuth scopes and team permissions.
Use when implementing role-based access, configuring per-team HubSpot scopes,
or setting up multi-user access patterns for HubSpot integrations.
Trigger with phrases like "hubspot RBAC", "hubspot roles",
"hubspot enterprise", "hubspot permissions", "hubspot team access", "hubspot OAuth scopes".
allowed-tools: Read, Write, Edit
version: 1.0.0
license: MIT
author: Jeremy Longshore <jeremy@intentsolutions.io>
tags: [saas, crm, marketing, hubspot]
compatible-with: claude-code
---
# HubSpot Enterprise RBAC
## Overview
Implement role-based access control for HubSpot integrations using OAuth scopes, multiple private apps with different permissions, and application-level authorization.
## Prerequisites
- HubSpot Enterprise subscription (for team-level permissions)
- Understanding of HubSpot OAuth scopes
- Multiple private apps or OAuth app configured
## Instructions
### Step 1: Scope-Based Access Model
HubSpot's permission model is scope-based. Create separate private apps for different access levels:
| Role | Private App | Scopes | Use Case |
|------|-----------|--------|----------|
| Reader | `hubspot-readonly` | `crm.objects.contacts.read`, `crm.objects.deals.read`, `crm.objects.companies.read` | Dashboards, reports |
| Writer | `hubspot-readwrite` | Above + `.write` variants | CRM operations |
| Admin | `hubspot-admin` | All CRM scopes + `crm.schemas.*.read` | Schema management |
| Sync | `hubspot-sync` | `crm.objects.contacts.read`, `crm.objects.contacts.write`, `crm.import` | Data sync jobs |
| Webhook | `hubspot-webhook` | `automation` | Event handling only |
### Step 2: Multi-Token Client Factory
```typescript
import * as hubspot from '@hubspot/api-client';
type AccessLevel = 'reader' | 'writer' | 'admin' | 'sync';
const TOKEN_MAP: Record<AccessLevel, string> = {
reader: process.env.HUBSPOT_READER_TOKEN!,
writer: process.env.HUBSPOT_WRITER_TOKEN!,
admin: process.env.HUBSPOT_ADMIN_TOKEN!,
sync: process.env.HUBSPOT_SYNC_TOKEN!,
};
const clientCache = new Map<AccessLevel, hubspot.Client>();
export function getClientForRole(role: AccessLevel): hubspot.Client {
if (!clientCache.has(role)) {
const token = TOKEN_MAP[role];
if (!token) {
throw new Error(`No token configured for role: ${role}`);
}
clientCache.set(role, new hubspot.Client({
accessToken: token,
numberOfApiCallRetries: 3,
}));
}
return clientCache.get(role)!;
}
// Usage
const readClient = getClientForRole('reader'); // can only read
const writeClient = getClientForRole('writer'); // can read and write
```
### Step 3: Application-Level Permission Middleware
```typescript
import { Request, Response, NextFunction } from 'express';
interface AppPermissions {
contacts: { read: boolean; write: boolean; delete: boolean };
deals: { read: boolean; write: boolean; delete: boolean };
companies: { read: boolean; write: boolean; delete: boolean };
}
const ROLE_PERMISSIONS: Record<string, AppPermissions> = {
sales_rep: {
contacts: { read: true, write: true, delete: false },
deals: { read: true, write: true, delete: false },
companies: { read: true, write: false, delete: false },
},
marketing: {
contacts: { read: true, write: true, delete: false },
deals: { read: true, write: false, delete: false },
companies: { read: true, write: false, delete: false },
},
admin: {
contacts: { read: true, write: true, delete: true },
deals: { read: true, write: true, delete: true },
companies: { read: true, write: true, delete: true },
},
readonly: {
contacts: { read: true, write: false, delete: false },
deals: { read: true, write: false, delete: false },
companies: { read: true, write: false, delete: false },
},
};
function requirePermission(
objectType: keyof AppPermissions,
action: 'read' | 'write' | 'delete'
) {
return (req: Request, res: Response, next: NextFunction) => {
const userRole = req.user?.role || 'readonly';
const permissions = ROLE_PERMISSIONS[userRole];
if (!permissions || !permissions[objectType]?.[action]) {
return res.status(403).json({
error: 'Forbidden',
message: `Role "${userRole}" lacks ${action} permission for ${objectType}`,
});
}
next();
};
}
// Usage
app.get('/api/contacts', requirePermission('contacts', 'read'), listContacts);
app.post('/api/contacts', requirePermission('contacts', 'write'), createContact);
app.delete('/api/contacts/:id', requirePermission('contacts', 'delete'), deleteContact);
```
### Step 4: OAuth 2.0 for Multi-Portal Access
```typescript
// For public apps accessing multiple HubSpot portals
interface PortalCredentials {
portalId: string;
accessToken: string;
refreshToken: string;
expiresAt: Date;
}
class MultiPortalManager {
private credentials = new Map<string, PortalCredentials>();
async getClient(portalId: string): Promise<hubspot.Client> {
let creds = this.credentials.get(portalId);
if (!creds) {
throw new Error(`No credentials for portal ${portalId}. User must authorize.`);
}
// Refresh token if expired
if (new Date() >= creds.expiresAt) {
creds = await this.refreshToken(creds);
this.credentials.set(portalId, creds);
}
return new hubspot.Client({ accessToken: creds.accessToken });
}
private async refreshToken(creds: PortalCredentials): Promise<PortalCredentials> {
const tempClient = new hubspot.Client();
const response = await tempClient.oauth.tokensApi.create(
'refresh_token',
undefined, undefined,
process.env.HUBSPOT_CLIENT_ID!,
process.env.HUBSPOT_CLIENT_SECRET!,
creds.refreshToken
);
return {
...creds,
accessToken: response.accessToken,
refreshToken: response.refreshToken,
expiresAt: new Date(Date.now() + response.expiresIn * 1000),
};
}
}
```
### Step 5: Audit Trail
```typescript
interface HubSpotAuditEntry {
timestamp: string;
userId: string;
role: string;
action: string;
objectType: string;
objectId: string;
success: boolean;
hubspotCorrelationId?: string;
}
async function auditHubSpotAction(
userId: string, role: string, action: string,
objectType: string, objectId: string, success: boolean,
correlationId?: string
): Promise<void> {
const entry: HubSpotAuditEntry = {
timestamp: new Date().toISOString(),
userId, role, action, objectType, objectId, success,
hubspotCorrelationId: correlationId,
};
// Store in your audit database
await db.auditLog.insert(entry);
// Alert on suspicious activity
if (!success && action === 'delete') {
console.warn('Failed delete attempt:', { userId, role, objectType, objectId });
}
}
```
## Output
- Scope-based access model with separate private apps per role
- Multi-token client factory for role-based HubSpot access
- Application-level permission middleware
- Multi-portal OAuth management for public apps
- Audit trail for all HubSpot operations
## Error Handling
| Issue | Cause | Solution |
|-------|-------|----------|
| `403 MISSING_SCOPES` | Token lacks required scope | Use the correct role's token |
| Permission denied in app | User role too restrictive | Check ROLE_PERMISSIONS mapping |
| Token refresh fails | Client secret changed | Update client secret in env |
| Audit gaps | Async logging failed | Add retry to audit log writes |
## Resources
- [HubSpot OAuth Scopes](https://developers.hubspot.com/docs/guides/apps/authentication/scopes)
- [Private Apps Guide](https://developers.hubspot.com/docs/guides/apps/private-apps/overview)
- [HubSpot Teams & Permissions](https://knowledge.hubspot.com/account/hubspot-user-permissions-guide)
## Next Steps
For major migrations, see `hubspot-migration-deep-dive`.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!