Skip to content

Authentication Security

Proper authentication is critical for securing your BITXpay integration. This guide covers how to securely manage your API credentials.

API Key Management

Storing Credentials

Never hardcode credentials

Never store API keys directly in your source code.

Recommended approaches:

  1. Environment Variables
bash
# .env (never commit this file)
BITXPAY_API_KEY=your_api_key
BITXPAY_SECRET_KEY=your_secret_key
  1. Secrets Manager
javascript
// AWS Secrets Manager example
import { SecretsManager } from '@aws-sdk/client-secrets-manager';

const client = new SecretsManager({ region: 'us-east-1' });
const secret = await client.getSecretValue({ SecretId: 'bitxpay-credentials' });
const credentials = JSON.parse(secret.SecretString);
  1. Vault
javascript
// HashiCorp Vault example
const vault = require('node-vault')();
const { data } = await vault.read('secret/data/bitxpay');

Key Rotation

Rotate your API keys regularly:

  1. Generate a new API key in the dashboard
  2. Update your application with the new key
  3. Verify the new key works correctly
  4. Revoke the old key
javascript
// Support multiple keys during rotation
const apiKeys = [
  process.env.BITXPAY_API_KEY_NEW,
  process.env.BITXPAY_API_KEY_OLD
];

Request Signing

Signature Generation

Merchant API requests are signed with your Ed25519 (EdDSA) private key — not HMAC. Always generate signatures server-side. Note the canonical message order is METHOD + PATH + TIMESTAMP + BODY:

javascript
import crypto from 'crypto';

function signRequest(privateKeyPEM, method, path, timestamp, body = '') {
  const message = `${method}${path}${timestamp}${body}`;

  // Ed25519 (EdDSA): pass `null` — Ed25519 hashes the message internally.
  const signature = crypto.sign(null, Buffer.from(message, 'utf8'), privateKeyPEM);

  return signature.toString('base64');
}

HMAC is for webhooks only

HMAC-SHA256 is used to verify inbound webhooks (see below), not to sign your outbound API requests. Don't confuse the two: outbound requests use the Ed25519 signature above. For the full signing guide, see Authentication.

Timestamp Validation

Include a current timestamp and handle clock skew:

javascript
const timestamp = Math.floor(Date.now() / 1000);

// Requests older than 5 minutes are rejected
// Ensure your server's clock is synchronized (use NTP)

Webhook Verification

Always verify webhook signatures using the raw request body (before JSON parsing):

javascript
// IMPORTANT: Use express.raw() so req.body is the raw Buffer
app.post('/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-bitxpay-signature'];
  const rawPayload = req.body; // Raw Buffer — do NOT parse before verifying

  const expectedSignature = crypto
    .createHmac('sha256', secretKey)
    .update(rawPayload)
    .digest('hex');

  // Use timing-safe comparison to prevent timing attacks
  if (!crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  )) {
    return res.status(401).send('Invalid signature');
  }

  const event = JSON.parse(rawPayload);
  // Process webhook...
});

IP Whitelisting

Coming Soon

IP whitelisting is not yet available. This section describes planned functionality and will be updated once the feature ships.

For additional security, you will be able to whitelist your server IPs from the DashboardSettingsSecurity page, restricting API access to a set of known server IP addresses.

Common Vulnerabilities

Prevent Key Exposure

RiskMitigation
Keys in source codeUse environment variables
Keys in logsRedact sensitive data
Keys in URLsUse headers instead
Keys in browserKeep keys server-side only

Secure Transmission

  • Always use HTTPS
  • Verify SSL certificates
  • Use TLS 1.2 or higher
javascript
// Ensure SSL verification is enabled
const https = require('https');

https.request({
  hostname: 'api.bitxpay.com',
  rejectUnauthorized: true // Default, but be explicit
});