Security Best Practices
Comprehensive security guidelines for FortiBlox Nexus API keys and applications
Security Best Practices
Protecting your FortiBlox Nexus API keys is critical to preventing unauthorized usage, unexpected charges, and security breaches. This guide provides comprehensive security practices with clear do's and don'ts.
Critical: Never expose API keys in client-side code, public repositories, or browser applications. Compromised keys can lead to service disruption and unexpected charges.
Environment Variables: The Foundation
Don't Do This
// ❌ NEVER hardcode API keys
const apiKey = "fbx_1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p";
const connection = new Connection(
`https://nexus.fortiblox.com/rpc?api-key=${apiKey}`
);# ❌ NEVER hardcode API keys
API_KEY = "fbx_1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p"
client = Client(f"https://nexus.fortiblox.com/rpc?api-key={API_KEY}")// ❌ NEVER hardcode API keys
let api_key = "fbx_1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p";
let url = format!("https://nexus.fortiblox.com/rpc?api-key={}", api_key);Do This Instead
// ✅ CORRECT - Use environment variables
require('dotenv').config();
const connection = new Connection(
`https://nexus.fortiblox.com/rpc?api-key=${process.env.FORTIBLOX_API_KEY}`,
'confirmed'
);
// Validate the key exists
if (!process.env.FORTIBLOX_API_KEY) {
throw new Error('FORTIBLOX_API_KEY environment variable is required');
}Create a .env file:
# .env
FORTIBLOX_API_KEY=fbx_1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p
NODE_ENV=productionAdd to .gitignore:
# .gitignore
.env
.env.local
.env.*.local
*.env# ✅ CORRECT - Use environment variables
import os
from dotenv import load_dotenv
from solana.rpc.api import Client
load_dotenv()
# Validate the key exists
api_key = os.getenv('FORTIBLOX_API_KEY')
if not api_key:
raise ValueError('FORTIBLOX_API_KEY environment variable is required')
client = Client(f"https://nexus.fortiblox.com/rpc?api-key={api_key}")Create a .env file:
# .env
FORTIBLOX_API_KEY=fbx_1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p
ENVIRONMENT=productionAdd to .gitignore:
# .gitignore
.env
*.env
__pycache__/// ✅ CORRECT - Use environment variables
use solana_client::rpc_client::RpcClient;
use std::env;
use dotenv::dotenv;
fn main() -> Result<(), Box<dyn std::error::Error>> {
dotenv().ok();
// Validate the key exists
let api_key = env::var("FORTIBLOX_API_KEY")
.expect("FORTIBLOX_API_KEY environment variable is required");
let url = format!("https://nexus.fortiblox.com/rpc?api-key={}", api_key);
let client = RpcClient::new(url);
Ok(())
}Create a .env file:
# .env
FORTIBLOX_API_KEY=fbx_1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p
RUST_ENV=productionAdd to .gitignore:
# .gitignore
.env
target/
Cargo.lockSeparate Keys Per Environment
Don't Do This
// ❌ NEVER use the same key across environments
const apiKey = process.env.FORTIBLOX_API_KEY; // One key for everythingDo This Instead
// ✅ CORRECT - Environment-specific keys
function getFortiBloxApiKey() {
const env = process.env.NODE_ENV || 'development';
switch (env) {
case 'production':
return process.env.FORTIBLOX_API_KEY_PROD;
case 'staging':
return process.env.FORTIBLOX_API_KEY_STAGING;
case 'development':
default:
return process.env.FORTIBLOX_API_KEY_DEV;
}
}
const apiKey = getFortiBloxApiKey();
if (!apiKey) {
throw new Error(`FORTIBLOX_API_KEY for ${process.env.NODE_ENV} is not set`);
}
const connection = new Connection(
`https://nexus.fortiblox.com/rpc?api-key=${apiKey}`,
'confirmed'
);Benefits:
- Isolate usage and billing per environment
- Revoke compromised keys without affecting other environments
- Apply different access controls per environment
- Better monitoring and cost tracking
Never Use API Keys in Browser Applications
The Problem
<!-- ❌ EXTREMELY DANGEROUS - Anyone can steal your key -->
<script>
const apiKey = 'fbx_1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p';
fetch(`https://nexus.fortiblox.com/rpc?api-key=${apiKey}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
method: 'getHealth',
id: 1
})
});
</script>Why this is dangerous:
- Anyone can open DevTools → Network tab and see your API key
- Your key appears in browser history and logs
- Attackers can copy and abuse your key
- No way to prevent unauthorized usage
Solution 1: Backend Proxy (Recommended)
Create a backend API that proxies requests to FortiBlox:
// ✅ CORRECT - Backend proxy
const express = require('express');
const fetch = require('node-fetch');
require('dotenv').config();
const app = express();
app.use(express.json());
// CORS configuration (restrict to your domain)
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', 'https://yourdomain.com');
res.header('Access-Control-Allow-Methods', 'POST');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
});
app.post('/api/rpc', async (req, res) => {
try {
// API key is stored securely on the server
const apiKey = process.env.FORTIBLOX_API_KEY;
// Optional: Add request validation
if (!req.body.method) {
return res.status(400).json({ error: 'Missing RPC method' });
}
// Optional: Rate limiting per user/IP
// Implement your rate limiting logic here
// Forward request to FortiBlox
const response = await fetch(
`https://nexus.fortiblox.com/rpc?api-key=${apiKey}`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(req.body)
}
);
const data = await response.json();
res.json(data);
} catch (error) {
console.error('RPC proxy error:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
app.listen(3000, () => {
console.log('RPC proxy running on port 3000');
});Frontend code:
// Frontend - No API key exposed!
async function getAccountInfo(publicKey) {
const response = await fetch('/api/rpc', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
method: 'getAccountInfo',
params: [publicKey.toString()],
id: 1
})
});
return await response.json();
}# ✅ CORRECT - Backend proxy
from flask import Flask, request, jsonify
from flask_cors import CORS
import requests
import os
from dotenv import load_dotenv
load_dotenv()
app = Flask(__name__)
# CORS configuration (restrict to your domain)
CORS(app, origins=["https://yourdomain.com"])
@app.route('/api/rpc', methods=['POST'])
def rpc_proxy():
try:
# API key is stored securely on the server
api_key = os.getenv('FORTIBLOX_API_KEY')
if not api_key:
return jsonify({'error': 'Server configuration error'}), 500
# Optional: Add request validation
if 'method' not in request.json:
return jsonify({'error': 'Missing RPC method'}), 400
# Forward request to FortiBlox
response = requests.post(
f"https://nexus.fortiblox.com/rpc?api-key={api_key}",
json=request.json,
headers={'Content-Type': 'application/json'}
)
return jsonify(response.json())
except Exception as e:
print(f"RPC proxy error: {e}")
return jsonify({'error': 'Internal server error'}), 500
if __name__ == '__main__':
app.run(port=5000)// ✅ CORRECT - Next.js API route
// pages/api/rpc.js
export default async function handler(req, res) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
try {
// API key is stored securely on the server
const apiKey = process.env.FORTIBLOX_API_KEY;
if (!req.body.method) {
return res.status(400).json({ error: 'Missing RPC method' });
}
// Forward request to FortiBlox
const response = await fetch(
`https://nexus.fortiblox.com/rpc?api-key=${apiKey}`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(req.body)
}
);
const data = await response.json();
res.status(200).json(data);
} catch (error) {
console.error('RPC proxy error:', error);
res.status(500).json({ error: 'Internal server error' });
}
}Frontend code (React):
// Frontend - No API key exposed!
import { useConnection } from './useConnection';
function MyComponent() {
async function fetchAccountInfo(publicKey) {
const response = await fetch('/api/rpc', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
method: 'getAccountInfo',
params: [publicKey.toString()],
id: 1
})
});
return await response.json();
}
// Use the function...
}Solution 2: FortiBlox RPC Proxy (Coming Soon)
We're developing an open-source RPC proxy tool that you can deploy to Cloudflare Workers, Vercel, or your own infrastructure with one click.
Planned features:
- One-click deployment to Cloudflare Workers
- Automatic request filtering and validation
- Custom rate limiting per user/IP
- Domain whitelisting built-in
- Zero cold-start latency
- WebSocket support
- Free tier friendly (100,000 requests/day on Cloudflare)
Access Control: Multiple Layers
FortiBlox Nexus provides multiple layers of access control to protect your API keys.
Domain Restrictions (Web Applications)
Restrict which domains can use your API key.
Configure in Developer Portal:
- Go to API Keys → Select your key
- Enable Domain Restrictions
- Add allowed domains:
https://myapp.com
https://*.myapp.com
https://staging.myapp.com
localhost:3000Wildcard support: Use *.myapp.com to allow all subdomains
How it works:
// ✅ Request from https://myapp.com - ALLOWED
fetch('https://nexus.fortiblox.com/rpc?api-key=fbx_...', {
method: 'POST',
// Origin header: https://myapp.com
});
// ❌ Request from https://attacker.com - BLOCKED
// Returns: 403 Forbidden - Domain not allowedImportant: Domain restrictions only work when browsers send Origin or Referer headers. For server-to-server calls, use IP restrictions instead.
IP Address Restrictions (Server Applications)
Restrict which IP addresses or CIDR ranges can use your API key.
Configure in Developer Portal:
- Go to API Keys → Select your key
- Enable IP Restrictions
- Add allowed IPs:
# Allow only requests from this IP
203.0.113.45Use cases:
- Single server deployments
- Home/office development
- Specific cloud instances
# Allow requests from this IP range
203.0.113.0/24This allows IPs from 203.0.113.0 to 203.0.113.255 (256 addresses).
Common CIDR ranges:
/32- Single IP (203.0.113.45/32)/24- 256 IPs (203.0.113.0/24)/16- 65,536 IPs (203.0.0.0/16)
# Allow multiple specific IPs (one per line)
203.0.113.45
198.51.100.12
192.0.2.100
2001:db8::1 # IPv6 supportedUse cases:
- Multiple server instances
- Load-balanced deployments
- Distributed systems
# AWS EC2 instances in a VPC
172.31.0.0/16
# Google Cloud Platform
10.128.0.0/16
# Azure
10.0.0.0/16
# DigitalOcean
159.203.0.0/16Find your cloud provider's IP ranges:
Find your IP: Run curl ifconfig.me or visit https://ifconfig.me
Network Restrictions
Restrict which X1 Blockchain networks (mainnet, devnet, testnet) the API key can access.
// API key restricted to devnet only
// ✅ This works - devnet allowed
const devnetConnection = new Connection(
`https://nexus.fortiblox.com/rpc?api-key=${process.env.FORTIBLOX_API_KEY}&network=devnet`
);
// ❌ This fails - mainnet not allowed
// Returns: 403 Forbidden - Network not allowed
const mainnetConnection = new Connection(
`https://nexus.fortiblox.com/rpc?api-key=${process.env.FORTIBLOX_API_KEY}&network=mainnet`
);Benefits:
- Prevent accidental mainnet usage with dev keys
- Separate billing for different networks
- Enhanced security through network isolation
Key Rotation
Regular key rotation minimizes the impact of a compromised key.
Recommended rotation schedule:
- Development keys: Every 90 days
- Production keys: Every 30 days
- After employee departure: Immediately
- After suspected compromise: Immediately
Rotation Procedure
Step 1: Generate new key
- Go to Developer Portal → API Keys
- Click "Create New API Key"
- Use same permissions as old key
- Copy the new key immediately
Step 2: Update environment variables
# Update .env files
echo "FORTIBLOX_API_KEY=fbx_NEW_KEY_HERE" > .env.production
# For cloud deployments
# AWS Secrets Manager
aws secretsmanager update-secret \
--secret-id fortiblox-api-key \
--secret-string "fbx_NEW_KEY_HERE"
# GCP Secret Manager
echo -n "fbx_NEW_KEY_HERE" | \
gcloud secrets versions add fortiblox-api-key --data-file=-
# Azure Key Vault
az keyvault secret set \
--vault-name MyKeyVault \
--name fortiblox-api-key \
--value "fbx_NEW_KEY_HERE"Step 3: Deploy changes
# Deploy to production
git add .env.production
git commit -m "chore: rotate FortiBlox API key"
git push origin main
# Or use your deployment tool
npm run deploy
# or
docker-compose up -dStep 4: Verify functionality
# Test the new key
curl https://nexus.fortiblox.com/rpc?api-key=$NEW_KEY \
-X POST \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"getHealth","id":1}'
# Expected response: {"jsonrpc":"2.0","result":"ok","id":1}Step 5: Monitor and revoke old key
- Monitor production for 24-48 hours
- Check error rates and logs
- Once confirmed working, revoke old key in Developer Portal
- Document the rotation in your changelog
Automated Rotation Script
#!/bin/bash
# rotate-api-key.sh
set -e
echo "FortiBlox API Key Rotation Script"
echo "=================================="
# Step 1: Prompt for new key (manual generation for now)
echo "1. Generate a new API key in the Developer Portal"
echo "2. Copy the new key"
read -sp "Enter new API key: " NEW_KEY
echo
# Step 2: Backup old key
OLD_KEY=$(grep FORTIBLOX_API_KEY .env.production | cut -d '=' -f2)
echo "Old key (first 10 chars): ${OLD_KEY:0:10}..."
# Step 3: Update .env file
sed -i.bak "s/FORTIBLOX_API_KEY=.*/FORTIBLOX_API_KEY=$NEW_KEY/" .env.production
echo "✓ Updated .env.production"
# Step 4: Test new key
echo "Testing new key..."
RESPONSE=$(curl -s https://nexus.fortiblox.com/rpc?api-key=$NEW_KEY \
-X POST \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"getHealth","id":1}')
if echo "$RESPONSE" | grep -q '"result":"ok"'; then
echo "✓ New key is valid"
else
echo "✗ New key validation failed"
echo "Response: $RESPONSE"
# Restore old key
mv .env.production.bak .env.production
exit 1
fi
# Step 5: Commit changes (optional)
echo "API key rotated successfully!"
echo "Remember to:"
echo "1. Deploy the changes"
echo "2. Monitor production for 24-48 hours"
echo "3. Revoke the old key in the Developer Portal"Monitoring API Key Usage
Regular monitoring helps detect suspicious activity early.
What to Monitor
1. Unusual request patterns
- Sudden spike in requests (10x normal)
- Requests at odd hours (3 AM on weekends)
- Requests from unexpected geographic locations
2. Unexpected endpoints
- RPC methods you don't use in your app
- High-cost operations (e.g.,
getProgramAccounts) - Failed authentication attempts
3. Error rates
- Sudden increase in 403 (Forbidden) errors
- Rate limit exceeded errors
- Authentication failures
Set Up Alerts
In the Developer Portal:
- Go to Settings → Notifications
- Enable alerts for:
- Daily credit usage > 80% of monthly limit
- Rate limit exceeded > 10 times/hour
- Unusual usage patterns detected
- Failed authentication > 100 attempts/day
- API key approaching expiration
Email notification example:
Subject: [FortiBlox Alert] Unusual API key usage detected
Your API key (fbx_...5o6p) has unusual activity:
- Request spike: 50,000 requests in the last hour (normal: 5,000)
- New geographic location: Requests from Russia (first time)
- New RPC methods: getProgramAccounts (never used before)
Action recommended: Review your application logs and consider rotating the key.
View details: https://nexus.fortiblox.com/api-keys/12345/analyticsLeast Privilege Principle
Only grant the minimum necessary permissions to each API key.
Don't Do This
// ❌ One key with all permissions
const masterKey = process.env.FORTIBLOX_MASTER_KEY;
// Used everywhere
const rpcConnection = new Connection(`https://nexus.fortiblox.com/rpc?api-key=${masterKey}`);
const geyserStream = connectGeyser(masterKey);
const enhancedApi = new EnhancedAPI(masterKey);Do This Instead
// ✅ Separate keys for different services
const config = {
rpc: process.env.FORTIBLOX_RPC_KEY, // RPC-only access
geyser: process.env.FORTIBLOX_GEYSER_KEY, // Geyser-only access
enhanced: process.env.FORTIBLOX_ENHANCED_KEY // Enhanced API only
};
// Each service uses its specific key
const rpcConnection = new Connection(
`https://nexus.fortiblox.com/rpc?api-key=${config.rpc}`
);
const geyserStream = connectGeyser(config.geyser);
const enhancedApi = new EnhancedAPI(config.enhanced);Benefits:
- Limit blast radius of compromised keys
- Better cost tracking per service
- Easier to debug issues
- Granular access control
- Revoke specific service access without affecting others
Git Repository Safety
Don't Do This
# ❌ NEVER commit .env files
git add .env
git commit -m "Add configuration"
git push origin main
# Now your API key is in git history foreverDo This Instead
# ✅ CORRECT - Always .gitignore sensitive files
# 1. Create .gitignore before first commit
echo ".env" >> .gitignore
echo ".env.local" >> .gitignore
echo ".env.*.local" >> .gitignore
echo "*.env" >> .gitignore
# 2. Commit .gitignore
git add .gitignore
git commit -m "Add .gitignore"
# 3. Create .env.example as a template (without real keys)
cat > .env.example << 'EOF'
# FortiBlox API Configuration
FORTIBLOX_API_KEY=fbx_your_api_key_here
NODE_ENV=development
EOF
# 4. Commit the template
git add .env.example
git commit -m "Add environment template"If You Already Committed Secrets
If you accidentally committed API keys to git, you must:
1. Revoke the exposed key immediately
- Go to Developer Portal → API Keys
- Find the exposed key and click "Revoke"
2. Remove from git history
# Use BFG Repo-Cleaner (easier than git filter-branch)
# Download from: https://rtyley.github.io/bfg-repo-cleaner/
# Remove .env from history
bfg --delete-files .env
# Clean up
git reflog expire --expire=now --all
git gc --prune=now --aggressive
# Force push (WARNING: coordinate with team first!)
git push origin --force --all3. Generate a new key
- Create a new API key in Developer Portal
- Update your application with the new key
Important: Even after removing from git history, assume the key was compromised. Always revoke and regenerate.
Security Checklist
Use this checklist to ensure your API keys are secure:
Development
- API keys stored in environment variables (not hardcoded)
-
.envfiles added to.gitignore -
.env.exampletemplate provided (without real keys) - No API keys in source code or comments
- No API keys in configuration files committed to git
Deployment
- Separate keys for dev, staging, and production
- Keys stored in secure secret management (AWS Secrets Manager, etc.)
- Environment-specific key selection logic implemented
- Keys validated on application startup
Access Control
- Domain restrictions enabled (for web apps)
- IP restrictions enabled (for server apps)
- Network restrictions configured (mainnet/devnet)
- Least privilege principle applied (separate keys per service)
Monitoring & Rotation
- Usage monitoring enabled in Developer Portal
- Alert notifications configured
- Key rotation schedule documented
- Keys rotated at least every 90 days
- Old/unused keys revoked
Client-Side Safety
- Backend proxy used for browser applications
- No API keys in frontend JavaScript
- No API keys in mobile app code
- CORS configured on backend proxy
Team Management
- Team members use their own keys (no sharing)
- Keys revoked when team members leave
- Key management process documented
- Security training provided to team
What to Do If Your Key Is Compromised
If you suspect your API key has been compromised, act immediately:
1. Revoke the key (5 seconds)
- Go to Developer Portal → API Keys
- Click the compromised key
- Click "Revoke Key" → Confirm
2. Generate a new key (30 seconds)
- Click "Create New API Key"
- Use a descriptive name (e.g., "Production v2 - Rotated 2025-01-15")
- Configure same permissions as old key
- Copy the new key immediately
3. Update applications (5-15 minutes)
# Update environment variables
export FORTIBLOX_API_KEY="new_key_here"
# Or update secrets
aws secretsmanager update-secret --secret-id fortiblox-api-key \
--secret-string "new_key_here"
# Restart applications
docker-compose restart
# or
kubectl rollout restart deployment/my-app4. Review usage (10 minutes)
- Go to Developer Portal → Analytics
- Check recent requests for suspicious activity
- Download usage logs if needed
5. Check billing (5 minutes)
- Review current credit usage
- Check for unexpected charges
- Contact support if abuse detected
6. Contact support (if needed)
- Email: [email protected]
- Subject: "Compromised API Key - Urgent"
- Include: Key ID, time of compromise, estimated impact
Act fast! The faster you revoke a compromised key, the less damage an attacker can do. Don't wait to investigate - revoke first, investigate later.
Additional Resources
Access Control Guide
Detailed guide on domain, IP, and network restrictions
RPC Proxy Tool
Deploy your own RPC proxy for browser apps
Rate Limits
Understand rate limits and optimize usage
API Key Management API
Programmatically manage your API keys
Support
Need help securing your API keys?
- Discord: discord.gg/fortiblox - Community support
- Email: [email protected] - Security team
- Documentation: Browse our comprehensive security guides
- Emergency: For compromised keys, email [email protected] immediately