agentsclimarketplace

Salesloft security basics

Skill jeremylongshore/claude-code-plugins-plus-skills/plugins/saas-packs/salesloft-pack/skills/salesloft-security-basics

425 plugins, 2,810 skills, 200 agents for Claude Code. Open-source marketplace at tonsofskills.com with the ccpi CLI package manager.

Install
npx -y skills add jeremylongshore/claude-code-plugins-plus-skills --skill salesloft-security-basics

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

What its author says it does

Copied from the file, not written here

'Secure SalesLoft OAuth tokens, API keys, and webhook signatures.

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

3.9 KB, as published. Nobody here has run it

SalesLoft Security Basics

Overview

Secure SalesLoft API integrations: OAuth token management, webhook signature verification, secret storage, and scope-based access control. SalesLoft uses OAuth 2.0 bearer tokens and HMAC-SHA256 webhook signatures.

Instructions

Step 1: Secret Storage

# .gitignore -- NEVER commit credentials
.env
.env.local
.env.*.local

# .env
SALESLOFT_CLIENT_ID=app-client-id
SALESLOFT_CLIENT_SECRET=app-secret
SALESLOFT_WEBHOOK_SECRET=webhook-signing-secret
// Validate secrets at startup
const required = ['SALESLOFT_CLIENT_ID', 'SALESLOFT_CLIENT_SECRET'];
for (const key of required) {
  if (!process.env[key]) throw new Error(`Missing required env: ${key}`);
}

Step 2: Token Lifecycle Management

// Store tokens securely with expiry tracking
interface TokenStore {
  accessToken: string;
  refreshToken: string;
  expiresAt: number; // Unix timestamp
}

async function getValidToken(store: TokenStore): Promise<string> {
  // Refresh 5 minutes before expiry
  if (Date.now() > (store.expiresAt - 300) * 1000) {
    const refreshed = await refreshAccessToken(store.refreshToken);
    store.accessToken = refreshed.access_token;
    store.refreshToken = refreshed.refresh_token;
    store.expiresAt = Math.floor(Date.now() / 1000) + refreshed.expires_in;
    await persistTokenStore(store); // Save to DB or secret manager
  }
  return store.accessToken;
}

Step 3: Webhook Signature Verification

import crypto from 'crypto';

function verifyWebhookSignature(
  rawBody: Buffer,
  signature: string,
  timestamp: string,
  secret: string,
): boolean {
  // Reject stale webhooks (replay attack prevention)
  const age = Math.abs(Date.now() / 1000 - parseInt(timestamp));
  if (age > 300) return false; // 5-minute window

  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${timestamp}.${rawBody.toString()}`)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature), Buffer.from(expected)
  );
}

Step 4: OAuth Scope Minimization

Use CaseRequired ScopesAvoid
Read-only dashboardpeople:read, cadences:read*:write
Cadence enrollmentpeople:read, cadence_memberships:createadmin
Full syncpeople:*, cadences:*, activities:readTeam admin scopes

Step 5: Security Checklist

  • OAuth tokens stored in secret manager (not env files in prod)
  • Refresh tokens encrypted at rest
  • Webhook endpoints verify signatures before processing
  • .env files in .gitignore
  • Different OAuth apps for dev/staging/prod
  • Token refresh runs before expiry (not after 401)
  • API logs monitored for unusual access patterns

Error Handling

IssueDetectionResponse
Token leaked in gitGitHub secret scanning alertsRevoke immediately, rotate
Webhook replay attackTimestamp > 5 min oldReject request
Brute force on webhookHigh 401 rateRate limit webhook endpoint

Resources

Next Steps

For production deployment, see salesloft-prod-checklist.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.