Skip to main content

Security Best Practices

Security is critical when working with AI platforms. This guide covers best practices for protecting your Claro API keys, managing access, and maintaining a secure integration.

API Key Management

Creating Secure API Keys

1

Use Descriptive Names

Name API keys by environment and purpose:
✅ Good:
- production-web-app
- staging-api-tests
- development-local

❌ Bad:
- key1
- test
- mykey
2

Create Environment-Specific Keys

Never share API keys across environments:
  • Development - Local testing only
  • Staging - Pre-production validation
  • Production - Live applications only
3

Document Key Purpose

Keep a record of what each key is used for:
production-web-app: Main website customer support
staging-api-tests: CI/CD integration tests
development-jane: Jane's local development
4

Save Keys Immediately

API keys are only shown once during creation. Save them securely immediately.
If you lose an API key, you must delete it and create a new one. There is no way to retrieve a lost key.

Storing API Keys Securely

Never commit API keys to version control or share them publicly:
Local Development
# .env file (add to .gitignore!)
BAYT_API_KEY=your_api_key_here
OPENAI_API_KEY=your_openai_key_here
Load in your application:
import os
from dotenv import load_dotenv
from baytos.claro import BaytClient

load_dotenv()

client = BaytClient(api_key=os.getenv("BAYT_API_KEY"))
Always add .env to .gitignore:
echo ".env" >> .gitignore

Key Rotation

Regular key rotation reduces the risk of compromised keys:

Rotation Schedule

Development

Every 6 months Lower risk, less frequent rotation

Staging

Every 3 months Regular rotation for testing

Production

Every 90 days Highest security standard

Safe Rotation Process

1

Create New Key

Generate a new API key in the Claro dashboard
2

Deploy New Key

Update your application with the new key:
  • Update environment variables
  • Deploy to staging first
  • Test thoroughly
  • Deploy to production
3

Monitor for Issues

Watch for errors over 24-48 hours:
  • Check error rates
  • Monitor authentication failures
  • Verify all services updated
4

Delete Old Key

Once confirmed the new key works everywhere, delete the old key
Never delete the old key before deploying the new one. This will break your production application.

Emergency Key Rotation

If you suspect a key is compromised:
1

Immediately Create New Key

Don’t wait - create a replacement key right away
2

Quick Deploy

Deploy the new key as quickly as possible, even if it means brief downtime
3

Delete Compromised Key

Delete the compromised key immediately to prevent unauthorized access
4

Audit Access

Review API access logs to understand the extent of unauthorized use
5

Notify Team

Alert your security team and stakeholders

Access Control

Workspace Permissions

Limit who can create and manage API keys:
RoleCan Create KeysCan View KeysCan Delete Keys
Owner
Admin
Member
Viewer
Only Owners and Admins should manage API keys.

Service Accounts

For production systems, use service accounts instead of personal accounts:
1

Create Service Account

Create a dedicated account for your application (e.g., [email protected])
2

Add to Workspace

Invite the service account to your workspace with appropriate permissions
3

Generate API Keys

Create API keys from the service account
4

Document Ownership

Document which team owns each service account
Service accounts ensure API keys aren’t tied to individual employees who may leave the organization.

Audit Logging

Monitoring API Usage

Track API key usage in the Claro dashboard:
1

Navigate to API Keys

Go to Settings → API Keys in the Claro dashboard
2

View Usage Statistics

For each key, review:
  • Last used timestamp
  • Total requests
  • Error rates
  • Usage patterns
3

Identify Anomalies

Look for suspicious activity:
  • Unexpected spikes in usage
  • Requests from unusual locations
  • High error rates
  • Usage of supposedly inactive keys

Automated Monitoring

Set up alerts for suspicious activity:
import requests
import os
from datetime import datetime, timedelta

def check_api_usage():
    """Monitor API key usage for anomalies"""
    # Fetch usage data from Claro API
    api_key = os.getenv("BAYT_API_KEY")
    headers = {"Authorization": f"Bearer {api_key}"}

    response = requests.get(
        "https://api.baytos.ai/v1/usage",
        headers=headers
    )

    usage = response.json()

    # Check for anomalies
    if usage['requests_today'] > usage['avg_requests'] * 2:
        send_alert(
            f"Unusual API usage: {usage['requests_today']} requests "
            f"(avg: {usage['avg_requests']})"
        )

    if usage['error_rate'] > 0.05:  # 5% error rate
        send_alert(
            f"High error rate: {usage['error_rate']*100}%"
        )

def send_alert(message):
    """Send alert via email, Slack, PagerDuty, etc."""
    # Your alerting logic
    pass

Secrets Management

Environment-Specific Secrets

Never mix secrets across environments:
# ✅ Good: Clear environment separation
ENVIRONMENTS = {
    'development': {
        'BAYT_API_KEY': os.getenv('BAYT_API_KEY_DEV'),
        'OPENAI_API_KEY': os.getenv('OPENAI_API_KEY_DEV'),
    },
    'staging': {
        'BAYT_API_KEY': os.getenv('BAYT_API_KEY_STAGING'),
        'OPENAI_API_KEY': os.getenv('OPENAI_API_KEY_STAGING'),
    },
    'production': {
        'BAYT_API_KEY': os.getenv('BAYT_API_KEY_PROD'),
        'OPENAI_API_KEY': os.getenv('OPENAI_API_KEY_PROD'),
    }
}

env = os.getenv('ENVIRONMENT', 'development')
config = ENVIRONMENTS[env]

Secrets in Configuration Files

Never commit secrets to git:
# ❌ BAD - config.yaml committed to git
api:
  key: sk_live_abc123  # Never do this!

# ✅ Good - config.yaml with placeholder
api:
  key: ${BAYT_API_KEY}  # Loaded from environment
Load secrets at runtime:
import yaml
import os

def load_config(config_file):
    """Load config with environment variable substitution"""
    with open(config_file) as f:
        config = yaml.safe_load(f)

    # Replace ${VAR} with environment variable
    for key, value in config.items():
        if isinstance(value, str) and value.startswith('${'):
            env_var = value[2:-1]  # Extract VAR from ${VAR}
            config[key] = os.getenv(env_var)

    return config

OWASP Considerations

Preventing Common Vulnerabilities

Risk: User input injected into prompts could manipulate LLM behaviorPrevention:
def safe_prompt_injection(user_input: str, prompt_template: str) -> str:
    """Safely inject user input into prompts"""
    # Sanitize user input
    sanitized = user_input.strip()

    # Escape special characters if needed
    sanitized = sanitized.replace("{", "{{").replace("}", "}}")

    # Use template with clear boundaries
    return prompt_template.format(user_input=sanitized)

# Example usage
from baytos.claro import BaytClient

client = BaytClient(api_key=os.getenv("BAYT_API_KEY"))
prompt = client.get_prompt("@workspace/qa-bot:v1")

# Inject user input safely
full_prompt = safe_prompt_injection(
    user_input="What are your hours?",
    prompt_template=f"{prompt.generator}\n\nUser question: {{user_input}}"
)
Risk: Sensitive data leaked through prompts or API responsesPrevention:
  • Never include PII in prompts
  • Redact sensitive data before logging
  • Use environment-specific prompts
  • Implement data classification
import re

def redact_sensitive_data(text: str) -> str:
    """Redact PII from logs and prompts"""
    # Email addresses
    text = re.sub(r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b',
                  '[EMAIL_REDACTED]', text)

    # Phone numbers
    text = re.sub(r'\b\d{3}[-.]?\d{3}[-.]?\d{4}\b',
                  '[PHONE_REDACTED]', text)

    # Credit cards
    text = re.sub(r'\b\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b',
                  '[CARD_REDACTED]', text)

    return text

# Use before logging
logger.info(f"User query: {redact_sensitive_data(user_query)}")
Risk: Unable to detect or investigate security incidentsPrevention:
import logging
from datetime import datetime

# Configure security logging
security_logger = logging.getLogger('security')
handler = logging.FileHandler('security.log')
handler.setFormatter(logging.Formatter(
    '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
))
security_logger.addHandler(handler)
security_logger.setLevel(logging.INFO)

# Log security events
def log_api_call(user_id: str, action: str, success: bool):
    security_logger.info({
        'timestamp': datetime.utcnow().isoformat(),
        'user_id': user_id,
        'action': action,
        'success': success,
        'ip': request.remote_addr  # If using Flask/Django
    })

# Usage
log_api_call(
    user_id="user_123",
    action="get_prompt",
    success=True
)
Risk: Unauthorized access to your application’s AI featuresPrevention: Always validate users before allowing prompt access:
from functools import wraps
from flask import request, jsonify

def require_auth(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        # Verify user authentication
        auth_header = request.headers.get('Authorization')

        if not auth_header or not verify_token(auth_header):
            return jsonify({'error': 'Unauthorized'}), 401

        return f(*args, **kwargs)
    return decorated_function

@app.route('/api/ask')
@require_auth  # Always protect AI endpoints
def ask_question():
    # Your prompt logic
    pass
Risk: API abuse or DoS attacksPrevention: Implement rate limiting on your endpoints:
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address

limiter = Limiter(
    app,
    key_func=get_remote_address,
    default_limits=["100 per hour"]
)

@app.route('/api/ask')
@limiter.limit("10 per minute")  # Limit AI endpoint usage
def ask_question():
    # Your prompt logic
    pass

Compliance

Data Privacy Regulations

General Data Protection Regulation (EU)Key requirements:
  • Data minimization - collect only necessary data
  • Right to deletion - allow users to delete their data
  • Data portability - export user data on request
  • Consent management - explicit user consent required
Implementation:
def handle_gdpr_deletion(user_id: str):
    """Delete all user data per GDPR right to deletion"""
    # Delete user prompts
    # Delete user interactions
    # Remove user from workspace memberships
    # Clear cached data
    pass

def export_user_data(user_id: str):
    """Export user data per GDPR data portability"""
    # Collect all user data
    # Format as JSON or CSV
    # Return to user
    pass

Security Checklist

  • API keys stored in environment variables, never in code
  • .env files added to .gitignore
  • No hardcoded secrets in configuration files
  • Sensitive data redacted in logs
  • Code review process includes security checks
  • Production API keys different from dev/staging
  • Keys stored in secrets manager (AWS/GCP/Azure)
  • Regular key rotation schedule (every 90 days)
  • Service accounts used instead of personal accounts
  • HTTPS enforced for all API calls
  • Rate limiting implemented
  • Authentication required for AI endpoints
  • API usage monitored for anomalies
  • Security events logged
  • Alerts configured for suspicious activity
  • Regular access reviews conducted
  • Unused API keys deleted
  • Audit trail maintained for compliance
  • Incident response plan documented
  • Emergency key rotation procedure tested
  • Security contact information current
  • Breach notification process defined
  • Regular security training for team

Incident Response

If an API Key is Compromised

1

Immediate Actions (0-15 minutes)

  1. Delete compromised key immediately
  2. Create new API key
  3. Deploy new key to production
  4. Alert security team
2

Investigation (15-60 minutes)

  1. Review audit logs for unauthorized access
  2. Identify what data was accessed
  3. Determine scope of breach
  4. Document timeline of events
3

Remediation (1-24 hours)

  1. Rotate all related credentials
  2. Update security procedures
  3. Implement additional monitoring
  4. Review and update access controls
4

Post-Incident (1-7 days)

  1. Conduct post-mortem analysis
  2. Update documentation
  3. Train team on lessons learned
  4. Implement preventive measures
  5. Notify affected parties if required

Next Steps