Authentication API

On this page

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 sessions
  • sessionStorage - 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

  1. Admin - Full system access

    • All content operations
    • User management
    • System settings
    • Theme management
  2. 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

  1. Use HTTPS - Always use HTTPS in production
  2. Validate Tokens - Check token validity on each request
  3. Handle Errors - Implement proper error handling for auth failures
  4. Secure Storage - Store tokens securely on the client side
  5. Token Rotation - Re-authenticate periodically

For API Consumers

  1. Error Handling - Always check for authentication errors
  2. Token Validation - Verify token expiration before requests
  3. Logout Cleanup - Clear tokens on logout
  4. 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
    }
}