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:
- Environment Variables
# .env (never commit this file)
BITXPAY_API_KEY=your_api_key
BITXPAY_SECRET_KEY=your_secret_key- Secrets Manager
// 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);- Vault
// HashiCorp Vault example
const vault = require('node-vault')();
const { data } = await vault.read('secret/data/bitxpay');Key Rotation
Rotate your API keys regularly:
- Generate a new API key in the dashboard
- Update your application with the new key
- Verify the new key works correctly
- Revoke the old key
// 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:
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:
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):
// 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 Dashboard → Settings → Security page, restricting API access to a set of known server IP addresses.
Common Vulnerabilities
Prevent Key Exposure
| Risk | Mitigation |
|---|---|
| Keys in source code | Use environment variables |
| Keys in logs | Redact sensitive data |
| Keys in URLs | Use headers instead |
| Keys in browser | Keep keys server-side only |
Secure Transmission
- Always use HTTPS
- Verify SSL certificates
- Use TLS 1.2 or higher
// Ensure SSL verification is enabled
const https = require('https');
https.request({
hostname: 'api.bitxpay.com',
rejectUnauthorized: true // Default, but be explicit
});