Chapter 3: Access Tokens
Overview
Access tokens (API keys) are the primary authentication method for programmatic access to the Polysystems Backend API. This chapter provides comprehensive guidance on generating, managing, securing, and optimizing your access tokens.
What are Access Tokens?
Access tokens are long-lived credentials that authenticate API requests without requiring users to share their account passwords. Each token:
- Is tied to a specific user account
- Can be individually revoked or deleted
- Has optional expiration dates
- Can have spending limits configured
- Tracks usage statistics independently
- Works across all API endpoints
Benefits of Access Tokens
- Security: No password exposure in application code
- Granular Control: Different tokens for different applications
- Easy Revocation: Revoke compromised tokens without changing passwords
- Usage Tracking: Monitor which tokens are consuming resources
- Spending Limits: Set per-token budgets to control costs
- Long-Lived: No need for frequent re-authentication
Token Format
Access tokens follow a structured format:
ps_{environment}_{random_string}
Components:
├─ ps_ : Polysystems prefix
├─ {environment}: live/test environment indicator
└─ {random} : 32+ character cryptographic random stringExamples
Production Token:
ps_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0
Development Token:
ps_test_x9y8z7w6v5u4t3s2r1q0p9o8n7m6l5k4j3h2Generating Access Tokens
Basic Token Generation
Create a new access token using your JWT authentication:
curl -X POST https://api.polysystems.ai/api/keys \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "My Application Token"
}'Response:
{
"id": "key-123e4567-e89b-12d3-a456-426614174000",
"name": "My Application Token",
"key_value": "ps_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
"is_active": true,
"created_at": "2024-01-15T12:00:00Z",
"expires_at": null
}⚠️ Critical: The key_value is only shown once during creation. Save it immediately in a secure location!
Token with Expiration
Create a token that automatically expires:
curl -X POST https://api.polysystems.ai/api/keys \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Temporary Access Token",
"expires_at": "2024-12-31T23:59:59Z"
}'Use Cases for Expiring Tokens:
- Short-term partner integrations
- Time-limited demos or trials
- Temporary contractor access
- Testing and development
- Security compliance requirements
Listing Access Tokens
View all access tokens associated with your account:
curl -X GET https://api.polysystems.ai/api/keys \
-H "Authorization: Bearer YOUR_JWT_TOKEN"Response:
[
{
"id": "key-123e4567-e89b-12d3-a456-426614174000",
"name": "Production API Key",
"key_value_preview": "ps_live_a1b2...o5p6",
"is_active": true,
"last_used_at": "2024-01-15T14:30:00Z",
"created_at": "2024-01-01T10:00:00Z",
"expires_at": null
},
{
"id": "key-456e7890-e12b-34d5-a678-901234567890",
"name": "Development Key",
"key_value_preview": "ps_live_x9y8...k4j3",
"is_active": true,
"last_used_at": "2024-01-14T09:15:00Z",
"created_at": "2024-01-05T15:30:00Z",
"expires_at": "2024-06-30T23:59:59Z"
},
{
"id": "key-789a0123-b45c-67d8-e901-234567890123",
"name": "Old Testing Key",
"key_value_preview": "ps_live_m3n4...b1c2",
"is_active": false,
"last_used_at": "2023-12-20T11:45:00Z",
"created_at": "2023-11-10T08:00:00Z",
"expires_at": null
}
]Understanding the Response
- id: Unique identifier for the token (used for management operations)
- name: Human-readable name you assigned
- key_value_preview: Partial token value (first 12 and last 4 characters)
- is_active: Whether the token is currently valid
- last_used_at: Timestamp of most recent API call
- created_at: When the token was generated
- expires_at: Expiration date (null = never expires)
Revoking Access Tokens
Revoke a token to immediately invalidate it without deleting the record:
curl -X POST https://api.polysystems.ai/api/keys/{key_id}/revoke \
-H "Authorization: Bearer YOUR_JWT_TOKEN"Response:
{
"success": true,
"message": "Access key revoked successfully"
}When to Revoke Tokens
- Token may have been compromised
- Employee/contractor access removal
- Application decommissioned
- Suspicious activity detected
- Regular security audits
- Rotation before deletion
Note: Revoked tokens can be viewed in your token list but cannot be reactivated. Generate a new token instead.
Deleting Access Tokens
Permanently remove a token from your account:
curl -X DELETE https://api.polysystems.ai/api/keys/{key_id} \
-H "Authorization: Bearer YOUR_JWT_TOKEN"Response:
{
"success": true,
"message": "Access key deleted successfully"
}Revoke vs Delete
| Action | Result | History Preserved | Reversible |
|---|---|---|---|
| Revoke | Token invalidated | Yes | No |
| Delete | Token removed | No | No |
Best Practice: Revoke tokens first, verify no issues, then delete after a grace period.
Using Access Tokens
Method 1: X-API-Key Header (Recommended)
curl -X POST https://api.polysystems.ai/api/hub/agents/chat \
-H "X-API-Key: ps_live_your_token_here" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{"role": "user", "content": "Hello, world!"}
]
}'Advantages:
- Clear separation from OAuth/JWT Bearer tokens
- Industry standard for API keys
- Easy to identify in logs and monitoring
Method 2: Authorization Bearer Header
curl -X POST https://api.polysystems.ai/api/hub/agents/chat \
-H "Authorization: Bearer ps_live_your_token_here" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{"role": "user", "content": "Hello, world!"}
]
}'Advantages:
- Compatible with OAuth 2.0 client libraries
- Works with OpenAI-compatible clients (v1 endpoints)
Token Naming Strategy
Use descriptive names to easily identify tokens:
Recommended Naming Patterns
# Environment-based
"Production Server"
"Staging Environment"
"Development Local"
# Application-based
"Mobile App - iOS"
"Web Dashboard"
"Analytics Service"
# Purpose-based
"Data Ingestion Pipeline"
"Webhook Handler"
"Scheduled Reports"
# Team-based
"Engineering Team"
"Data Science Team"
"QA Automation"
# Combined approach (recommended)
"Production - Web Dashboard - v2"
"Staging - Mobile App - iOS"
"Dev - John's Local Environment"Naming Best Practices
- Include environment (prod/staging/dev)
- Include application or service name
- Add version numbers if applicable
- Include team or owner if shared
- Keep names concise but descriptive
- Avoid sensitive information in names
Token Lifecycle Management
Complete Token Lifecycle
┌─────────────┐
│ CREATE │ ← Generate new token
└──────┬──────┘
│
▼
┌─────────────┐
│ ACTIVE │ ← Token in use
└──────┬──────┘
│
├──────────────┐
│ │
▼ ▼
┌─────────────┐ ┌──────────┐
│ EXPIRED │ │ REVOKED │ ← Manually deactivated
└──────┬──────┘ └────┬─────┘
│ │
└──────┬───────┘
│
▼
┌─────────────┐
│ DELETED │ ← Permanently removed
└─────────────┘Rotation Strategy
Implement regular token rotation for enhanced security:
#!/bin/bash
# Token rotation script
# 1. Generate new token
NEW_TOKEN=$(curl -s -X POST https://api.polysystems.ai/api/keys \
-H "Authorization: Bearer $JWT_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"name\": \"Production - Rotated $(date +%Y-%m-%d)\"}" \
| jq -r '.key_value')
# 2. Update application configuration
echo "PS_API_KEY=$NEW_TOKEN" > /secure/location/.env
# 3. Restart application services
systemctl restart myapp
# 4. Wait for verification period (24 hours)
sleep 86400
# 5. Revoke old token
curl -X POST https://api.polysystems.ai/api/keys/$OLD_KEY_ID/revoke \
-H "Authorization: Bearer $JWT_TOKEN"
# 6. Delete old token after grace period
sleep 86400
curl -X DELETE https://api.polysystems.ai/api/keys/$OLD_KEY_ID \
-H "Authorization: Bearer $JWT_TOKEN"Recommended Rotation Schedule
| Environment | Rotation Frequency | Reason |
|---|---|---|
| Production | Every 90 days | Balance security and stability |
| Staging | Every 180 days | Less critical but still important |
| Development | As needed | Frequently recreated anyway |
| Partner Access | Every 30-60 days | Third-party security |
Token Security Best Practices
1. Secure Storage
Environment Variables (Recommended)
# .env file (add to .gitignore!)
PS_API_KEY=ps_live_your_token_here
PS_API_URL=https://api.polysystems.aiSecrets Management Systems
# AWS Secrets Manager
aws secretsmanager get-secret-value \
--secret-id prod/polysystems/api-key \
--query SecretString \
--output text
# HashiCorp Vault
vault kv get -field=api_key secret/polysystems
# Kubernetes Secrets
kubectl get secret polysystems-api-key -o jsonpath='{.data.api-key}' | base64 -d2. Never Commit Tokens
Bad Examples (Don’t Do This!)
# ❌ Hardcoded in source code
API_KEY = "ps_live_a1b2c3d4e5f6g7h8i9j0k1l2"
# ❌ In configuration files
config = {
"api_key": "ps_live_a1b2c3d4e5f6g7h8i9j0k1l2"
}Good Examples
# ✅ From environment variables
import os
API_KEY = os.getenv('PS_API_KEY')
# ✅ From secrets manager
from aws_secretsmanager import get_secret
API_KEY = get_secret('prod/polysystems/api-key')3. Limit Token Scope
Create separate tokens for different purposes:
# Mobile app token (limited)
curl -X POST https://api.polysystems.ai/api/keys \
-H "Authorization: Bearer $JWT_TOKEN" \
-d '{"name": "Mobile App Token"}'
# Then set spending limits
curl -X PUT https://api.polysystems.ai/api/keys/{key_id}/limits \
-H "Authorization: Bearer $JWT_TOKEN" \
-d '{
"daily_limit": 5.00,
"monthly_limit": 100.00,
"per_request_limit": 0.50
}'4. Monitor Token Usage
Regularly review token activity:
# List all tokens with usage stats
curl -X GET https://api.polysystems.ai/api/keys \
-H "Authorization: Bearer $JWT_TOKEN" \
| jq '.[] | {name, last_used_at, is_active}'Red Flags to Watch For:
- Tokens not used in 90+ days
- Unexpected geographic access patterns
- Unusual request volumes
- Failed authentication attempts
- Tokens from former employees
5. Incident Response Plan
If a token is compromised:
# IMMEDIATE: Revoke the token
curl -X POST https://api.polysystems.ai/api/keys/{key_id}/revoke \
-H "Authorization: Bearer $JWT_TOKEN"
# Check recent usage
curl -X GET https://api.polysystems.ai/api/monitoring/usage?key_id={key_id} \
-H "Authorization: Bearer $JWT_TOKEN"
# Review transactions
curl -X GET https://api.polysystems.ai/api/payments/transactions?limit=100 \
-H "Authorization: Bearer $JWT_TOKEN"
# Generate new token
curl -X POST https://api.polysystems.ai/api/keys \
-H "Authorization: Bearer $JWT_TOKEN" \
-d '{"name": "Replacement Token - Post Incident"}'Access Token Limits and Quotas
Default Limits
- Maximum tokens per account: 50
- Token name length: 1-100 characters
- Token expiration: Min 1 hour, Max 10 years (or never)
Request Limits
All tokens are subject to:
- Rate limiting (varies by endpoint)
- Spending limits (if configured)
- Account balance (must have sufficient credits)
Advanced Token Management
Programmatic Token Management
Automate token lifecycle management:
import os
import requests
from datetime import datetime, timedelta
class TokenManager:
def __init__(self, jwt_token):
self.jwt_token = jwt_token
self.base_url = "https://api.polysystems.ai"
self.headers = {
"Authorization": f"Bearer {jwt_token}",
"Content-Type": "application/json"
}
def create_token(self, name, expires_days=None):
"""Create a new access token"""
data = {"name": name}
if expires_days:
expires_at = datetime.utcnow() + timedelta(days=expires_days)
data["expires_at"] = expires_at.isoformat() + "Z"
response = requests.post(
f"{self.base_url}/api/keys",
headers=self.headers,
json=data
)
return response.json()
def list_tokens(self):
"""List all access tokens"""
response = requests.get(
f"{self.base_url}/api/keys",
headers=self.headers
)
return response.json()
def revoke_token(self, key_id):
"""Revoke an access token"""
response = requests.post(
f"{self.base_url}/api/keys/{key_id}/revoke",
headers=self.headers
)
return response.json()
def delete_old_tokens(self, days_inactive=90):
"""Delete tokens not used in X days"""
tokens = self.list_tokens()
cutoff = datetime.utcnow() - timedelta(days=days_inactive)
for token in tokens:
if token['last_used_at']:
last_used = datetime.fromisoformat(
token['last_used_at'].replace('Z', '+00:00')
)
if last_used < cutoff:
print(f"Deleting inactive token: {token['name']}")
self.revoke_token(token['id'])
# Usage
manager = TokenManager(os.getenv('PS_JWT_TOKEN'))
new_token = manager.create_token("Automated Production Token", expires_days=90)
print(f"New token: {new_token['key_value']}")Token Audit Script
#!/bin/bash
# audit_tokens.sh - Review and report on all access tokens
JWT_TOKEN=$PS_JWT_TOKEN
API_URL="https://api.polysystems.ai"
echo "=== Access Token Audit Report ==="
echo "Generated: $(date)"
echo ""
# Get all tokens
TOKENS=$(curl -s -X GET "$API_URL/api/keys" \
-H "Authorization: Bearer $JWT_TOKEN")
# Count total tokens
TOTAL=$(echo "$TOKENS" | jq 'length')
ACTIVE=$(echo "$TOKENS" | jq '[.[] | select(.is_active == true)] | length')
INACTIVE=$(echo "$TOKENS" | jq '[.[] | select(.is_active == false)] | length')
echo "Total Tokens: $TOTAL"
echo "Active: $ACTIVE"
echo "Inactive: $INACTIVE"
echo ""
# Find tokens not used in 90 days
echo "=== Tokens Not Used in 90 Days ==="
CUTOFF=$(date -u -d '90 days ago' +%Y-%m-%dT%H:%M:%SZ)
echo "$TOKENS" | jq -r --arg cutoff "$CUTOFF" \
'.[] | select(.last_used_at < $cutoff or .last_used_at == null) |
"\(.name) (Last used: \(.last_used_at // "Never"))"'
echo ""
# Find expiring tokens
echo "=== Tokens Expiring Soon (30 days) ==="
EXPIRE_SOON=$(date -u -d '30 days' +%Y-%m-%dT%H:%M:%SZ)
echo "$TOKENS" | jq -r --arg expire "$EXPIRE_SOON" \
'.[] | select(.expires_at != null and .expires_at < $expire) |
"\(.name) (Expires: \(.expires_at))"'Troubleshooting
Token Not Working
Problem: API returns “Invalid API key”
Solutions:
- Verify token is active:
curl -X GET https://api.polysystems.ai/api/keys -H "Authorization: Bearer $JWT" - Check for typos in token value
- Ensure proper header format:
X-API-Key: ps_live_... - Verify token hasn’t expired
- Check if token was revoked
Token Expired
Problem: API returns “API key expired”
Solution:
# Generate new token
curl -X POST https://api.polysystems.ai/api/keys \
-H "Authorization: Bearer $JWT_TOKEN" \
-d '{"name": "Replacement Token"}'
# Update application configuration
# Revoke old tokenCan’t Create More Tokens
Problem: “Maximum tokens limit reached”
Solution:
# List all tokens
curl -X GET https://api.polysystems.ai/api/keys \
-H "Authorization: Bearer $JWT_TOKEN"
# Delete unused tokens
curl -X DELETE https://api.polysystems.ai/api/keys/{unused_key_id} \
-H "Authorization: Bearer $JWT_TOKEN"Token Lost or Forgotten
Problem: Can’t find saved token value
Solution:
- Token values cannot be retrieved after creation
- Revoke the old token and generate a new one
- Update your application with the new token
- Implement better secrets management going forward
Summary
In this chapter, you learned:
- ✅ How to generate access tokens with and without expiration
- ✅ Token format and structure
- ✅ Listing, revoking, and deleting tokens
- ✅ Best practices for token naming and organization
- ✅ Security best practices for token storage and usage
- ✅ Token lifecycle management and rotation strategies
- ✅ Programmatic token management
- ✅ Troubleshooting common token issues
Next Steps
- Chapter 4: API Routing - Explore available endpoints
- Chapter 6: Spending Limits - Configure per-token spending limits
- Chapter 5: Payment & Credits - Manage your account balance