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:

Current Implementation

Development Mode (Current)

Status: ⚠️ Requires Proxy Server

For development, we use a local proxy server:

  1. OpenAI Proxy (Port 3002)

    • Location: libs/gograb-ai/src/proxy/openai-proxy.js
    • Handles OpenAI API calls
    • Provides CORS support
  2. 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:

  1. Never expose API keys in the browser
  2. Use a backend API server
  3. Implement authentication and authorization
  4. 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:

  1. Make sure the proxy server is running: yarn proxy:ai
  2. Check that the proxy URL is correct in configuration
  3. Verify the proxy server logs for errors

Connection Refused

Error: Connection refused or ERR_CONNECTION_REFUSED

Solution:

  1. Start the proxy server: yarn proxy:ai
  2. Check that port 3002 is not in use by another process
  3. Verify firewall settings

Authentication Errors

Error: No API key provided or Invalid API key

Solution:

  1. Open the AI Configuration panel
  2. Enter your OpenAI API key (starts with sk-)
  3. Save the configuration
  4. Retry your request

API Key Management

Where Keys Are Stored

  1. Development:

    • IndexedDB (browser storage)
    • Environment variables (optional)
  2. Production:

    • Backend server environment variables
    • Secure key management service (AWS Secrets Manager, etc.)

How to Set API Keys

In the UI:

  1. Open AI Chat component
  2. Click Settings/Configuration
  3. Enter your API keys
  4. 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:

  1. Exposes your API key to anyone who inspects the network traffic
  2. Users can steal your key and make unlimited requests
  3. No way to implement rate limiting or cost controls
  4. CORS restrictions from most AI providers

Q: Is the IndexedDB storage secure?

A: IndexedDB provides basic browser storage security:

For production, always store API keys server-side.

Q: How do I rotate API keys?

A:

  1. Generate new API key in provider's dashboard
  2. Update configuration in your app
  3. Test with new key
  4. Revoke old key
  5. Update documentation

Q: Can I use the same proxy for multiple apps?

A: Yes, but implement proper authentication and authorization:

Next Steps

  1. ✅ Start the proxy server: yarn proxy:ai
  2. ✅ Configure your API keys in the UI
  3. ✅ Test the connection
  4. 📋 Plan your production architecture
  5. 🔐 Implement proper authentication
  6. 📊 Add monitoring and analytics

Resources

Support

If you encounter issues:

  1. Check the proxy server logs
  2. Verify your API key is valid
  3. Review the troubleshooting section
  4. Check browser console for errors
  5. Test with the AI Tester component

Last Updated: 2025-10-15 Version: 1.0.0