Create webhook endpoint with signature verification
✓Works with OpenClaudeYou are a backend API developer. The user wants to create a secure webhook endpoint that verifies incoming webhook signatures to ensure authenticity.
What to check first
- Confirm your framework (Express, FastAPI, Django) and webhook provider (Stripe, GitHub, Twilio)
- Verify you have the webhook secret key from your provider's dashboard
- Check that your server is accessible at a public URL (localhost won't work for real webhooks)
Steps
- Install required cryptographic libraries:
npm install crypto(Node.js built-in) orpip install cryptography(Python) - Retrieve the webhook secret from your provider's settings and store it in environment variables as
WEBHOOK_SECRET - Create a dedicated route handler that accepts POST requests at a path like
/webhooks/events - Extract the signature from the webhook request headers (typically
X-Signature,X-Hub-Signature-256, orStripe-Signature) - Extract the raw request body as a string (before JSON parsing) — this is critical for signature verification
- Recreate the signature using HMAC-SHA256 with your secret key and the raw body
- Use constant-time comparison to verify the calculated signature matches the header signature
- Only parse and process the webhook payload if the signature matches; reject unsigned requests with 403 status
Code
const express = require('express');
const crypto = require('crypto');
const app = express();
// Store raw body as string for signature verification
app.use(express.raw({ type: 'application/json' }));
// Webhook signature verification middleware
function verifyWebhookSignature(req, res, next) {
const signature = req.headers['x-webhook-signature'];
const secret = process.env.WEBHOOK_SECRET;
if (!signature || !secret) {
return res.status(401).json({ error: 'Missing signature or secret' });
}
// Get raw body as string
const rawBody = req.body.toString('utf8');
// Calculate expected signature using HMAC-SHA256
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
// Use constant-time comparison to prevent timing attacks
const isValid = crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
if (!isValid) {
return res.status(403).json({ error: 'Invalid signature' });
}
// Attach parsed JSON to request object for next handler
req.webhook = JSON.parse(rawBody);
next();
}
// Webhook endpoint
app.post('/webhooks/events', verifyWebhookSignature, (req, res) => {
const event = req.webhook;
console.log(`Received webhook event: ${event.type}`);
// Handle different event types
switch (event.type)
Note: this example was truncated in the source. See the GitHub repo for the latest full version.
Common Pitfalls
- Not validating request bodies before processing — attackers will send malformed payloads to crash your service
- Returning detailed error messages in production — leaks internal architecture to attackers
- Forgetting CORS headers — frontend will silently fail with cryptic browser errors
- Hardcoding API keys in code — use environment variables and secret management
- No rate limiting — one client can DoS your entire API
When NOT to Use This Skill
- When a single shared library would suffice — APIs add network latency and failure modes
- For internal-only data flow within the same process — use direct function calls
- When you need transactional consistency across services — APIs can't guarantee this without distributed transactions
How to Verify It Worked
- Test all CRUD operations end-to-end including error cases (404, 401, 403, 500)
- Run an OWASP ZAP scan against your API — catches common security issues automatically
- Load test with k6 or Artillery — verify your API holds up under realistic traffic
- Verify rate limits actually trigger when exceeded — they often don't due to misconfiguration
Production Considerations
- Version your API from day one (
/v1/) — breaking changes are inevitable, give yourself a path - Set request size limits — prevents memory exhaustion attacks
- Add structured logging with request IDs — trace every request across your stack
- Document your API with OpenAPI — generates client SDKs and interactive docs for free
Related API Development Skills
Other Claude Code skills in the same category — free to download.
REST API Scaffold
Scaffold a complete REST API with CRUD operations
GraphQL Schema Generator
Generate GraphQL schema from existing data models
API Documentation
Generate OpenAPI/Swagger documentation from code
API Versioning
Implement API versioning strategy
Rate Limiter
Add rate limiting to API endpoints
API Error Handler
Create standardized API error handling
Request Validator
Add request validation middleware (Zod, Joi)
API Response Formatter
Standardize API response format
Want a API Development skill personalized to YOUR project?
This is a generic skill that works for everyone. Our AI can generate one tailored to your exact tech stack, naming conventions, folder structure, and coding patterns — with 3x more detail.