Authentication Guide
# Authentication Guide
This guide covers all aspects of authentication with our platform, including API key authentication, OAuth flows, and best practices for securing your applications.
## Authentication Methods
Our platform supports multiple authentication methods to suit different use cases:
### 1. API Key Authentication
The simplest method for server-to-server communication:
```bash
curl -X POST https://api.example.com/v1/auth/login \
-H "Content-Type: application/json" \
-d '{
"api_key": "your-api-key-here"
}'
```
**Response:**
```json
{
"success": true,
"data": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600
}
}
```
### 2. Bearer Token Authentication
Use the access token received from login for subsequent requests:
```bash
curl -X GET https://api.example.com/v1/users/me \
-H "Authorization: Bearer your-access-token"
```
## Implementation Examples
### JavaScript/Node.js
```javascript
class APIClient {
constructor(apiKey) {
this.apiKey = apiKey;
this.accessToken = null;
}
async authenticate() {
const response = await fetch('https://api.example.com/v1/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
api_key: this.apiKey
})
});
const data = await response.json();
if (data.success) {
this.accessToken = data.data.access_token;
return data.data;
} else {
throw new Error(data.error.message);
}
}
async makeAuthenticatedRequest(endpoint) {
if (!this.accessToken) {
await this.authenticate();
}
const response = await fetch(`https://api.example.com/v1${endpoint}`, {
headers: {
'Authorization': `Bearer ${this.accessToken}`,
'Content-Type': 'application/json'
}
});
return response.json();
}
}
// Usage
const client = new APIClient('your-api-key');
const userData = await client.makeAuthenticatedRequest('/users/me');
```
### Python
```python
import requests
import json
class APIClient:
def __init__(self, api_key):
self.api_key = api_key
self.access_token = None
self.base_url = "https://api.example.com/v1"
def authenticate(self):
response = requests.post(
f"{self.base_url}/auth/login",
headers={"Content-Type": "application/json"},
json={"api_key": self.api_key}
)
data = response.json()
if data["success"]:
self.access_token = data["data"]["access_token"]
return data["data"]
else:
raise Exception(data["error"]["message"])
def make_authenticated_request(self, endpoint):
if not self.access_token:
self.authenticate()
response = requests.get(
f"{self.base_url}{endpoint}",
headers={
"Authorization": f"Bearer {self.access_token}",
"Content-Type": "application/json"
}
)
return response.json()
# Usage
client = APIClient("your-api-key")
user_data = client.make_authenticated_request("/users/me")
```
## Token Management
### Token Expiration
Access tokens expire after 1 hour by default. Implement token refresh logic:
```javascript
class APIClient {
constructor(apiKey) {
this.apiKey = apiKey;
this.accessToken = null;
this.tokenExpiry = null;
}
isTokenExpired() {
return !this.tokenExpiry || Date.now() >= this.tokenExpiry;
}
async authenticate() {
const response = await fetch('https://api.example.com/v1/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
api_key: this.apiKey
})
});
const data = await response.json();
if (data.success) {
this.accessToken = data.data.access_token;
// Set expiry time (subtract 5 minutes for safety)
this.tokenExpiry = Date.now() + (data.data.expires_in - 300) * 1000;
return data.data;
} else {
throw new Error(data.error.message);
}
}
async makeAuthenticatedRequest(endpoint) {
if (this.isTokenExpired()) {
await this.authenticate();
}
// ... rest of the request logic
}
}
```
### Secure Token Storage
**Server-side (Node.js):**
```javascript
// Use environment variables
const apiKey = process.env.API_KEY;
// For session storage
req.session.accessToken = token;
// For database storage (encrypted)
const encryptedToken = await encrypt(token, encryptionKey);
await db.tokens.create({ userId, token: encryptedToken });
```
**Client-side (Browser):**
```javascript
// Store in memory (cleared on page refresh)
let accessToken = null;
// For persistent storage (less secure)
localStorage.setItem('accessToken', token);
// For session storage (cleared when tab closes)
sessionStorage.setItem('accessToken', token);
```
## Error Handling
Handle authentication errors gracefully:
```javascript
async function handleAuthError(error) {
switch (error.code) {
case 'INVALID_API_KEY':
console.error('API key is invalid. Please check your configuration.');
break;
case 'TOKEN_EXPIRED':
console.log('Token expired, refreshing...');
await authenticate();
break;
case 'RATE_LIMITED':
console.error('Rate limit exceeded. Please wait before retrying.');
break;
default:
console.error('Authentication error:', error.message);
}
}
// Usage in request
try {
const response = await makeAuthenticatedRequest('/users/me');
return response;
} catch (error) {
await handleAuthError(error);
throw error;
}
```
## Security Best Practices
### 1. API Key Security
- **Never expose API keys in client-side code**
- Store keys in environment variables
- Rotate keys regularly
- Use different keys for development and production
### 2. Token Security
- Store tokens securely (encrypted if possible)
- Implement token expiration handling
- Clear tokens on logout
- Use HTTPS for all API calls
### 3. Rate Limiting
```javascript
class RateLimiter {
constructor(maxRequests = 100, windowMs = 60000) {
this.maxRequests = maxRequests;
this.windowMs = windowMs;
this.requests = [];
}
async checkLimit() {
const now = Date.now();
this.requests = this.requests.filter(time => now - time < this.windowMs);
if (this.requests.length >= this.maxRequests) {
throw new Error('Rate limit exceeded');
}
this.requests.push(now);
}
}
```
### 4. Request Validation
```javascript
function validateRequest(data) {
const required = ['api_key'];
const missing = required.filter(field => !data[field]);
if (missing.length > 0) {
throw new Error(`Missing required fields: ${missing.join(', ')}`);
}
if (data.api_key.length < 32) {
throw new Error('API key appears to be invalid');
}
}
```
## Testing Authentication
### Unit Tests
```javascript
describe('Authentication', () => {
test('should authenticate with valid API key', async () => {
const client = new APIClient('valid-api-key');
const result = await client.authenticate();
expect(result.access_token).toBeDefined();
expect(result.token_type).toBe('Bearer');
});
test('should handle invalid API key', async () => {
const client = new APIClient('invalid-key');
await expect(client.authenticate()).rejects.toThrow('Invalid API key');
});
});
```
### Integration Tests
```javascript
describe('API Integration', () => {
test('should make authenticated requests', async () => {
const client = new APIClient(process.env.TEST_API_KEY);
const userData = await client.makeAuthenticatedRequest('/users/me');
expect(userData.success).toBe(true);
expect(userData.data.id).toBeDefined();
});
});
```
## Troubleshooting
### Common Issues
1. **"Invalid API Key" Error**
- Verify the API key is correct
- Check for extra spaces or characters
- Ensure the key is active in your dashboard
2. **"Token Expired" Error**
- Implement automatic token refresh
- Check system clock synchronization
- Verify token expiration handling
3. **"Rate Limited" Error**
- Implement exponential backoff
- Reduce request frequency
- Check your rate limit quotas
### Debug Mode
Enable debug logging for troubleshooting:
```javascript
const DEBUG = process.env.NODE_ENV === 'development';
function log(message, data = null) {
if (DEBUG) {
console.log(`[Auth] ${message}`, data);
}
}
```
## Next Steps
After implementing authentication:
- Set up user management and permissions
- Implement OAuth flows if needed
- Add multi-factor authentication
- Configure webhook authentication
For more information, check out our [API Reference](/api-docs) and [Security Guide](/docs/guides/security).