SECURE API ARCHITECTURE
Ecosistema completo para organización y gestión de contenido con interfaces espaciales
🔒 Secure AI API Architecture
Overview
This document describes the secure architecture for connecting to AI APIs (OpenAI, Anthropic, Google) in the GoGrab platform.
⚠️ CRITICAL SECURITY NOTICE: Never expose API keys in the browser. Always use a backend proxy or server to handle AI API calls.
Architecture Layers
┌─────────────────────────────────────────────────────────────┐
│ Browser (Frontend) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Angular Services │ │
│ │ - OpenAIService │ │
│ │ - AnthropicService │ │
│ │ - GoogleService │ │
│ └──────────────────┬──────────────────────────────────┘ │
└─────────────────────┼──────────────────────────────────────┘
│
│ Secure HTTP Calls
│ (No API keys in browser)
▼
┌─────────────────────────────────────────────────────────────┐
│ Proxy Layer (Node.js) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ OpenAI Proxy Server (Port 3002) │ │
│ │ - Handles CORS │ │
│ │ - Validates requests │ │
│ │ - Forwards to OpenAI API │ │
│ │ - Returns sanitized responses │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────┬───────────────────────────────────────┘
│
│ Authenticated API Calls
│ (API keys managed server-side)
▼
┌─────────────────────────────────────────────────────────────┐
│ External AI APIs │
│ - OpenAI API (api.openai.com) │
│ - Anthropic API (api.anthropic.com) │
│ - Google AI API (generativelanguage.googleapis.com) │
└─────────────────────────────────────────────────────────────┘
Security Principles
1. Never Store API Keys in Frontend Code
❌ BAD:
const apiKey = 'sk-1234567890abcdef'; // NEVER DO THIS!
✅ GOOD:
// API keys stored in:
// - IndexedDB (encrypted)
// - Environment variables (server-side)
// - Secure backend configuration
2. Always Use Proxy for API Calls
❌ BAD (Direct API call from browser):
this.http.post('https://api.openai.com/v1/chat/completions', body, {
headers: { Authorization: `Bearer ${apiKey}` }
});
✅ GOOD (Through proxy):
this.proxyService.sendChatRequest(body, apiKey);
// Proxy handles authentication and CORS
3. Implement Rate Limiting
Proxy servers should implement rate limiting to prevent abuse:
- Per-user limits
- Per-IP limits
- Token budget tracking
Current Implementation
Development Mode (Current)
Status: ⚠️ Requires Proxy Server
For development, we use a local proxy server:
OpenAI Proxy (Port 3002)
- Location:
libs/gograb-ai/src/proxy/openai-proxy.js - Handles OpenAI API calls
- Provides CORS support
- Location:
Configuration
- API keys stored in IndexedDB
- Proxy URL:
http://localhost:3002
To Start Development:
# Terminal 1: Start the AI proxy
yarn proxy:ai
# Terminal 2: Start your app
yarn dev:gograb # or your app command
Production Mode (Recommended)
For production, you should:
- Never expose API keys in the browser
- Use a backend API server
- Implement authentication and authorization
- Add rate limiting and monitoring
How to Use
Starting the Proxy Server
# Start OpenAI proxy
yarn proxy:openai
# Or use the alias
yarn proxy:ai
The proxy will start on http://localhost:3002
Configuring Your App
The services are pre-configured to use the proxy. No additional configuration needed for development.
Testing the Connection
Use the AI Chat component or AI Tester to verify connectivity:
// In your component
const aiService = inject(AIFactoryService);
const openaiService = aiService.getService(AIProvider.OPENAI);
// Test connection
openaiService.complete([
{ role: MessageRole.USER, content: 'Hello' }
]).subscribe({
next: (response) => console.log('✅ Connected:', response),
error: (error) => console.error('❌ Error:', error)
});
Troubleshooting
CORS Errors
Error: Access to XMLHttpRequest has been blocked by CORS policy
Solution:
- Make sure the proxy server is running:
yarn proxy:ai - Check that the proxy URL is correct in configuration
- Verify the proxy server logs for errors
Connection Refused
Error: Connection refused or ERR_CONNECTION_REFUSED
Solution:
- Start the proxy server:
yarn proxy:ai - Check that port 3002 is not in use by another process
- Verify firewall settings
Authentication Errors
Error: No API key provided or Invalid API key
Solution:
- Open the AI Configuration panel
- Enter your OpenAI API key (starts with
sk-) - Save the configuration
- Retry your request
API Key Management
Where Keys Are Stored
Development:
- IndexedDB (browser storage)
- Environment variables (optional)
Production:
- Backend server environment variables
- Secure key management service (AWS Secrets Manager, etc.)
How to Set API Keys
In the UI:
- Open AI Chat component
- Click Settings/Configuration
- Enter your API keys
- Save
Programmatically:
const configService = inject(AiConfigService);
configService.setApiKey(AIProvider.OPENAI, 'sk-your-key-here');
Migration from Direct API
If you have code making direct API calls:
Before (Insecure):
this.http.post('https://api.openai.com/v1/chat/completions', body, {
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json'
}
});
After (Secure):
// OpenAIService now uses proxy automatically
this.openaiService.complete(messages, options);
Best Practices
1. Environment-Specific Configuration
// environment.ts
export const environment = {
production: false,
aiProxy: {
openai: 'http://localhost:3002',
useProxy: true
}
};
// environment.prod.ts
export const environment = {
production: true,
aiProxy: {
openai: 'https://your-backend-api.com/ai',
useProxy: true
}
};
2. Error Handling
Always handle errors gracefully:
this.openaiService.complete(messages, options).pipe(
catchError(error => {
if (error.error === 'proxy_unavailable') {
this.showError('AI service is currently unavailable');
} else if (error.type === 'authentication_error') {
this.showError('Please configure your API key');
}
return EMPTY;
})
).subscribe();
3. Rate Limiting UI
Show users when they're approaching limits:
// Track token usage
const usage = completion.usage;
console.log(`Tokens used: ${usage.totalTokens}`);
// Warn users
if (usage.totalTokens > 90000) {
this.showWarning('Approaching token limit for this month');
}
Production Deployment
Option 1: Standalone Proxy Server
Deploy the proxy as a separate Node.js service:
# In your production server
cd libs/gograb-ai/src/proxy
node openai-proxy.js
Configure with environment variables:
PORT=3002
ALLOWED_ORIGINS=https://your-domain.com
OPENAI_API_KEY=sk-your-production-key
Option 2: Integrated Backend API
Create API endpoints in your backend:
// NestJS example
@Controller('api/ai')
export class AIController {
@Post('openai/chat')
async chat(@Body() body: any) {
// Validate user
// Check rate limits
// Call OpenAI API
// Return response
}
}
Option 3: Serverless Functions
Use AWS Lambda, Google Cloud Functions, or Vercel Functions:
// Vercel function: api/openai.ts
export default async function handler(req, res) {
// Validate request
// Call OpenAI API
// Return response
}
Monitoring and Logging
Track important metrics:
// Log API calls
console.log('AI API Call:', {
provider: 'openai',
model: 'gpt-4',
tokens: usage.totalTokens,
cost: calculateCost(usage),
timestamp: new Date()
});
// Track errors
console.error('AI API Error:', {
error: error.type,
message: error.message,
timestamp: new Date()
});
Cost Management
Token Tracking
// Track cumulative usage
let totalTokens = 0;
let totalCost = 0;
service.complete(messages).subscribe(completion => {
totalTokens += completion.usage.totalTokens;
totalCost += calculateCost(completion.usage);
console.log(`Total tokens: ${totalTokens}`);
console.log(`Estimated cost: $${totalCost.toFixed(4)}`);
});
Setting Limits
const MAX_TOKENS_PER_REQUEST = 4000;
const MAX_MONTHLY_SPEND = 100; // dollars
if (requestTokens > MAX_TOKENS_PER_REQUEST) {
throw new Error('Request exceeds token limit');
}
if (monthlySpend >= MAX_MONTHLY_SPEND) {
throw new Error('Monthly budget exceeded');
}
FAQ
Q: Why can't I call OpenAI API directly from the browser?
A: For security reasons:
- Exposes your API key to anyone who inspects the network traffic
- Users can steal your key and make unlimited requests
- No way to implement rate limiting or cost controls
- CORS restrictions from most AI providers
Q: Is the IndexedDB storage secure?
A: IndexedDB provides basic browser storage security:
- ✅ Isolated per origin (domain)
- ✅ Not accessible to other websites
- ❌ Not encrypted by default
- ❌ Accessible via browser DevTools
- ❌ Not suitable for production
For production, always store API keys server-side.
Q: How do I rotate API keys?
A:
- Generate new API key in provider's dashboard
- Update configuration in your app
- Test with new key
- Revoke old key
- Update documentation
Q: Can I use the same proxy for multiple apps?
A: Yes, but implement proper authentication and authorization:
- Verify the requesting app
- Implement per-app rate limits
- Track usage per app
- Add app-specific logging
Next Steps
- ✅ Start the proxy server:
yarn proxy:ai - ✅ Configure your API keys in the UI
- ✅ Test the connection
- 📋 Plan your production architecture
- 🔐 Implement proper authentication
- 📊 Add monitoring and analytics
Resources
Support
If you encounter issues:
- Check the proxy server logs
- Verify your API key is valid
- Review the troubleshooting section
- Check browser console for errors
- Test with the AI Tester component
Last Updated: 2025-10-15 Version: 1.0.0