Best Practices

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 .env and .whatalo/ to .gitignore automatically
  • Run whatalo validate regularly — 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.storeId for 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: 200 for success, 4xx for client errors, 500 for 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.uninstalled webhook and delete all merchant data when a plugin is removed

On this page