Shopify Security
Before writing code
Fetch live docs:
- Web-search
site:shopify.dev security best practicesfor security guidelines - Web-search
site:shopify.dev webhook verification hmacfor HMAC implementation - Web-search
site:shopify.dev session tokenfor session token verification
HMAC Webhook Verification
Every 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.
Session Token Verification
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 ID
OAuth Scope Management
Principle of Least Privilege
- Request only scopes your app needs
- Separate read and write scopes
- Review scopes when adding features
Scope Verification
Verify the access token has expected scopes:
- Store granted scopes during OAuth callback
- Check before making API calls that require specific permissions
Content Security Policy (CSP)
For embedded apps in Shopify admin:
- Shopify admin sets strict CSP headers
- Your app must comply: no inline scripts, no
eval(), no external fonts without proper headers - Use
frame-ancestorsheader for iframe embedding:Content-Security-Policy: frame-ancestors https://*.myshopify.com https://admin.shopify.com;
GDPR Mandatory Webhooks
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 uninstall
Failing to implement these results in app rejection.
Input Validation
API Data
- Validate and sanitize all input from Shopify webhooks
- Verify webhook topic matches expected schema
- Validate metafield values (may contain arbitrary JSON)
Theme/Liquid
- Apply
| escapefilter to user-generated content - Use
| jsonfilter for embedding data in JavaScript - Never output raw
customerdata without escaping
GraphQL
- Use parameterized queries (variables, not string interpolation)
- Validate and sanitize user input before passing as variables
- Handle
userErrorsin mutation responses
Secrets Management
- Never hardcode API keys, secrets, or tokens in source code
- Use environment variables or platform secret management
- Rotate access tokens periodically
- Store tokens encrypted at rest
- Use
.envfiles locally (excluded from version control)
Best Practices
- Verify HMAC on every webhook — never skip verification
- Use
timingSafeEqualfor all secret comparisons - Validate session tokens on every embedded app request
- Implement all GDPR mandatory webhooks before submitting for app review
- Apply CSP headers for embedded apps
- Escape all user input in Liquid templates
- Use parameterized GraphQL queries — never interpolate user input into queries
- Log security events but never log tokens or secrets
- Keep dependencies updated — run
npm auditregularly
Fetch the Shopify security documentation for exact HMAC implementation, session token structure, and CSP requirements before implementing.