Authentication
The License Server API uses Bearer token authentication for administrative endpoints, while public endpoints require no authentication.
Authentication Levels
Public Endpoints
Most endpoints are public and require no authentication:
- License verification (
/verify-license) - License activation (
/activate-license) - Usage tracking (
/track-usage) - Export license data (
/export-license)
Admin Endpoints (Authentication Required)
Administrative operations require a Bearer token:
- Issue licenses (
/issue-license) - Revoke licenses (
/revoke-license) - Delete licenses (
/delete-license) - View admin statistics (
/admin/stats)
Setting Up Authentication
1. Get Your Admin API Key
The admin API key is configured via environment variable:
bash
export ADMIN_API_KEY="your-secure-admin-api-key-here"Security Best Practices
- Use a strong, randomly generated key (minimum 32 characters)
- Store the key securely (environment variables, secrets manager)
- Rotate the key regularly
- Never log or expose the key in client-side code
2. Making Authenticated Requests
Include the Bearer token in the Authorization header:
bash
curl -X POST https://your-license-api.com/v1/issue-license \
-H "Authorization: Bearer your-admin-api-key" \
-H "Content-Type: application/json" \
-d '{
"tier": "pro",
"product_id": "your-product",
"issued_to": "customer@company.com",
"expires_at": "2025-12-31T23:59:59Z"
}'Client Examples
JavaScript/Node.js
javascript
class LicenseAdminClient {
constructor(baseURL, adminKey) {
this.baseURL = baseURL;
this.headers = {
'Content-Type': 'application/json',
'Authorization': `Bearer ${adminKey}`
};
}
async issueLicense(licenseData) {
const response = await fetch(`${this.baseURL}/issue-license`, {
method: 'POST',
headers: this.headers,
body: JSON.stringify(licenseData)
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${await response.text()}`);
}
return response.json();
}
async revokeLicense(key, revoked = true) {
const response = await fetch(`${this.baseURL}/revoke-license`, {
method: 'POST',
headers: this.headers,
body: JSON.stringify({ key, revoked })
});
return response.json();
}
}
// Usage
const adminClient = new LicenseAdminClient(
'https://your-license-api.com/v1',
process.env.ADMIN_API_KEY
);
const license = await adminClient.issueLicense({
tier: 'pro',
product_id: 'your-product',
issued_to: 'customer@example.com',
expires_at: '2025-12-31T23:59:59Z',
limits: { users: 100 }
});Python
python
import os
import requests
from typing import Dict, Any
class LicenseAdminClient:
def __init__(self, base_url: str, admin_key: str = None):
self.base_url = base_url
self.admin_key = admin_key or os.getenv('ADMIN_API_KEY')
if not self.admin_key:
raise ValueError("Admin API key is required")
self.headers = {
'Content-Type': 'application/json',
'Authorization': f'Bearer {self.admin_key}'
}
def issue_license(self, license_data: Dict[str, Any]) -> Dict[str, Any]:
response = requests.post(
f'{self.base_url}/issue-license',
json=license_data,
headers=self.headers
)
response.raise_for_status()
return response.json()
def revoke_license(self, key: str, revoked: bool = True) -> Dict[str, Any]:
response = requests.post(
f'{self.base_url}/revoke-license',
json={'key': key, 'revoked': revoked},
headers=self.headers
)
response.raise_for_status()
return response.json()
# Usage
admin_client = LicenseAdminClient('https://your-license-api.com/v1')
license = admin_client.issue_license({
'tier': 'pro',
'product_id': 'your-product',
'issued_to': 'customer@example.com',
'expires_at': '2025-12-31T23:59:59Z',
'limits': {'users': 100}
})cURL Examples
Issue a License
bash
curl -X POST https://your-license-api.com/v1/issue-license \
-H "Authorization: Bearer $ADMIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"tier": "pro",
"product_id": "your-product",
"issued_to": "customer@company.com",
"expires_at": "2025-12-31T23:59:59Z",
"limits": {
"users": 100,
"api_calls": 10000
},
"max_activations": 5
}'Revoke a License
bash
curl -X POST https://your-license-api.com/v1/revoke-license \
-H "Authorization: Bearer $ADMIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"key": "7yChyZcfMG23Dx1sjBoLziPFrH4n-6f28",
"revoked": true
}'Get Admin Statistics
bash
curl -H "Authorization: Bearer $ADMIN_API_KEY" \
https://your-license-api.com/v1/admin/statsError Handling
403 Forbidden
When authentication fails, you'll receive a 403 status with an error message:
json
{
"error": "Unauthorized"
}Common causes:
- Missing
Authorizationheader - Invalid or expired admin API key
- Incorrect token format (should be
Bearer <key>)
Example Error Handling
javascript
try {
const response = await fetch('/issue-license', {
method: 'POST',
headers: {
'Authorization': `Bearer ${adminKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(licenseData)
});
if (response.status === 403) {
throw new Error('Admin authentication failed. Check your API key.');
}
if (!response.ok) {
const error = await response.json();
throw new Error(error.error || 'Request failed');
}
return await response.json();
} catch (error) {
console.error('License operation failed:', error.message);
throw error;
}Security Considerations
Token Storage
- Server-side: Store in environment variables or secure secret managers
- Never store admin tokens in:
- Client-side JavaScript
- Version control systems
- Log files
- URLs or query parameters
Token Rotation
- Rotate admin API keys regularly (recommended: every 90 days)
- Use different keys for different environments (dev/staging/production)
- Implement key rotation without downtime using key versioning
Network Security
- Always use HTTPS in production
- Consider IP allowlisting for admin operations
- Implement request signing for additional security if needed
Next Steps
- Learn about rate limits to understand request quotas
- Explore the Integration Guide for implementation examples
- Check out Admin Operations for license management workflows