Authentication API
Overview
Aether CMS API uses token-based authentication to secure all endpoints. Authentication is required for all API operations to ensure content security and user accountability.
Authentication Methods
1. Bearer Token Authentication (Recommended)
The primary authentication method uses Bearer tokens in the Authorization header.
Header Format:
Authorization: Bearer {token}
Example:
fetch("/api/posts", {
headers: {
Authorization: "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"Content-Type": "application/json",
},
})
2. Cookie-Based Authentication
For web applications, signed cookies can be used for authentication.
Cookie Name: authToken
Login Process
Login Endpoint
POST /api/auth/login
Request Body:
{
"username": "your_username",
"password": "your_password"
}
Success Response (200):
{
"success": true,
"data": {
"user": {
"id": "user_id",
"username": "your_username",
"email": "user@example.com",
"role": "admin",
"createdAt": "2024-01-01T00:00:00.000Z"
},
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expiresAt": 1703980800000
}
}
Error Response (401):
{
"success": false,
"error": "Invalid username or password"
}
Login Implementation Example
async function login(username, password) {
try {
const response = await fetch("/api/auth/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ username, password }),
})
const result = await response.json()
if (result.success) {
// Store token for future requests
localStorage.setItem("authToken", result.data.token)
return result.data
} else {
throw new Error(result.error)
}
} catch (error) {
console.error("Login failed:", error)
throw error
}
}
Logout Process
Logout Endpoint
POST /api/auth/logout
Headers:
Authorization: Bearer {token}
Success Response (200):
{
"success": true
}
Error Response (400):
{
"success": false,
"error": "No token provided"
}
Logout Implementation Example
async function logout() {
const token = localStorage.getItem("authToken")
try {
const response = await fetch("/api/auth/logout", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
},
})
const result = await response.json()
if (result.success) {
localStorage.removeItem("authToken")
return true
}
} catch (error) {
console.error("Logout failed:", error)
} finally {
// Always clear local token
localStorage.removeItem("authToken")
}
}
Token Management
Token Expiration
- Tokens expire after 24 hours by default
- The
expiresAt
timestamp indicates when the token expires - Expired tokens will return 401 Unauthorized responses
Token Refresh
Currently, tokens cannot be refreshed. When a token expires, users must log in again to obtain a new token.
Token Storage
Client-Side Storage Options:
localStorage
- Persists across browser sessionssessionStorage
- Cleared when browser tab closes- Secure cookies - For enhanced security
Security Considerations:
- Never store tokens in plain text files
- Use HTTPS in production
- Clear tokens on logout
- Implement token expiration handling
Rate Limiting
Login Attempts
The API implements rate limiting for login attempts to prevent brute force attacks:
- Maximum Attempts: 5 failed attempts
- Lockout Period: 15 minutes
- Scope: Per username
Rate Limited Response (429):
{
"success": false,
"error": "Account temporarily locked. Try again in 12 minutes."
}
Rate Limit Headers
Rate limit information is included in response headers:
X-RateLimit-Limit: 5
X-RateLimit-Remaining: 3
X-RateLimit-Reset: 1703980800
User Roles & Permissions
Available Roles
Admin - Full system access
- All content operations
- User management
- System settings
- Theme management
Editor - Content management
- Create, edit, delete posts/pages
- Media management
- Limited settings access
Permission Checking
The API automatically checks permissions based on the authenticated user's role. Insufficient permissions result in 403 Forbidden responses.
Security Best Practices
For Developers
- Use HTTPS - Always use HTTPS in production
- Validate Tokens - Check token validity on each request
- Handle Errors - Implement proper error handling for auth failures
- Secure Storage - Store tokens securely on the client side
- Token Rotation - Re-authenticate periodically
For API Consumers
- Error Handling - Always check for authentication errors
- Token Validation - Verify token expiration before requests
- Logout Cleanup - Clear tokens on logout
- Network Security - Use secure connections
Authentication Helper Functions
Token Validation
function isTokenExpired(expiresAt) {
return Date.now() >= expiresAt
}
function getStoredToken() {
const token = localStorage.getItem("authToken")
const expiresAt = localStorage.getItem("tokenExpiry")
if (!token || !expiresAt || isTokenExpired(parseInt(expiresAt))) {
localStorage.removeItem("authToken")
localStorage.removeItem("tokenExpiry")
return null
}
return token
}
Authenticated Request Helper
async function authenticatedRequest(url, options = {}) {
const token = getStoredToken()
if (!token) {
throw new Error("No valid authentication token")
}
const response = await fetch(url, {
...options,
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
...options.headers,
},
})
if (response.status === 401) {
// Token expired or invalid
localStorage.removeItem("authToken")
localStorage.removeItem("tokenExpiry")
throw new Error("Authentication expired")
}
return response
}
Error Handling
Common Authentication Errors
- 401 Unauthorized - Invalid or expired token
- 403 Forbidden - Insufficient permissions
- 429 Too Many Requests - Rate limit exceeded
- 400 Bad Request - Missing credentials
Error Response Format
{
"success": false,
"error": "Detailed error message",
"code": "ERROR_CODE" // Optional error code
}
Implementation Example
async function handleAuthenticatedRequest(url, options) {
try {
const response = await authenticatedRequest(url, options)
const data = await response.json()
if (!data.success) {
throw new Error(data.error)
}
return data
} catch (error) {
if (error.message === "Authentication expired") {
// Redirect to login or show login modal
redirectToLogin()
} else {
// Handle other errors
console.error("API Error:", error.message)
}
throw error
}
}