Get your own Node server
const crypto = require('crypto');

// Simulated API request
function createApiRequest(apiKey, secretKey, method, path, queryParams, body, timestamp) {
  // Create the string to sign
  const stringToSign = [
    method.toUpperCase(),
    path,
    new URLSearchParams(queryParams).toString(),
    typeof body === 'string' ? body : JSON.stringify(body || {}),
    timestamp
  ].join('\n');
  
  // Create HMAC signature
  const hmac = crypto.createHmac('sha256', secretKey);
  hmac.update(stringToSign);
  const signature = hmac.digest('hex');
  
  // Return the request with authentication headers
  return {
    url: `https://api.example.com${path}?${new URLSearchParams(queryParams)}`,
    method,
    headers: {
      'Content-Type': 'application/json',
      'X-Api-Key': apiKey,
      'X-Timestamp': timestamp,
      'X-Signature': signature
    },
    body: body || {},
    // For debugging/verification
    stringToSign
  };
}

// Simulate API server verification
function verifyApiRequest(apiKey, secretKey, method, path, queryParams, body, timestamp, signature) {
  // Recreate the string that was signed
  const stringToSign = [
    method.toUpperCase(),
    path,
    new URLSearchParams(queryParams).toString(),
    typeof body === 'string' ? body : JSON.stringify(body || {}),
    timestamp
  ].join('\n');
  
  // Verify HMAC signature
  const hmac = crypto.createHmac('sha256', secretKey);
  hmac.update(stringToSign);
  const expectedSignature = hmac.digest('hex');
  
  return {
    isValid: crypto.timingSafeEqual(
      Buffer.from(signature, 'hex'),
      Buffer.from(expectedSignature, 'hex')
    ),
    expectedSignature
  };
}

// API credentials
const apiKey = 'user123';
const secretKey = 'very-secret-api-key';

// Create a request
const timestamp = new Date().toISOString();
const request = createApiRequest(
  apiKey,
  secretKey,
  'POST',
  '/api/v1/users',
  { filter: 'active' },
  { name: 'John Doe', email: 'john@example.com' },
  timestamp
);

console.log('API Request:');
console.log(`URL: ${request.url}`);
console.log(`Method: ${request.method}`);
console.log('Headers:', request.headers);
console.log('Body:', request.body);
console.log('\nString that was signed:');
console.log(request.stringToSign);

// Server verifies the request
const verification = verifyApiRequest(
  apiKey,
  secretKey,
  'POST',
  '/api/v1/users',
  { filter: 'active' },
  { name: 'John Doe', email: 'john@example.com' },
  timestamp,
  request.headers['X-Signature']
);

console.log('\nVerification result:');
console.log(`Is signature valid? ${verification.isValid}`);

// Try with tampered data
const tamperedVerification = verifyApiRequest(
  apiKey,
  secretKey,
  'POST',
  '/api/v1/users',
  { filter: 'active' },
  { name: 'Jane Doe', email: 'jane@example.com' }, // Changed body
  timestamp,
  request.headers['X-Signature']
);

console.log('\nTampered verification result:');
console.log(`Is signature valid? ${tamperedVerification.isValid}`);

              
API Request:
URL: https://api.example.com/api/v1/users?filter=active
Method: POST
Headers: {
  'Content-Type': 'application/json',
  'X-Api-Key': 'user123',
  'X-Timestamp': '2023-01-01T12:00:00.000Z',
  'X-Signature': '1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3'
}
Body: { name: 'John Doe', email: 'john@example.com' }

String that was signed:
POST
/api/v1/users
filter=active
{"name":"John Doe","email":"john@example.com"}
2023-01-01T12:00:00.000Z

Verification result:
Is signature valid? true

Tampered verification result:
Is signature valid? false