Integrate OpenAPI/Swagger documentation using drf-spectacular, enhancing API documentation with comprehensive guides and schema generation. Add multiple documentation files covering authentication, error codes, rate limiting, and migration strategies. Update settings and URLs to support new documentation endpoints and schema configurations.

This commit is contained in:
IGNY8 VPS (Salman)
2025-11-16 02:15:37 +00:00
parent 452d065c22
commit 79648db07f
16 changed files with 3501 additions and 6 deletions

View File

@@ -0,0 +1,493 @@
# Authentication Guide
**Version**: 1.0.0
**Last Updated**: 2025-11-16
Complete guide for authenticating with the IGNY8 API v1.0.
---
## Overview
The IGNY8 API uses **JWT (JSON Web Token) Bearer Token** authentication. All endpoints require authentication except:
- `POST /api/v1/auth/login/` - User login
- `POST /api/v1/auth/register/` - User registration
---
## Authentication Flow
### 1. Register or Login
**Register** (if new user):
```http
POST /api/v1/auth/register/
Content-Type: application/json
{
"email": "user@example.com",
"username": "user",
"password": "secure_password123",
"first_name": "John",
"last_name": "Doe"
}
```
**Login** (existing user):
```http
POST /api/v1/auth/login/
Content-Type: application/json
{
"email": "user@example.com",
"password": "secure_password123"
}
```
### 2. Receive Tokens
**Response**:
```json
{
"success": true,
"data": {
"user": {
"id": 1,
"email": "user@example.com",
"username": "user",
"role": "owner",
"account": {
"id": 1,
"name": "My Account",
"slug": "my-account"
}
},
"access": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjE3MDAxMjM0NTZ9...",
"refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjE3MDAxODk0NTZ9..."
},
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
```
### 3. Use Access Token
Include the `access` token in all subsequent requests:
```http
GET /api/v1/planner/keywords/
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
```
### 4. Refresh Token (when expired)
When the access token expires (15 minutes), use the refresh token:
```http
POST /api/v1/auth/refresh/
Content-Type: application/json
{
"refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
```
**Response**:
```json
{
"success": true,
"data": {
"access": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
},
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
```
---
## Token Expiration
- **Access Token**: 15 minutes
- **Refresh Token**: 7 days
### Handling Token Expiration
**Option 1: Automatic Refresh**
```python
def get_access_token():
# Check if token is expired
if is_token_expired(current_token):
# Refresh token
response = requests.post(
f"{BASE_URL}/auth/refresh/",
json={"refresh": refresh_token}
)
data = response.json()
if data['success']:
return data['data']['access']
return current_token
```
**Option 2: Re-login**
```python
def login():
response = requests.post(
f"{BASE_URL}/auth/login/",
json={"email": email, "password": password}
)
data = response.json()
if data['success']:
return data['data']['access']
```
---
## Code Examples
### Python
```python
import requests
import time
from datetime import datetime, timedelta
class Igny8API:
def __init__(self, base_url="https://api.igny8.com/api/v1"):
self.base_url = base_url
self.access_token = None
self.refresh_token = None
self.token_expires_at = None
def login(self, email, password):
"""Login and store tokens"""
response = requests.post(
f"{self.base_url}/auth/login/",
json={"email": email, "password": password}
)
data = response.json()
if data['success']:
self.access_token = data['data']['access']
self.refresh_token = data['data']['refresh']
# Token expires in 15 minutes
self.token_expires_at = datetime.now() + timedelta(minutes=14)
return True
else:
print(f"Login failed: {data['error']}")
return False
def refresh_access_token(self):
"""Refresh access token using refresh token"""
if not self.refresh_token:
return False
response = requests.post(
f"{self.base_url}/auth/refresh/",
json={"refresh": self.refresh_token}
)
data = response.json()
if data['success']:
self.access_token = data['data']['access']
self.refresh_token = data['data']['refresh']
self.token_expires_at = datetime.now() + timedelta(minutes=14)
return True
else:
print(f"Token refresh failed: {data['error']}")
return False
def get_headers(self):
"""Get headers with valid access token"""
# Check if token is expired or about to expire
if not self.token_expires_at or datetime.now() >= self.token_expires_at:
if not self.refresh_access_token():
raise Exception("Token expired and refresh failed")
return {
'Authorization': f'Bearer {self.access_token}',
'Content-Type': 'application/json'
}
def get(self, endpoint):
"""Make authenticated GET request"""
response = requests.get(
f"{self.base_url}{endpoint}",
headers=self.get_headers()
)
return response.json()
def post(self, endpoint, data):
"""Make authenticated POST request"""
response = requests.post(
f"{self.base_url}{endpoint}",
headers=self.get_headers(),
json=data
)
return response.json()
# Usage
api = Igny8API()
api.login("user@example.com", "password")
# Make authenticated requests
keywords = api.get("/planner/keywords/")
```
### JavaScript
```javascript
class Igny8API {
constructor(baseUrl = 'https://api.igny8.com/api/v1') {
this.baseUrl = baseUrl;
this.accessToken = null;
this.refreshToken = null;
this.tokenExpiresAt = null;
}
async login(email, password) {
const response = await fetch(`${this.baseUrl}/auth/login/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ email, password })
});
const data = await response.json();
if (data.success) {
this.accessToken = data.data.access;
this.refreshToken = data.data.refresh;
// Token expires in 15 minutes
this.tokenExpiresAt = new Date(Date.now() + 14 * 60 * 1000);
return true;
} else {
console.error('Login failed:', data.error);
return false;
}
}
async refreshAccessToken() {
if (!this.refreshToken) {
return false;
}
const response = await fetch(`${this.baseUrl}/auth/refresh/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ refresh: this.refreshToken })
});
const data = await response.json();
if (data.success) {
this.accessToken = data.data.access;
this.refreshToken = data.data.refresh;
this.tokenExpiresAt = new Date(Date.now() + 14 * 60 * 1000);
return true;
} else {
console.error('Token refresh failed:', data.error);
return false;
}
}
async getHeaders() {
// Check if token is expired or about to expire
if (!this.tokenExpiresAt || new Date() >= this.tokenExpiresAt) {
if (!await this.refreshAccessToken()) {
throw new Error('Token expired and refresh failed');
}
}
return {
'Authorization': `Bearer ${this.accessToken}`,
'Content-Type': 'application/json'
};
}
async get(endpoint) {
const response = await fetch(
`${this.baseUrl}${endpoint}`,
{ headers: await this.getHeaders() }
);
return await response.json();
}
async post(endpoint, data) {
const response = await fetch(
`${this.baseUrl}${endpoint}`,
{
method: 'POST',
headers: await this.getHeaders(),
body: JSON.stringify(data)
}
);
return await response.json();
}
}
// Usage
const api = new Igny8API();
await api.login('user@example.com', 'password');
// Make authenticated requests
const keywords = await api.get('/planner/keywords/');
```
---
## Security Best Practices
### 1. Store Tokens Securely
**❌ Don't:**
- Store tokens in localStorage (XSS risk)
- Commit tokens to version control
- Log tokens in console/logs
- Send tokens in URL parameters
**✅ Do:**
- Store tokens in httpOnly cookies (server-side)
- Use secure storage (encrypted) for client-side
- Rotate tokens regularly
- Implement token revocation
### 2. Handle Token Expiration
Always check token expiration and refresh before making requests:
```python
def is_token_valid(token_expires_at):
# Refresh 1 minute before expiration
return datetime.now() < (token_expires_at - timedelta(minutes=1))
```
### 3. Implement Retry Logic
```python
def make_request_with_retry(url, headers, max_retries=3):
for attempt in range(max_retries):
response = requests.get(url, headers=headers)
if response.status_code == 401:
# Token expired, refresh and retry
refresh_token()
headers = get_headers()
continue
return response.json()
raise Exception("Max retries exceeded")
```
### 4. Validate Token Before Use
```python
def validate_token(token):
try:
# Decode token (without verification for structure check)
import jwt
decoded = jwt.decode(token, options={"verify_signature": False})
exp = decoded.get('exp')
if exp and datetime.fromtimestamp(exp) < datetime.now():
return False
return True
except:
return False
```
---
## Error Handling
### Authentication Errors
**401 Unauthorized**:
```json
{
"success": false,
"error": "Authentication required",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
```
**Solution**: Include valid `Authorization: Bearer <token>` header.
**403 Forbidden**:
```json
{
"success": false,
"error": "Permission denied",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
```
**Solution**: User lacks required permissions. Check user role and resource access.
---
## Testing Authentication
### Using Swagger UI
1. Navigate to `https://api.igny8.com/api/docs/`
2. Click "Authorize" button
3. Enter: `Bearer <your_token>`
4. Click "Authorize"
5. All requests will include the token
### Using cURL
```bash
# Login
curl -X POST https://api.igny8.com/api/v1/auth/login/ \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","password":"password"}'
# Use token
curl -X GET https://api.igny8.com/api/v1/planner/keywords/ \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json"
```
---
## Troubleshooting
### Issue: "Authentication required" (401)
**Causes**:
- Missing Authorization header
- Invalid token format
- Expired token
**Solutions**:
1. Verify `Authorization: Bearer <token>` header is included
2. Check token is not expired
3. Refresh token or re-login
### Issue: "Permission denied" (403)
**Causes**:
- User lacks required role
- Resource belongs to different account
- Site/sector access denied
**Solutions**:
1. Check user role has required permissions
2. Verify resource belongs to user's account
3. Check site/sector access permissions
### Issue: Token expires frequently
**Solution**: Implement automatic token refresh before expiration.
---
**Last Updated**: 2025-11-16
**API Version**: 1.0.0