|
| 1 | +# Authentication |
| 2 | + |
| 3 | +Storm API uses API key authentication passed in request headers. |
| 4 | + |
| 5 | +## Authentication Method |
| 6 | + |
| 7 | +### Header-Based Authentication |
| 8 | + |
| 9 | +Include your API key in the `storm-api-key` header: |
| 10 | + |
| 11 | +```python |
| 12 | +headers = { |
| 13 | + "storm-api-key": "your-api-key-here" |
| 14 | +} |
| 15 | +``` |
| 16 | + |
| 17 | +## Complete Example |
| 18 | + |
| 19 | +```python |
| 20 | +import requests |
| 21 | + |
| 22 | +class StormClient: |
| 23 | + def __init__(self, api_key, base_url="https://https://live-stargate.sionic.im"): |
| 24 | + self.api_key = api_key |
| 25 | + self.base_url = base_url |
| 26 | + self.headers = {"storm-api-key": api_key} |
| 27 | + |
| 28 | + def get(self, endpoint, params=None): |
| 29 | + """GET request with authentication.""" |
| 30 | + url = f"{self.base_url}{endpoint}" |
| 31 | + response = requests.get(url, headers=self.headers, params=params) |
| 32 | + response.raise_for_status() |
| 33 | + return response.json() |
| 34 | + |
| 35 | + def post(self, endpoint, json=None, data=None, files=None): |
| 36 | + """POST request with authentication.""" |
| 37 | + url = f"{self.base_url}{endpoint}" |
| 38 | + response = requests.post( |
| 39 | + url, |
| 40 | + headers=self.headers, |
| 41 | + json=json, |
| 42 | + data=data, |
| 43 | + files=files |
| 44 | + ) |
| 45 | + response.raise_for_status() |
| 46 | + return response.json() |
| 47 | + |
| 48 | +# Initialize client |
| 49 | +client = StormClient(api_key="your-api-key") |
| 50 | + |
| 51 | +# Test authentication |
| 52 | +agents = client.get("/api/v2/agents") |
| 53 | +print(f"Authentication successful! Found {len(agents['data']['data'])} agents.") |
| 54 | +``` |
| 55 | + |
| 56 | +## Security Best Practices |
| 57 | + |
| 58 | +### 1. Never Hard-code API Keys |
| 59 | + |
| 60 | +❌ **Bad:** |
| 61 | +```python |
| 62 | +API_KEY = "sk_live_abcd1234" # Never do this! |
| 63 | +``` |
| 64 | + |
| 65 | +✅ **Good:** |
| 66 | +```python |
| 67 | +import os |
| 68 | +API_KEY = os.environ.get("STORM_API_KEY") |
| 69 | +``` |
| 70 | + |
| 71 | +### 2. Use Environment Variables |
| 72 | + |
| 73 | +```bash |
| 74 | +# .bashrc or .zshrc |
| 75 | +export STORM_API_KEY="your-api-key-here" |
| 76 | +``` |
| 77 | + |
| 78 | +### 3. Secure Storage |
| 79 | + |
| 80 | +For production applications: |
| 81 | + |
| 82 | +```python |
| 83 | +import keyring |
| 84 | + |
| 85 | +# Store API key securely |
| 86 | +keyring.set_password("storm-api", "api-key", "your-key") |
| 87 | + |
| 88 | +# Retrieve API key |
| 89 | +api_key = keyring.get_password("storm-api", "api-key") |
| 90 | +``` |
| 91 | + |
| 92 | +## Error Handling |
| 93 | + |
| 94 | +Handle authentication errors gracefully: |
| 95 | + |
| 96 | +```python |
| 97 | +def make_authenticated_request(endpoint, api_key): |
| 98 | + """Make request with proper error handling.""" |
| 99 | + try: |
| 100 | + response = requests.get( |
| 101 | + f"https://https://live-stargate.sionic.im{endpoint}", |
| 102 | + headers={"storm-api-key": api_key} |
| 103 | + ) |
| 104 | + |
| 105 | + if response.status_code == 401: |
| 106 | + print("❌ Authentication failed. Check your API key.") |
| 107 | + return None |
| 108 | + elif response.status_code == 403: |
| 109 | + print("❌ Access forbidden. Check your permissions.") |
| 110 | + return None |
| 111 | + |
| 112 | + response.raise_for_status() |
| 113 | + return response.json() |
| 114 | + |
| 115 | + except requests.exceptions.RequestException as e: |
| 116 | + print(f"❌ Request failed: {e}") |
| 117 | + return None |
| 118 | +``` |
| 119 | + |
| 120 | +## Rate Limiting |
| 121 | + |
| 122 | +Storm API implements rate limiting. Handle it properly: |
| 123 | + |
| 124 | +```python |
| 125 | +import time |
| 126 | + |
| 127 | +def request_with_retry(client, method, endpoint, max_retries=3, **kwargs): |
| 128 | + """Make request with automatic retry on rate limit.""" |
| 129 | + for attempt in range(max_retries): |
| 130 | + try: |
| 131 | + if method == "GET": |
| 132 | + return client.get(endpoint, **kwargs) |
| 133 | + elif method == "POST": |
| 134 | + return client.post(endpoint, **kwargs) |
| 135 | + except requests.exceptions.HTTPError as e: |
| 136 | + if e.response.status_code == 429: # Rate limited |
| 137 | + wait_time = int(e.response.headers.get("Retry-After", 60)) |
| 138 | + print(f"Rate limited. Waiting {wait_time} seconds...") |
| 139 | + time.sleep(wait_time) |
| 140 | + else: |
| 141 | + raise |
| 142 | + |
| 143 | + raise Exception("Max retries exceeded") |
| 144 | +``` |
| 145 | + |
| 146 | +## Testing Authentication |
| 147 | + |
| 148 | +Quick test script: |
| 149 | + |
| 150 | +```python |
| 151 | +#!/usr/bin/env python3 |
| 152 | +"""Test Storm API authentication.""" |
| 153 | + |
| 154 | +import sys |
| 155 | +import requests |
| 156 | +import os |
| 157 | + |
| 158 | +def test_auth(api_key=None): |
| 159 | + """Test API authentication.""" |
| 160 | + api_key = api_key or os.environ.get("STORM_API_KEY") |
| 161 | + |
| 162 | + if not api_key: |
| 163 | + print("❌ No API key provided") |
| 164 | + print("Set STORM_API_KEY environment variable or pass as argument") |
| 165 | + return False |
| 166 | + |
| 167 | + headers = {"storm-api-key": api_key} |
| 168 | + |
| 169 | + try: |
| 170 | + response = requests.get( |
| 171 | + "https://https://live-stargate.sionic.im/api/v2/agents", |
| 172 | + headers=headers, |
| 173 | + params={"page": 1, "size": 1} |
| 174 | + ) |
| 175 | + |
| 176 | + if response.status_code == 200: |
| 177 | + print("✅ Authentication successful!") |
| 178 | + return True |
| 179 | + else: |
| 180 | + print(f"❌ Authentication failed: {response.status_code}") |
| 181 | + print(response.text) |
| 182 | + return False |
| 183 | + |
| 184 | + except Exception as e: |
| 185 | + print(f"❌ Error: {e}") |
| 186 | + return False |
| 187 | + |
| 188 | +if __name__ == "__main__": |
| 189 | + api_key = sys.argv[1] if len(sys.argv) > 1 else None |
| 190 | + test_auth(api_key) |
| 191 | +``` |
| 192 | + |
| 193 | +## Next Steps |
| 194 | + |
| 195 | +- [Your First API Call](./03-first-api-call.ipynb) - Make your first Storm API request |
0 commit comments