Help us improve
Share bugs, ideas, or general feedback.
From shopify-commerce
Secures Shopify apps via HMAC webhook verification, session token validation, OAuth scope checks, CSP headers, GDPR webhooks, and input sanitization.
npx claudepluginhub orcaqubits/agentic-commerce-skills-plugins --plugin shopify-commerceHow this skill is triggered — by the user, by Claude, or both
Slash command
/shopify-commerce:shopify-securityThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
**Fetch live docs**:
Implements Shopify security best practices for API credential storage, webhook HMAC validation with TypeScript/Express, and access scopes.
Provides patterns for Shopify app development using Remix/React Router, embedded apps with App Bridge, webhooks, GraphQL Admin API, Polaris components, billing, and extensions.
Implements BigCommerce security: OAuth/JWT token management, API/webhook auth, CSP, input validation, PCI compliance. Use for hardening integrations or security reviews.
Share bugs, ideas, or general feedback.
Fetch live docs:
site:shopify.dev security best practices for security guidelinessite:shopify.dev webhook verification hmac for HMAC implementationsite:shopify.dev session token for session token verificationEvery webhook includes X-Shopify-Hmac-SHA256:
import crypto from 'crypto';
function verifyShopifyWebhook(
rawBody: Buffer,
hmacHeader: string,
secret: string,
): boolean {
const calculated = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('base64');
return crypto.timingSafeEqual(
Buffer.from(calculated),
Buffer.from(hmacHeader),
);
}
Critical: Use timingSafeEqual to prevent timing attacks. Use raw body buffer, not parsed JSON.
For embedded apps using App Bridge:
import jwt from 'jsonwebtoken';
function verifySessionToken(token: string, apiSecret: string) {
const decoded = jwt.verify(token, apiSecret, {
algorithms: ['HS256'],
});
// Verify issuer is a valid Shopify shop
const iss = decoded.iss as string;
if (!iss.match(/^https:\/\/[a-zA-Z0-9-]+\.myshopify\.com\/admin$/)) {
throw new Error('Invalid issuer');
}
return decoded;
}
Session token claims:
iss — shop admin URLdest — shop URLsub — user IDexp — expiration (1 minute)nbf — not beforeiat — issued atjti — unique token IDVerify the access token has expected scopes:
For embedded apps in Shopify admin:
eval(), no external fonts without proper headersframe-ancestors header for iframe embedding:
Content-Security-Policy: frame-ancestors https://*.myshopify.com https://admin.shopify.com;
Every app MUST implement:
customers/data_request — respond within 30 days with customer datacustomers/redact — delete customer data within 30 daysshop/redact — delete ALL store data within 48 hours of uninstallFailing to implement these results in app rejection.
| escape filter to user-generated content| json filter for embedding data in JavaScriptcustomer data without escapinguserErrors in mutation responses.env files locally (excluded from version control)timingSafeEqual for all secret comparisonsnpm audit regularlyFetch the Shopify security documentation for exact HMAC implementation, session token structure, and CSP requirements before implementing.