Security
Request signing and verification for secure communication
All requests made from Phoenix to operator endpoints are signed using Phoenix's private RSA key. Operators must verify the signature using the public key provided during onboarding.
Request Signing Overview
Phoenix Games uses RSA-based digital signatures to ensure:
- Authenticity - Requests actually come from Phoenix Games
- Integrity - Request content hasn't been tampered with
- Non-repudiation - Requests can be traced back to Phoenix Games
Signature Header
Each request from Phoenix includes a signature header:
signature: BASE64_SIGNATURE
Signature Verification Process
To verify incoming requests from Phoenix:
Step 1: Extract Request Data
// Read the raw JSON body as a string
const rawBody = request.body; // Keep as string, don't parse to JSON yet
// Extract the signature header
const signature = request.headers['signature'];
Step 2: Prepare Verification
// You'll need Phoenix's public key (provided during onboarding)
const phoenixPublicKey = `-----BEGIN PUBLIC KEY-----
YOUR_PHOENIX_PUBLIC_KEY_HERE
-----END PUBLIC KEY-----`;
Step 3: Verify Signature
const crypto = require('crypto');
function verifySignature(rawBody, signature, publicKey) {
try {
const verifier = crypto.createVerify('RSA-SHA256');
verifier.update(rawBody, 'utf8');
const isValid = verifier.verify(publicKey, signature, 'base64');
return isValid;
} catch (error) {
console.error('Signature verification failed:', error);
return false;
}
}
// Usage
const isValidRequest = verifySignature(rawBody, signature, phoenixPublicKey);
Step 4: Handle Verification Result
if (!isValidRequest) {
// Reject the request
return response.status(401).json({ error: 'Invalid signature' });
}
// Safe to process the request
const requestData = JSON.parse(rawBody);
Complete Verification Example
function handlePhoenixWebhook(request, response) {
// Extract signature
const signature = request.headers['signature'];
if (!signature) {
return response.status(401).json({ error: 'Missing signature' });
}
// Get raw body
const rawBody = JSON.stringify(request.body);
// Verify signature
const isValid = verifySignature(rawBody, signature, PHOENIX_PUBLIC_KEY);
if (!isValid) {
return response.status(401).json({ error: 'Invalid signature' });
}
// Process the verified request
processWebhookRequest(request.body, response);
}
Security Best Practices
Key Management
- Store Phoenix's public key securely in environment variables or secure config
- Never expose private keys in client-side code or version control
- Rotate keys periodically and update Phoenix Games when you do
Request Handling
- Always verify signatures before processing any request
- Use constant-time comparison for signature verification when possible
- Log failed verification attempts for security monitoring
- Implement rate limiting on your webhook endpoints
Network Security
- Use HTTPS only for all webhook endpoints
- Validate request origins match Phoenix Games IP ranges
- Implement proper firewall rules for your webhook endpoints
- Monitor for suspicious patterns in incoming requests
Error Handling
- Don't expose internal errors in webhook responses
- Log security events for audit trails
- Implement proper timeout handling for cryptographic operations
- Have fallback procedures for key rotation scenarios
Troubleshooting
Common Issues
Signature Verification Fails
- Ensure you're using the correct Phoenix public key
- Verify you're reading the raw request body (not parsed JSON)
- Check that the signature header is being read correctly
- Confirm you're using RSA-SHA256 algorithm
Missing Signature Headers
- Verify your server is receiving all headers
- Check for proxy/load balancer header forwarding issues
- Ensure Phoenix Games has the correct webhook URL
Intermittent Failures
- Check for encoding issues with the request body
- Verify time synchronization between systems
- Monitor for network connectivity issues