Security Best Practices
Essential security guidelines for plugin developers — webhook verification, secret management, scope minimization, input validation, and token handling.
Security mistakes in plugins affect real merchants and their customers. Follow these practices before submitting your plugin for review.
1. Always verify webhook signatures
Never process an incoming webhook without first verifying its HMAC signature. An unverified webhook can be replayed or forged.
import { verifyWebhook } from "@whatalo/plugin-sdk/webhooks";
export async function POST(request: Request) {
const payload = await request.text();
const signature = request.headers.get("x-whatalo-hmac-sha256") ?? "";
const isValid = verifyWebhook({ payload, signature, secret: process.env.WHATALO_CLIENT_SECRET! });
if (!isValid) {
return new Response("Invalid signature", { status: 401 });
}
// Safe to process payload here
}Use the enhanced template verifier for replay protection — it rejects requests with a timestamp outside a 300-second window.
2. Protect your client secret
Your client secret authenticates your plugin to the platform. Exposing it is equivalent to handing over your plugin's identity.
- Never commit secrets to version control
- Always use environment variables:
process.env.WHATALO_CLIENT_SECRET - The scaffolded template adds
.envand.whatalo/to.gitignoreautomatically - Run
whatalo validateregularly — it scans your project for hardcoded secrets
3. Request minimum scopes
Only declare the permission scopes your plugin genuinely needs in whatalo.app.ts. Requesting broad permissions when only narrow access is needed:
- Increases the risk surface if your plugin is ever compromised
- Is flagged during the review process
4. Validate all input
- Validate the structure of webhook payloads before processing them
- Sanitize any external data before rendering it in your UI
- Do not trust
context.storeIdfor server-side authorization — always verify access via the API
5. Secure your webhook endpoint
- Use HTTPS in production — never HTTP
- Implement replay protection (verify request timestamps)
- Return appropriate HTTP status codes:
200for success,4xxfor client errors,500for unexpected failures
6. Handle token expiration
The CLI handles token refresh automatically during development. For server-side API calls in production:
- Handle
AuthenticationError(HTTP 401) gracefully - Implement retry logic for transient failures before surfacing an error to the merchant
7. Do not store unnecessary merchant data
- Fetch merchant data from the API when needed rather than caching it long-term
- If you must persist data, encrypt it at rest
- Listen for the
app.uninstalledwebhook and delete all merchant data when a plugin is removed
Distribution
Choose between private and public distribution modes. Private plugins are auto-approved. Public plugins require review and appear in the marketplace.
Performance Best Practices
Guidelines for keeping your plugin fast — bundle size, initial load time, API usage patterns, resize rate limits, and lazy loading.