From lucidchart-pack
Introduces security best practices for Lucidchart API integration: OAuth2 client credentials, webhook signature verification, input validation, and API version pinning.
How this skill is triggered — by the user, by Claude, or both
Slash command
/lucidchart-pack:lucidchart-security-basicsThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Lucidchart documents often contain sensitive business diagrams — org charts, network topologies, database schemas, and architecture plans that reveal internal infrastructure. The API uses OAuth2 client credentials, meaning a compromised client secret grants access to every document the integration can reach. Collaboration sharing with granular permission levels (view, edit, owner) must be enfor...
Lucidchart documents often contain sensitive business diagrams — org charts, network topologies, database schemas, and architecture plans that reveal internal infrastructure. The API uses OAuth2 client credentials, meaning a compromised client secret grants access to every document the integration can reach. Collaboration sharing with granular permission levels (view, edit, owner) must be enforced server-side. API versioning via the Lucid-Api-Version header requires pinning to avoid unexpected schema changes that break validation logic.
Lucid-Api-Version header pinned to a tested version in all requests.env files in .gitignore — never committed to version control// OAuth2 client credentials — load from secrets manager at startup
const LUCID_CLIENT_ID = process.env.LUCID_CLIENT_ID;
const LUCID_CLIENT_SECRET = process.env.LUCID_CLIENT_SECRET;
function validateLucidConfig(): void {
if (!LUCID_CLIENT_ID || !LUCID_CLIENT_SECRET) {
throw new Error('Missing LUCID_CLIENT_ID or LUCID_CLIENT_SECRET');
}
}
async function getLucidAccessToken(): Promise<string> {
const resp = await fetch('https://api.lucid.co/oauth2/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'client_credentials',
client_id: LUCID_CLIENT_ID!,
client_secret: LUCID_CLIENT_SECRET!,
}),
});
if (!resp.ok) throw new Error(`OAuth2 token request failed: ${resp.status}`);
const { access_token } = await resp.json();
return access_token;
// Cache token until expiry — never log it
}
import crypto from 'node:crypto';
const LUCID_WEBHOOK_SECRET = process.env.LUCID_WEBHOOK_SECRET!;
function verifyLucidWebhook(payload: string, signature: string): boolean {
const expected = crypto
.createHmac('sha256', LUCID_WEBHOOK_SECRET)
.update(payload, 'utf8')
.digest('hex');
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}
app.post('/webhooks/lucidchart', (req, res) => {
const sig = req.headers['x-lucid-signature'] as string;
if (!sig || !verifyLucidWebhook(JSON.stringify(req.body), sig)) {
return res.status(401).json({ error: 'Invalid webhook signature' });
}
// Process verified document change event
});
// Validate document IDs and enforce API version pinning
const LUCID_API_VERSION = '1';
function validateDocumentId(docId: string): boolean {
// Lucid document IDs are alphanumeric UUIDs
return /^[a-f0-9-]{36}$/.test(docId);
}
function lucidApiHeaders(token: string): Record<string, string> {
return {
Authorization: `Bearer ${token}`,
'Lucid-Api-Version': LUCID_API_VERSION,
'Content-Type': 'application/json',
};
}
function redactDiagramMetadata(doc: Record<string, unknown>): Record<string, unknown> {
const sensitive = ['creator_email', 'collaborator_emails', 'share_link', 'embed_url'];
const redacted = { ...doc };
for (const field of sensitive) {
if (redacted[field]) redacted[field] = '[REDACTED]';
}
return redacted;
}
// Always redact before logging — diagrams may contain org charts and network layouts
type LucidPermission = 'view' | 'edit' | 'owner';
function assertDocumentPermission(
userRole: LucidPermission,
requiredRole: LucidPermission
): void {
const hierarchy: LucidPermission[] = ['view', 'edit', 'owner'];
if (hierarchy.indexOf(userRole) < hierarchy.indexOf(requiredRole)) {
throw new Error(`Insufficient permission: need "${requiredRole}", have "${userRole}"`);
}
}
// Enforce server-side — never rely on Lucidchart UI permissions alone
Lucid-Api-Version header pinned to a tested version| Vulnerability | Risk | Mitigation |
|---|---|---|
| Client secret in logs | Full API access compromise | Never log OAuth2 credentials; redact in error handlers |
| Unverified webhooks | Spoofed document change events | Reject requests without valid x-lucid-signature |
| Unpinned API version | Breaking schema changes bypass validation | Always send Lucid-Api-Version header |
| Over-permissioned sharing | Unauthorized diagram access | Enforce view/edit/owner hierarchy server-side |
| Diagram data in logs | Leaked org charts and network topology | Redact creator, collaborator, and share URLs |
See lucidchart-prod-checklist.
6plugins reuse this skill
First indexed Jul 10, 2026
npx claudepluginhub jeremylongshore/claude-code-plugins-plus-skills --plugin lucidchart-packProvides a production deployment checklist for Lucidchart integrations covering OAuth2, API header pinning, rate limiting, and concurrent edit handling.
Guides completion of development work by verifying tests, detecting environment, and presenting structured options for merge, PR, or cleanup.
Guides creation and editing of skills using test-driven development with pressure scenarios and subagents to verify agent compliance.