Security Best Practices
Follow these recommendations to keep your Ruby API integration secure.
Protect Your API Secret
Your team_api_secret is the private key used to generate request signatures. Anyone who holds it can make authenticated API calls on your behalf.
Never expose your team_api_secret in:
- Client-side JavaScript or mobile app bundles
- Public Git repositories or version control history
- Log files, error messages, or analytics events
- URLs or query parameters
All API calls must originate from your server-side backend, where the secret is not accessible to end users.
Store Secrets Securely
Store credentials outside your source code. Recommended approaches:
| Environment | Recommended Method |
|---|---|
| Development | .env file (gitignored) loaded via dotenv or equivalent |
| Staging / Production | Environment variables injected at deploy time |
| Cloud environments | Secret manager (AWS Secrets Manager, GCP Secret Manager, HashiCorp Vault, etc.) |
Example — load from environment variable (Python):
import os
API_KEY = os.environ["RUBY_TEAM_API_KEY"]
API_SECRET = os.environ["RUBY_TEAM_API_SECRET"]
Example — load from environment variable (Node.js):
const API_KEY = process.env.RUBY_TEAM_API_KEY;
const API_SECRET = process.env.RUBY_TEAM_API_SECRET;
Key Rotation
Rotate your team_api_key and team_api_secret periodically or immediately if you suspect a compromise.
To request key rotation, contact Ruby support. During rotation:
- Ruby issues you a new key pair
- Update your environment variables or secret manager with the new values
- Redeploy your service to pick up the new credentials
- Confirm the old key has been revoked
Keep rotation intervals short for high-security environments (e.g., every 90 days).
Always Use HTTPS
All API requests must be made over HTTPS. Plain HTTP connections are not accepted by the Ruby API server. HTTPS ensures:
- Request headers (including
X-Team-KeyandX-Team-Signature) are encrypted in transit - The server's TLS certificate can be verified to prevent man-in-the-middle attacks
Ensure your HTTP client validates the server certificate and does not disable TLS verification (e.g., avoid verify=False in Python requests or rejectUnauthorized: false in Node.js).
Clock Synchronization
The X-Team-Timestamp header is validated against server time with a ±300 second tolerance. If your server clock drifts beyond this range, all requests will be rejected with a 401 Unauthorized error.
Synchronize your server clock using NTP (Network Time Protocol):
# Check current time offset (Linux)
timedatectl status
# Force NTP sync (systemd-based systems)
sudo systemctl restart systemd-timesyncd
# Verify NTP is active
timedatectl show --property=NTPSynchronized
For cloud-hosted servers, NTP is typically configured automatically. Verify it is enabled and running.
Use Constant-Time Signature Comparison
If you are implementing Seamless Wallet Callbacks and need to verify incoming signatures from Ruby, always use a constant-time comparison function. Naive string equality (==) is vulnerable to timing attacks that allow an attacker to infer the expected signature byte-by-byte.
Python:
import hmac
def verify_signature(expected: str, received: str) -> bool:
return hmac.compare_digest(expected.encode(), received.encode())
Node.js:
const crypto = require("crypto");
function verifySignature(expected, received) {
const a = Buffer.from(expected, "utf8");
const b = Buffer.from(received, "utf8");
if (a.length !== b.length) return false;
return crypto.timingSafeEqual(a, b);
}
Java:
import java.security.MessageDigest;
public static boolean verifySignature(String expected, String received) {
return MessageDigest.isEqual(
expected.getBytes(StandardCharsets.UTF_8),
received.getBytes(StandardCharsets.UTF_8)
);
}
See Callback Authentication for the full callback signature verification guide.
Summary Checklist
-
team_api_secretis stored server-side only, never in client code - Credentials are loaded from environment variables or a secret manager
- Key rotation is scheduled or can be performed on short notice
- All API requests use HTTPS with certificate validation enabled
- Server clock is NTP-synchronized (check periodically)
- Callback signature verification uses constant-time comparison