sequenceDiagram
participant User
participant ThirdParty as Third-Party App
participant Kai as Kai Authorization Server
participant API as Kai API
User->>ThirdParty: Clicks "Connect with Kai"
ThirdParty->>Kai: Redirects to authorization URL
Kai->>User: Shows consent screen
User->>Kai: Grants permission
Kai->>ThirdParty: Redirects with authorization code
ThirdParty->>Kai: Exchanges code for access token
Kai->>ThirdParty: Returns access token
ThirdParty->>API: Makes API request with token
API->>ThirdParty: Returns data
Authentication Guide
Secure authentication and API key management
Overview
Kai uses API key authentication for all API requests. This guide covers how to obtain, manage, and securely use API keys to authenticate your applications and integrations.
API keys provide full access to your Kai account. Treat them like passwords and never expose them in client-side code or public repositories.
Authentication Methods
Kai supports multiple authentication methods depending on your use case:
| Method | Use Case | Security Level |
|---|---|---|
| API Keys | Server-to-server, scripts, CI/CD | High |
| OAuth 2.0 | Third-party integrations, user delegation | Very High |
| LTI 1.3 | LMS integrations (Canvas, Blackboard, etc.) | Very High |
| Session Tokens | Web dashboard, temporary access | Medium |
API Keys
Obtaining an API Key
- Log in to your Kai dashboard: dashboard.kaitheai.com
- Navigate to Settings → API Keys
- Click “Generate New API Key”
- Configure key settings:
- Name: Descriptive name (e.g., “Production Server”, “Development”)
- Permissions: Select required scopes
- Expiration: Set expiration date (or never)
- Copy the key: It will only be shown once
API keys are only displayed once during creation. Store it securely immediately. If lost, you must generate a new key.
API Key Format
Kai API keys follow this format:
kai_<environment>_<32-character-random-string>
Examples:
kai_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6 # Production
kai_test_x9y8z7w6v5u4t3s2r1q0p9o8n7m6l5k4 # Test/sandbox
Key Prefixes: - kai_live_: Production environment - kai_test_: Test/sandbox environment
Using API Keys
Include your API key in the Authorization header of every API request:
HTTP Header:
Authorization: Bearer kai_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
Example Request:
curl https://chi2api.com/v1/courses \
-H "Authorization: Bearer kai_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"import requests
API_KEY = "kai_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
headers = {
"Authorization": f"Bearer {API_KEY}"
}
response = requests.get(
"https://chi2api.com/v1/courses",
headers=headers
)const API_KEY = "kai_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6";
const response = await fetch("https://chi2api.com/v1/courses", {
headers: {
"Authorization": `Bearer ${API_KEY}`
}
});import java.net.http.*;
String API_KEY = "kai_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6";
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://chi2api.com/v1/courses"))
.header("Authorization", "Bearer " + API_KEY)
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());require 'net/http'
require 'uri'
api_key = "kai_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
uri = URI.parse("https://chi2api.com/v1/courses")
request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer #{api_key}"
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
endAPI Key Permissions (Scopes)
Control what each API key can access using scopes:
| Scope | Description | Risk Level |
|---|---|---|
courses:read |
View course information | Low |
courses:write |
Create/update courses | Medium |
students:read |
View student data | Medium |
students:write |
Modify student records | High |
grading:read |
View grades | Medium |
grading:write |
Submit grades | High |
analytics:read |
Access analytics | Low |
feedback:read |
View feedback responses | Medium |
feedback:write |
Request feedback | Low |
admin:* |
Full administrative access | Very High |
Best Practice: Principle of Least Privilege
Only grant the minimum scopes needed for each key:
✅ Good: Integration key with only required scopes
Scopes: courses:read, grading:write
❌ Bad: Everything gets admin:*
Risk: Compromised key = full account access
Managing API Keys
List All Keys
View all active API keys:
GET /api-keys
Response:
{
"keys": [
{
"key_id": "key_abc123",
"name": "Production Server",
"prefix": "kai_live_a1b2...",
"scopes": ["courses:read", "grading:write"],
"created": "2024-01-01T00:00:00Z",
"last_used": "2024-01-15T14:30:00Z",
"expires": null
}
]
}Rotate API Keys
When to rotate: - ⏰ Periodically (every 90 days recommended) - 🚨 After suspected compromise - 👤 When team member leaves - 🔄 After major system changes
Rotation process:
- Generate new key with same permissions
- Update all integrations to use new key
- Test thoroughly in staging/development
- Deploy to production
- Revoke old key after confirming new key works
Create the new key before revoking the old one. Both keys work simultaneously during transition period.
Revoke API Keys
Immediately disable a compromised key:
DELETE /api-keys/{key_id}
Dashboard: 1. Settings → API Keys 2. Find the key to revoke 3. Click “Revoke” 4. Confirm action
Revoking a key takes effect immediately. Any requests using that key will fail.
OAuth 2.0
For third-party integrations or user-delegated access, use OAuth 2.0.
OAuth Flow
Registering an OAuth Application
- Dashboard → Settings → OAuth Applications
- Click “New Application”
- Configure settings:
- Application Name: Your app’s name
- Redirect URIs: Where to send users after authorization
- Scopes: Permissions your app needs
- Save to receive Client ID and Client Secret
Token Exchange
Exchange authorization code for access token:
POST https://chi2api.com/oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&
code=AUTHORIZATION_CODE&
client_id=YOUR_CLIENT_ID&
client_secret=YOUR_CLIENT_SECRET&
redirect_uri=https://your-app.com/callback
Response:
{
"access_token": "kai_oauth_abc123...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "kai_refresh_xyz789...",
"scope": "courses:read grading:write"
}Using Access Tokens
Use access tokens the same way as API keys:
Authorization: Bearer kai_oauth_abc123...
Refreshing Tokens
Access tokens expire after 1 hour. Use refresh token to get new access token:
POST https://chi2api.com/oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token&
refresh_token=kai_refresh_xyz789...&
client_id=YOUR_CLIENT_ID&
client_secret=YOUR_CLIENT_SECRET
LTI 1.3 Authentication
For LMS integrations, Kai supports LTI 1.3 (Learning Tools Interoperability).
LTI Configuration
Required Information:
| Field | Value |
|---|---|
| OpenID Connect Login URL | https://chi2api.com/lti/login |
| Target Link URI | https://chi2api.com/lti/launch |
| Public JWK URL | https://chi2api.com/.well-known/jwks.json |
| Redirect URIs | https://chi2api.com/lti/callback |
Required Claims:
sub- User identifierhttps://purl.imsglobal.org/spec/lti/claim/context- Course contexthttps://purl.imsglobal.org/spec/lti/claim/roles- User roles
Canvas LTI Setup
See Installation Guide - Canvas Integration for detailed instructions.
Blackboard LTI Setup
See Installation Guide - Blackboard Integration for detailed instructions.
Security Best Practices
Storing API Keys
Never Do This
# ❌ Hardcoded in source code
API_KEY = "kai_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
# ❌ Committed to Git
# config.py
API_KEY = "kai_live_..."
# ❌ In client-side JavaScript
const API_KEY = "kai_live_...";# ✅ Environment variables
import os
API_KEY = os.environ.get("KAI_API_KEY")
# ✅ Secret management service
from secret_manager import get_secret
API_KEY = get_secret("kai-api-key")
# ✅ Configuration files (gitignored)
import configparser
config = configparser.ConfigParser()
config.read("config.ini") # .gitignore includes config.ini
API_KEY = config["kai"]["api_key"]Environment Variables
Development:
# .env file (add to .gitignore)
KAI_API_KEY=kai_test_x9y8z7w6v5u4t3s2r1q0p9o8n7m6l5k4Production:
# Set in deployment environment
export KAI_API_KEY=kai_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6Docker:
# docker-compose.yml
services:
app:
environment:
- KAI_API_KEY=${KAI_API_KEY}Secret Management Services
AWS Secrets Manager:
import boto3
import json
client = boto3.client('secretsmanager')
response = client.get_secret_value(SecretId='kai-api-key')
API_KEY = json.loads(response['SecretString'])['api_key']HashiCorp Vault:
import hvac
client = hvac.Client(url='https://vault.example.com')
client.auth.approle.login(role_id='...', secret_id='...')
API_KEY = client.secrets.kv.v2.read_secret_version(
path='kai-api-key'
)['data']['data']['key']Google Secret Manager:
from google.cloud import secretmanager
client = secretmanager.SecretManagerServiceClient()
name = "projects/PROJECT_ID/secrets/kai-api-key/versions/latest"
response = client.access_secret_version(request={"name": name})
API_KEY = response.payload.data.decode("UTF-8")Network Security
Use HTTPS Only:
# ✅ Always HTTPS
response = requests.get("https://chi2api.com/v1/courses")
# ❌ Never HTTP
response = requests.get("http://chi2api.com/v1/courses")Verify SSL Certificates:
# ✅ Verify certificates (default)
response = requests.get(url, verify=True)
# ❌ Don't disable verification
response = requests.get(url, verify=False) # Dangerous!IP Allowlisting
Restrict API key usage to specific IP addresses:
Dashboard Configuration: 1. Settings → API Keys → [Your Key] → IP Restrictions 2. Add allowed IP addresses or CIDR ranges 3. Save changes
Example:
Allowed IPs:
- 203.0.113.0/24 (Office network)
- 198.51.100.42 (Production server)
Monitoring and Alerts
Enable alerts for: - Unusual API usage patterns - Failed authentication attempts - API key used from new IP address - Rate limit approaching
Configure in: Dashboard → Settings → Security → Alerts
Testing Authentication
Verify API Key
Test your API key is working:
curl https://chi2api.com/v1/auth/verify \
-H "Authorization: Bearer YOUR_API_KEY"Success Response:
{
"valid": true,
"key_id": "key_abc123",
"scopes": ["courses:read", "grading:write"],
"expires": null,
"rate_limit": {
"limit": 60,
"remaining": 58,
"reset": 1642262400
}
}Failure Response:
{
"error": {
"code": "invalid_api_key",
"message": "The provided API key is invalid or has been revoked"
}
}Test OAuth Flow
Use Kai’s OAuth testing tool:
- Dashboard → Settings → OAuth Applications → [Your App] → Test
- Click “Start OAuth Flow”
- Complete authorization
- Verify token received
Troubleshooting
Common Authentication Errors
“Invalid API Key”
Possible causes: - Key was revoked - Key contains typos or extra spaces - Using test key in production (or vice versa)
Solution: - Verify key in dashboard - Regenerate if needed - Check environment variables
“Insufficient Permissions”
Possible causes: - API key lacks required scope - Trying to access resource outside permissions
Solution: - Check required scopes in Endpoints Reference - Generate new key with appropriate scopes
“Rate Limit Exceeded”
Possible causes: - Too many requests in short period - Multiple services sharing one key
Solution: - Implement exponential backoff - Create separate keys for different services - Upgrade plan for higher limits
Getting Help
- 📧 Security Issues: security@chi2labs.com
- 💬 Authentication Support: support@chi2labs.com
- 📚 Documentation: API Reference, Endpoints
For integration examples and workflows, see the Integration Guide.