A secure, production-ready Node.js/Express backend that acts as a proxy for AI services (OpenRouter, OpenAI, Anthropic). Designed to be consumed by multiple frontend applications with built-in authentication, rate limiting, and usage tracking.
Live Demo: Flutter App using this Integration
See this API proxy in action with a real Flutter application!
If you find this project helpful, consider supporting me:
- Multi-Provider Support: OpenRouter, OpenAI, Anthropic (easily extensible)
- Secure API Key Management: Keep your AI API keys safe on the server
- Authentication: API key-based authentication for clients
- Rate Limiting: Configurable rate limits per client/IP
- CORS Support: Configurable allowed origins
- Request Validation: Comprehensive input validation
- Logging: Winston-based logging with rotation
- Error Handling: Centralized error handling
- Health Checks: Built-in health and status endpoints
- Docker Support: Ready for containerized deployment
- Production Ready: Security best practices with Helmet, compression, etc.
- Node.js >= 18.0.0
- npm >= 9.0.0
- OpenRouter API key (or other AI provider keys)
git clone <your-repo-url>
cd ai-api-proxy-backend
npm install
# Copy example environment file
cp .env.example .env
# Edit .env with your configuration
nano .env
Generate secure API keys for your clients:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
Add the generated keys to .env
:
CLIENT_API_KEYS=generated_key_1,generated_key_2,generated_key_3
Edit .env
file with your settings:
# Server
PORT=3000
NODE_ENV=production
# OpenRouter (Required)
OPENROUTER_API_KEY=your_openrouter_key_here
OPENROUTER_BASE_URL=https://openrouter.ai/api/v1
# Client Authentication (Required)
CLIENT_API_KEYS=key1,key2,key3
# Rate Limiting
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX_REQUESTS=100
# CORS
ALLOWED_ORIGINS=https://yourdomain.com,https://app.yourdomain.com
# Logging
LOG_LEVEL=info
# App Info
APP_NAME=AI API Proxy
APP_REFERER=https://yourdomain.com
npm run dev
npm start
# Build and run with Docker Compose
docker-compose up -d
# Or build and run manually
docker build -t ai-api-proxy .
docker run -p 3000:3000 --env-file .env ai-api-proxy
GET /health
Response:
{
"status": "healthy",
"timestamp": "2025-01-01T00:00:00.000Z",
"uptime": 123.45,
"environment": "production"
}
GET /api/info
Returns API documentation and available endpoints.
GET /api/status
Returns detailed service status and configuration.
All protected endpoints require authentication via:
- Header:
X-API-Key: your_client_api_key
- OR Header:
Authorization: Bearer your_client_api_key
POST /api/ai/generate
Request body:
{
"prompt": "What is artificial intelligence?",
"model": "google/gemini-2.0-flash-exp:free",
"temperature": 0.7,
"max_tokens": 500
}
Response:
{
"success": true,
"text": "Artificial intelligence (AI) is...",
"model": "google/gemini-2.0-flash-exp:free",
"usage": {
"prompt_tokens": 10,
"completion_tokens": 50,
"total_tokens": 60
}
}
POST /api/ai/completion
Request body:
{
"provider": "openrouter",
"model": "google/gemini-2.0-flash-exp:free",
"messages": [
{ "role": "system", "content": "You are a helpful assistant." },
{ "role": "user", "content": "Hello!" }
],
"temperature": 0.7,
"max_tokens": 500
}
POST /api/ai/embedding
Request body:
{
"text": "Text to generate embeddings for",
"provider": "openrouter",
"model": "text-embedding-ada-002"
}
GET /api/ai/models?provider=openrouter
This proxy uses API key authentication. Clients must include their API key in every request:
# Using curl
curl -X POST http://localhost:3000/api/ai/generate \
-H "X-API-Key: your_client_api_key" \
-H "Content-Type: application/json" \
-d '{"prompt": "Hello world"}'
# Or with Authorization header
curl -X POST http://localhost:3000/api/ai/generate \
-H "Authorization: Bearer your_client_api_key" \
-H "Content-Type: application/json" \
-d '{"prompt": "Hello world"}'
class AIProxyService {
static const String baseUrl = 'https://your-proxy-domain.com';
static const String apiKey = 'your_client_api_key';
final http.Client client;
AIProxyService(this.client);
Future<String> generateText(String prompt) async {
final response = await client.post(
Uri.parse('$baseUrl/api/ai/generate'),
headers: {
'X-API-Key': apiKey,
'Content-Type': 'application/json',
},
body: jsonEncode({
'prompt': prompt,
'model': 'google/gemini-2.0-flash-exp:free',
'temperature': 0.7,
'max_tokens': 500,
}),
);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
return data['text'];
} else {
throw Exception('Failed to generate text');
}
}
}
class AIProxyClient {
constructor(baseUrl, apiKey) {
this.baseUrl = baseUrl;
this.apiKey = apiKey;
}
async generateText(prompt) {
const response = await fetch(`${this.baseUrl}/api/ai/generate`, {
method: 'POST',
headers: {
'X-API-Key': this.apiKey,
'Content-Type': 'application/json',
},
body: JSON.stringify({
prompt,
model: 'google/gemini-2.0-flash-exp:free',
temperature: 0.7,
max_tokens: 500,
}),
});
if (!response.ok) {
throw new Error('Failed to generate text');
}
const data = await response.json();
return data.text;
}
}
// Usage
const client = new AIProxyClient('https://your-proxy-domain.com', 'your_client_api_key');
const result = await client.generateText('Hello, world!');
console.log(result);
import requests
import json
class AIProxyClient:
def __init__(self, base_url, api_key):
self.base_url = base_url
self.api_key = api_key
def generate_text(self, prompt):
response = requests.post(
f"{self.base_url}/api/ai/generate",
headers={
"X-API-Key": self.api_key,
"Content-Type": "application/json"
},
json={
"prompt": prompt,
"model": "google/gemini-2.0-flash-exp:free",
"temperature": 0.7,
"max_tokens": 500
}
)
response.raise_for_status()
return response.json()["text"]
# Usage
client = AIProxyClient("https://your-proxy-domain.com", "your_client_api_key")
result = client.generate_text("Hello, world!")
print(result)
- Never expose your AI provider API keys - Keep them only on the backend
- Use HTTPS in production - Always use SSL/TLS certificates
- Rotate client API keys regularly - Generate new keys periodically
- Monitor usage - Check logs for suspicious activity
- Set appropriate rate limits - Protect against abuse
- Restrict CORS origins - Only allow trusted domains
- Use environment variables - Never commit secrets to version control
Logs are stored in the logs/
directory:
error.log
- Error level logscombined.log
- All logs
In production, consider integrating with:
- ELK Stack (Elasticsearch, Logstash, Kibana)
- Datadog
- New Relic
- CloudWatch (AWS)
- Set up your server (Ubuntu/Debian recommended)
- Install Node.js 18+
- Clone repository
- Configure
.env
- Use PM2 for process management:
npm install -g pm2
pm2 start src/server.js --name ai-proxy
pm2 save
pm2 startup
# Build image
docker build -t ai-api-proxy .
# Run container
docker run -d -p 3000:3000 --env-file .env --name ai-proxy ai-api-proxy
# Or use Docker Compose
docker-compose up -d
- Heroku: Use Procfile with
web: node src/server.js
- AWS ECS/EKS: Use provided Dockerfile
- Google Cloud Run: Deploy container directly
- DigitalOcean App Platform: Auto-detects Node.js
- Railway: Connect git repository
- Render: Deploy from GitHub
# Run tests
npm test
# Test health endpoint
curl http://localhost:3000/health
# Test with authentication
curl -X POST http://localhost:3000/api/ai/generate \
-H "X-API-Key: your_client_key" \
-H "Content-Type: application/json" \
-d '{"prompt": "Test prompt"}'
This is a generic, reusable backend. Contributions welcome:
- Fork the repository
- Create a feature branch
- Make your changes
- Submit a pull request
MIT License - feel free to use in your projects
For issues, questions, or contributions:
- Create an issue on GitHub
- Check logs in
logs/
directory - Review
/api/info
endpoint for documentation
Current version: 1.0.0
See CHANGELOG.md for version history.
- Add OpenAI Assistants API support
- Implement usage tracking and analytics
- Add webhook support for async operations
- Create admin dashboard
- Add Redis for rate limiting in distributed systems
- Implement request caching
- Add more AI providers (Anthropic Claude, etc.)
- Create SDK packages for popular languages
Built with β€οΈ for the AI community