API Key Management
This guide explains how users can manage their own API keys for LLM providers in Gofannon. User-specific API keys take precedence over system-wide environment variables.
Table of Contents
- Overview
- How It Works
- User Interface
- API Endpoints
- Backend Implementation
- Security Considerations
- Configuration
Overview
Gofannon supports two ways to configure API keys for LLM providers:
- Environment Variables (System-wide): Set by administrators for all users
- User Profile Keys (User-specific): Each user can configure their own API keys
When both are available, user-specific keys take precedence over environment variables.
How It Works
Priority Order
When making an LLM API call, the system looks for API keys in this order:
- User's stored API key (if configured in profile)
- Environment variable (system-wide fallback)
- No key available (provider unavailable)
Example Flow
User requests GPT-4 completion
↓
Check user's profile for OpenAI API key
↓
┌────┴────┐
Found Not Found
↓ ↓
Use key Check OPENAI_API_KEY env var
↓
┌────┴────┐
Found Not Found
↓ ↓
Use key Error: Provider unavailable
User Interface
Profile Page
Users can manage their API keys through the Profile page:
- Navigate to Profile → API Keys tab
- View configured providers (showing "Configured" or "Not configured" status)
- Add, update, or remove API keys for each provider
Available Providers
The following providers support user-specific API keys:
| Provider | Environment Variable | User Key Field |
|---|---|---|
| OpenAI | OPENAI_API_KEY | openaiApiKey |
| Anthropic | ANTHROPIC_API_KEY | anthropicApiKey |
| Google Gemini | GEMINI_API_KEY | geminiApiKey |
| Perplexity | PERPLEXITYAI_API_KEY | perplexityApiKey |
UI Components
- Status Chip: Shows "Configured" (green) or "Not configured" (gray)
- Add/Update Button: Opens input field to enter a new API key
- Remove Button: Deletes the stored API key
- Masked Display: Keys are always masked (••••••••) in the UI
API Endpoints
Get User's API Keys
GET /api/users/me/api-keys
Returns the user's API keys (masked for security).
Response:
{
"openaiApiKey": "sk-...",
"anthropicApiKey": null,
"geminiApiKey": null,
"perplexityApiKey": null
}
Update API Key
PUT /api/users/me/api-keys
Content-Type: application/json
{
"provider": "openai",
"apiKey": "sk-..."
}
Supported providers: openai, anthropic, gemini, perplexity
Delete API Key
DELETE /api/users/me/api-keys/{provider}
Removes the stored API key for the specified provider.
Check Effective API Key
GET /api/users/me/api-keys/{provider}/effective
Returns whether an effective API key exists without exposing the actual key.
Response:
{
"provider": "openai",
"hasKey": true,
"source": "user" // or "env" or null
}
Backend Implementation
User Model
The User model includes an api_keys field:
class ApiKeys(BaseModel):
openai_api_key: Optional[str] = None
anthropic_api_key: Optional[str] = None
gemini_api_key: Optional[str] = None
perplexity_api_key: Optional[str] = None
class User(BaseModel):
# ... other fields ...
api_keys: ApiKeys = Field(default_factory=ApiKeys)
UserService Methods
# Get user's API keys
api_keys = user_service.get_api_keys(user_id)
# Update a specific API key
user_service.update_api_key(user_id, "openai", "sk-...")
# Delete a specific API key
user_service.delete_api_key(user_id, "openai")
# Get effective API key (user key first, then env var)
api_key = user_service.get_effective_api_key(user_id, "openai")
LLM Service Integration
The LLM service uses get_effective_api_key to determine which key to use:
# In call_llm() and stream_llm()
api_key = user_service.get_effective_api_key(user_id, provider)
if api_key:
kwargs["api_key"] = api_key
Provider Availability
The get_available_providers() function now considers user-specific keys:
def get_available_providers(user_id=None, user_basic_info=None):
# Check user-specific key first
if user_service and user_id:
user_key = user_service.get_effective_api_key(user_id, provider)
if user_key:
is_available = True
# Fall back to environment variable
if not is_available:
is_available = os.getenv(api_key_env_var) is not None
Security Considerations
Key Storage
- API keys are stored in the user's profile in the database
- Keys are not encrypted at rest (recommendation: use database-level encryption)
- Keys are transmitted over HTTPS
Key Masking
- Keys are never returned in full to the frontend
- Only the last 4 characters are shown (e.g.,
sk-...abcd) - Status checks only return boolean
hasKey, never the actual key
Best Practices
- Use environment variables for shared deployments: If running Gofannon as a shared service, consider using environment variables rather than user-specific keys
- Rotate keys regularly: Encourage users to rotate their API keys periodically
- Monitor usage: Track API usage per user to detect potential key abuse
- Secure database: Ensure the database has proper access controls and encryption
Configuration
Database Schema
When implementing a new database backend, ensure it can store the api_keys field in the user document:
{
"_id": "user-id",
"basicInfo": { ... },
"billingInfo": { ... },
"usageInfo": { ... },
"apiKeys": {
"openaiApiKey": "sk-...",
"anthropicApiKey": null,
"geminiApiKey": null,
"perplexityApiKey": null
}
}
Adding New Providers
To add support for a new provider:
- Update
ApiKeysmodel inmodels/user.py:
class ApiKeys(BaseModel):
# ... existing keys ...
new_provider_api_key: Optional[str] = None
- Add to
provider_key_mapinservices/user_service.py:
provider_key_map = {
# ... existing mappings ...
"new_provider": "new_provider_api_key",
}
- Update the UI in
components/profile/ApiKeysTab.jsx:
const PROVIDERS = [
// ... existing providers ...
{ id: 'new_provider', name: 'New Provider', description: '...' },
];
Troubleshooting
Provider Not Available
If a provider shows as unavailable:
- Check if the user has configured an API key in their profile
- Verify the environment variable is set (for fallback)
- Check the provider configuration in
config/provider_config.py
Key Not Working
If API calls fail with an authentication error:
- Verify the API key is valid by testing directly with the provider
- Check for typos or extra whitespace in the stored key
- Ensure the key has the necessary permissions/scopes
Migration from Environment Variables
To migrate from environment variables to user-specific keys:
- Leave environment variables in place as fallback
- Users can add their own keys in their profile
- User keys will automatically take precedence
Last Updated: January 2026 Maintainer: AI Alliance Gofannon Team