LeafMove Documentation CenterLeafMove Documentation Center
Home
Guide
API Docs
LeafMove Official
  • 简体中文
  • English
GitHub
Home
Guide
API Docs
LeafMove Official
  • 简体中文
  • English
GitHub
  • 🔧 API Docs

    • API Documentation
    • API Authentication Guide
    • API Usage Examples
    • Error Codes Reference

API Authentication Guide

Learn how to authenticate with the LeafMove API and manage access tokens securely.

🔐 Authentication Methods

Bearer Token Authentication

The LeafMove API uses Bearer Token authentication. You need to include a valid token in the Authorization header of each request.

Authorization: Bearer YOUR_API_TOKEN

Getting API Tokens

Method 1: Login Endpoint

async function login(email, password) {
  const response = await fetch('/api/auth/login', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      email: email,
      password: password
    })
  });
  
  const data = await response.json();
  
  if (data.code === 200) {
    // Save token
    localStorage.setItem('api_token', data.data.token);
    return data.data.token;
  } else {
    throw new Error(data.message);
  }
}

Method 2: Admin Dashboard

  1. Log in to the admin dashboard
  2. Navigate to "API Management" page
  3. Click "Generate New Token"
  4. Copy the generated token

🔑 Token Management

Secure Token Storage

// Token management utility
class TokenManager {
  static setToken(token) {
    // Use secure storage in production
    localStorage.setItem('api_token', token);
  }
  
  static getToken() {
    return localStorage.getItem('api_token');
  }
  
  static removeToken() {
    localStorage.removeItem('api_token');
  }
  
  static isTokenValid() {
    const token = this.getToken();
    if (!token) return false;
    
    try {
      // Parse JWT token (if using JWT)
      const payload = JSON.parse(atob(token.split('.')[1]));
      const now = Date.now() / 1000;
      
      return payload.exp > now;
    } catch (error) {
      return false;
    }
  }
}

Token Refresh

async function refreshToken() {
  const refreshToken = localStorage.getItem('refresh_token');
  
  if (!refreshToken) {
    throw new Error('No refresh token available');
  }
  
  const response = await fetch('/api/auth/refresh', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      refresh_token: refreshToken
    })
  });
  
  const data = await response.json();
  
  if (data.code === 200) {
    TokenManager.setToken(data.data.access_token);
    localStorage.setItem('refresh_token', data.data.refresh_token);
    return data.data.access_token;
  } else {
    // Refresh failed, need to re-login
    TokenManager.removeToken();
    localStorage.removeItem('refresh_token');
    throw new Error('Token refresh failed');
  }
}

🛡️ Permission Control

Permission Levels

Permission LevelDescriptionAccessible Endpoints
adminAdministratorAll endpoints
userRegular userUser-related endpoints
readonlyRead-only userQuery endpoints only

Permission Checking

class APIClient {
  constructor(token) {
    this.token = token;
    this.userInfo = null;
  }
  
  async getUserInfo() {
    if (!this.userInfo) {
      const response = await this.request('/api/user/profile');
      this.userInfo = response.data;
    }
    return this.userInfo;
  }
  
  async hasPermission(permission) {
    const userInfo = await this.getUserInfo();
    return userInfo.permissions.includes(permission);
  }
  
  async request(endpoint, options = {}) {
    const headers = {
      'Authorization': `Bearer ${this.token}`,
      'Content-Type': 'application/json',
      ...options.headers
    };
    
    const response = await fetch(endpoint, {
      ...options,
      headers
    });
    
    if (response.status === 401) {
      // Token expired or invalid
      throw new AuthError('Authentication failed');
    }
    
    if (response.status === 403) {
      // Insufficient permissions
      throw new PermissionError('Permission denied');
    }
    
    return response.json();
  }
}

🔒 Security Best Practices

1. Token Security

// ✅ Recommended: Use HTTPS
const API_BASE_URL = 'https://api.leafmove.com';

// ❌ Avoid: Passing token in URL
// https://api.leafmove.com/users?token=xxx

// ✅ Recommended: Pass in header
headers: {
  'Authorization': 'Bearer ' + token
}

2. Token Expiration Handling

class AuthenticatedAPIClient {
  async request(endpoint, options = {}) {
    try {
      return await this.makeRequest(endpoint, options);
    } catch (error) {
      if (error.status === 401) {
        // Try to refresh token
        try {
          await this.refreshToken();
          return await this.makeRequest(endpoint, options);
        } catch (refreshError) {
          // Refresh failed, redirect to login
          this.redirectToLogin();
          throw refreshError;
        }
      }
      throw error;
    }
  }
  
  redirectToLogin() {
    window.location.href = '/login';
  }
}

3. Request Interceptors

// Using Axios interceptors example
import axios from 'axios';

const apiClient = axios.create({
  baseURL: 'https://api.leafmove.com'
});

// Request interceptor
apiClient.interceptors.request.use(
  config => {
    const token = TokenManager.getToken();
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  error => {
    return Promise.reject(error);
  }
);

// Response interceptor
apiClient.interceptors.response.use(
  response => {
    return response;
  },
  async error => {
    const originalRequest = error.config;
    
    if (error.response?.status === 401 && !originalRequest._retry) {
      originalRequest._retry = true;
      
      try {
        await refreshToken();
        return apiClient(originalRequest);
      } catch (refreshError) {
        TokenManager.removeToken();
        window.location.href = '/login';
        return Promise.reject(refreshError);
      }
    }
    
    return Promise.reject(error);
  }
);

🧪 Testing Authentication

Test Token Validity

async function testAuthentication() {
  const token = TokenManager.getToken();
  
  if (!token) {
    console.log('❌ No token found');
    return false;
  }
  
  try {
    const response = await fetch('/api/auth/verify', {
      headers: {
        'Authorization': `Bearer ${token}`
      }
    });
    
    if (response.ok) {
      console.log('✅ Token is valid');
      return true;
    } else {
      console.log('❌ Token is invalid');
      return false;
    }
  } catch (error) {
    console.log('❌ Verification failed:', error.message);
    return false;
  }
}

Complete Authentication Flow

// Complete authentication flow example
async function authenticationFlow() {
  try {
    // 1. Check existing token
    if (TokenManager.isTokenValid()) {
      console.log('✅ Using existing token');
      return TokenManager.getToken();
    }
    
    // 2. Try to refresh token
    try {
      const newToken = await refreshToken();
      console.log('✅ Token refreshed successfully');
      return newToken;
    } catch (refreshError) {
      console.log('⚠️ Token refresh failed, need to re-login');
    }
    
    // 3. Re-login
    const email = prompt('Enter email:');
    const password = prompt('Enter password:');
    
    const token = await login(email, password);
    console.log('✅ Login successful');
    return token;
    
  } catch (error) {
    console.error('❌ Authentication failed:', error.message);
    throw error;
  }
}

📋 FAQ

Q: What to do when token expires?

A: The system will automatically try to refresh the token. If refresh fails, you need to re-login.

Q: How to check if token is valid?

A: You can call the /api/auth/verify endpoint to verify token validity.

Q: What to do if token is lost?

A: You need to re-login to get a new token, or regenerate one in the admin dashboard.

Q: Can I use multiple tokens simultaneously?

A: Yes, but it's recommended to use different tokens for different applications or environments.

🔗 Related Resources

  • API Overview
  • Usage Examples
  • Error Codes Reference
Edit this page on GitHub
Prev
API Documentation
Next
API Usage Examples