Работа с Access Tokens
Руководство по управлению токенами доступа. Access Tokens используются для программного доступа к API и привязаны к пользователю.
Обзор
Access Token - это специальный токен для аутентификации API запросов через заголовок x-access-token. В отличие от JWT токенов (для веб-интерфейса), Access Tokens используются для машина-к-машине (M2M) коммуникации.
mermaid
sequenceDiagram
participant Client as Внешний клиент
participant API as Integ API
participant DB as БД
Client->>API: POST /api/access-tokens<br/>(создать новый токен)
API->>DB: Сохранить токен
DB-->>API: Token saved
API-->>Client: {token, name, createdAt}
Client->>API: GET /api/integrations<br/>x-access-token: token
API->>API: Проверить токен
API->>DB: Получить данные
DB-->>API: Data
API-->>Client: ResponseЭндпоинты
POST /api/access-tokens
Создать новый токен доступа.
Request:
http
POST /api/access-tokens
Authorization: Bearer <jwt-token>
Content-Type: application/json
{
"name": "My Integration Token"
}Parameters:
name(optional) - Название токена для удобства (например, "Telegram Integration", "Analytics Service")
Response (201 Created):
json
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"token": "at_1234567890abcdefghijklmnopqrstuvwxyz",
"name": "My Integration Token",
"createdAt": "2025-01-15T10:30:00.000Z"
}ВАЖНО
Сохраните токен в безопасном месте! Он больше не будет отображаться.
Errors:
json
// 401 Unauthorized - JWT токен отсутствует или невалидный
{
"statusCode": 401,
"message": "Unauthorized",
"error": "Unauthorized"
}
// 400 Bad Request - Невалидные данные
{
"statusCode": 400,
"message": "Name is required",
"error": "Bad Request"
}GET /api/access-tokens
Получить список всех токенов пользователя.
Request:
http
GET /api/access-tokens
Authorization: Bearer <jwt-token>Response (200 OK):
json
[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "My Integration Token",
"createdAt": "2025-01-15T10:30:00.000Z",
"lastUsedAt": "2025-01-15T12:00:00.000Z"
},
{
"id": "660e8400-e29b-41d4-a716-446655440001",
"name": "Backup Token",
"createdAt": "2025-01-10T08:15:00.000Z",
"lastUsedAt": null
}
]lastUsedAt- Время последнего использования токена (null если не использовался)
DELETE /api/access-tokens/:tokenId
Отозвать (удалить) токен доступа.
Request:
http
DELETE /api/access-tokens/550e8400-e29b-41d4-a716-446655440000
Authorization: Bearer <jwt-token>Response (200 OK):
json
{
"message": "Token revoked successfully"
}Errors:
json
// 404 Not Found - Токен не найден
{
"statusCode": 404,
"message": "Token not found",
"error": "Not Found"
}
// 403 Forbidden - Пользователь пытается удалить чужой токен
{
"statusCode": 403,
"message": "Access denied",
"error": "Forbidden"
}Использование Access Token
В заголовке x-access-token
http
x-access-token: at_1234567890abcdefghijklmnopqrstuvwxyzПримеры
cURL
bash
TOKEN="at_1234567890abcdefghijklmnopqrstuvwxyz"
curl -X GET http://localhost:3000/api/integrations \
-H "x-access-token: $TOKEN"JavaScript / Fetch
javascript
const token = "at_1234567890abcdefghijklmnopqrstuvwxyz";
const response = await fetch("http://localhost:3000/api/integrations", {
headers: {
"x-access-token": token
}
});
const data = await response.json();Axios
typescript
import axios from "axios";
const api = axios.create({
baseURL: "http://localhost:3000/api"
});
// Для всех запросов
api.defaults.headers.common["x-access-token"] = "at_1234567890...";
// Или для конкретного запроса
const response = await api.get("/integrations", {
headers: {
"x-access-token": "at_1234567890..."
}
});Node.js HTTP Client
typescript
import axios from "axios";
class IntegApiClient {
private token: string;
private api = axios.create({
baseURL: process.env.INTEG_API_URL
});
constructor(accessToken: string) {
this.token = accessToken;
this.api.defaults.headers.common["x-access-token"] = accessToken;
}
async getIntegrations() {
try {
const { data } = await this.api.get("/integrations");
return data;
} catch (error) {
if (error.response?.status === 401) {
throw new Error("Access token is invalid or expired");
}
throw error;
}
}
async invokeHandler(handlerId: string, args?: Record<string, any>) {
const { data } = await this.api.post(`/handlers/${handlerId}/invoke`, { args });
return data;
}
}
// Использование
const client = new IntegApiClient(process.env.INTEG_API_TOKEN);
const integrations = await client.getIntegrations();Best Practices
Безопасность
✅ DO:
- Храните токен в защищённом хранилище (environment переменные, vault, secrets manager)
- Используйте разные токены для разных приложений/сервисов
- Регулярно ротируйте токены
- Отзывайте токены, которые больше не нужны
- Использование HTTPS в production
❌ DON'T:
- Не храните токен в исходном коде (git repository)
- Не отправляйте токен через незащищённое соединение (HTTP)
- Не логируйте токены в сообщения
- Не делитесь токеном между приложениями
Управление
typescript
// ✅ Good - разные токены для разных целей
const telegramToken = process.env.INTEG_TELEGRAM_TOKEN;
const slackToken = process.env.INTEG_SLACK_TOKEN;
// ✅ Good - использование конфигурации
const integApi = axios.create({
baseURL: process.env.INTEG_API_URL,
headers: {
"x-access-token": process.env.INTEG_API_TOKEN
}
});
// ❌ Bad - токен в коде
const token = "at_1234567890abcdefghijklmnopqrstuvwxyz";
// ❌ Bad - один токен для всего
const globalToken = "shared-token-for-all-integrations";Полный пример - M2M интеграция
typescript
import axios from "axios";
// Инициализация клиента
const integApi = axios.create({
baseURL: "http://localhost:3000/api",
headers: {
"x-access-token": process.env.INTEG_API_TOKEN
}
});
// Получение интеграций
async function listIntegrations() {
try {
const { data } = await integApi.get("/integrations");
return data;
} catch (error) {
console.error("Failed to list integrations:", error.response?.data);
throw error;
}
}
// Получение secrets
async function getSecrets(integrationName: string) {
try {
const { data } = await integApi.get(`/core/secrets?integration=${integrationName}`);
return data;
} catch (error) {
console.error(`Failed to get secrets for ${integrationName}:`, error.response?.data);
throw error;
}
}
// Вызов handler
async function invokeHandler(handlerId: string, args: Record<string, any>) {
try {
const { data } = await integApi.post(`/handlers/${handlerId}/invoke`, { args });
return data;
} catch (error) {
console.error(`Failed to invoke handler ${handlerId}:`, error.response?.data);
throw error;
}
}
// Использование
async function main() {
// 1. Получить интеграции
const integrations = await listIntegrations();
console.log("Available integrations:", integrations);
// 2. Получить secrets Telegram
const secrets = await getSecrets("telegram");
console.log("Telegram secrets:", secrets);
// 3. Вызвать handler (используя ID handler'а)
const result = await invokeHandler("handler-uuid-1", {
message: "Hello from M2M integration!",
chatId: "123456"
});
console.log("Handler result:", result);
}
main().catch(console.error);Troubleshooting
401 Unauthorized
Причины:
- Token отсутствует или неправильный
- Token истёк
- Неправильный формат заголовка
Решение:
bash
# Проверьте токен в переменной окружения
echo $INTEG_API_TOKEN
# Проверьте формат заголовка
curl -H "x-access-token: your-token" http://localhost:3000/api/integrations
# Создайте новый токен если старый потерян403 Forbidden
Причины:
- Пытаетесь удалить чужой токен
- Недостаточно прав
Решение:
- Убедитесь, что используете правильный токен
- Проверьте, что пытаетесь делать именно с вашим токеном
Дополнительно
- Integrations - Работа с интеграциями
- Authentication - JWT аутентификация для веб-интерфейса
- Архитектура - Как устроено хранилище токенов