← Назад к вопросам

Как работает Token?

2.0 Middle🔥 121 комментариев
#Браузер и сетевые технологии

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как работает Token?

Что такое Token

Token (токен) - это строка данных, которая служит доказательством идентичности и аутентификации пользователя при взаимодействии между клиентом (браузер) и сервером. Токен содержит информацию о пользователе в закодированном виде.

Виды Token

1. JWT (JSON Web Token) - самый популярный

JWT состоит из трёх частей, разделённых точками:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
├─ Header (заголовок)
├─ Payload (данные)
└─ Signature (подпись)

Header (закодирован в Base64):

{
  "alg": "HS256",  // Алгоритм подписи
  "typ": "JWT"     // Тип токена
}

Payload (закодирован в Base64, но НЕ зашифрован):

{
  "sub": "1234567890",  // ID пользователя
  "name": "John Doe",   // Имя
  "iat": 1516239022,    // Дата создания
  "exp": 1516242622     // Дата истечения (через час)
}

Signature (подпись на основе Header + Payload + Secret):

HSHA256(
  base64(header) + "." + base64(payload),
  "your-secret-key"
)

Как работает аутентификация с Token

Шаг 1: Логин

// Клиент отправляет credentials
fetch('https://api.example.com/login', {
  method: 'POST',
  body: JSON.stringify({
    email: 'user@example.com',
    password: 'secure123'
  })
})
.then(r => r.json())
.then(data => {
  // Сервер вернул токен
  const token = data.token;
  // Сохраняем в localStorage
  localStorage.setItem('authToken', token);
});

Ответ от сервера:

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyQGV4YW1wbGUuY29tIiwibmFtZSI6IkpvaG4gRG9lIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c",
  "expiresIn": 3600
}

Шаг 2: Сохранение Token

// Вариант 1: localStorage (небезопасно для sensitive данных)
localStorage.setItem('token', token);

// Вариант 2: sessionStorage (удаляется при закрытии браузера)
sessionStorage.setItem('token', token);

// Вариант 3: Cookie с флагом httpOnly (безопаснее)
// Отправляется автоматически браузером

Шаг 3: Отправка Token в запросах

// Каждый API запрос включает токен в заголовок
const token = localStorage.getItem('token');

fetch('https://api.example.com/user/profile', {
  method: 'GET',
  headers: {
    'Authorization': `Bearer ${token}`
  }
})
.then(r => r.json())
.then(data => console.log(data));

Шаг 4: Проверка на сервере

// На бэкенде (Node.js + Express пример)
app.get('/user/profile', (req, res) => {
  const token = req.headers.authorization?.split(' ')[1];
  
  if (!token) {
    return res.status(401).json({ error: 'No token' });
  }
  
  try {
    // Проверяем подпись и срок действия
    const decoded = jwt.verify(token, 'your-secret-key');
    // decoded = { sub: 'user@example.com', ... }
    
    // Ищем пользователя в БД
    const user = await User.findById(decoded.sub);
    res.json(user);
  } catch (err) {
    res.status(401).json({ error: 'Invalid token' });
  }
});

Жизненный цикл Token

┌─────────────────────────────────────────────────────┐
│ 1. Создание                                         │
│    Сервер создает JWT с данными пользователя       │
└────────────────┬────────────────────────────────────┘
                 ↓
┌─────────────────────────────────────────────────────┐
│ 2. Отправка клиенту                                │
│    HTTP ответ с токеном в body или Cookie          │
└────────────────┬────────────────────────────────────┘
                 ↓
┌─────────────────────────────────────────────────────┐
│ 3. Сохранение                                      │
│    Клиент сохраняет в localStorage/sessionStorage   │
└────────────────┬────────────────────────────────────┘
                 ↓
┌─────────────────────────────────────────────────────┐
│ 4. Использование                                   │
│    Отправляется в Authorization заголовке          │
└────────────────┬────────────────────────────────────┘
                 ↓
┌─────────────────────────────────────────────────────┐
│ 5. Проверка                                        │
│    Сервер проверяет подпись и дату истечения       │
└────────────────┬────────────────────────────────────┘
                 ↓
┌─────────────────────────────────────────────────────┐
│ 6. Обновление или истечение                        │
│    Когда exp пройдена -> нужен новый токен         │
└─────────────────────────────────────────────────────┘

Пример полной реализации на Frontend

// auth.js
class AuthService {
  async login(email, password) {
    const response = await fetch('/api/login', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ email, password })
    });
    
    if (!response.ok) throw new Error('Login failed');
    
    const { token } = await response.json();
    localStorage.setItem('token', token);
    return token;
  }
  
  getToken() {
    return localStorage.getItem('token');
  }
  
  isAuthenticated() {
    const token = this.getToken();
    if (!token) return false;
    
    // Декодируем payload (вторая часть)
    const parts = token.split('.');
    const payload = JSON.parse(atob(parts[1]));
    
    // Проверяем, не истёк ли токен
    const isExpired = payload.exp * 1000 < Date.now();
    return !isExpired;
  }
  
  logout() {
    localStorage.removeItem('token');
  }
  
  async makeRequest(url, options = {}) {
    const token = this.getToken();
    
    return fetch(url, {
      ...options,
      headers: {
        ...options.headers,
        'Authorization': `Bearer ${token}`
      }
    });
  }
}

Token vs Cookie

Token (JWT в localStorage):

  • Отправляется вручную в заголовке
  • Уязвим к XSS (JavaScript может прочитать)
  • Контролируется фронтенд кодом

Cookie с httpOnly:

  • Отправляется автоматически браузером
  • Защищен от XSS (JavaScript не может прочитать)
  • Требует CSRF защиты

Refresh Token - обновление доступа

Аксес токен живёт недолго (15 минут), а Refresh токен живёт долго (7 дней):

// Логин
const { accessToken, refreshToken } = await login(email, password);
localStorage.setItem('accessToken', accessToken);
localStorage.setItem('refreshToken', refreshToken);

// Когда accessToken истекает
async function refreshAccessToken() {
  const refreshToken = localStorage.getItem('refreshToken');
  
  const response = await fetch('/api/refresh', {
    method: 'POST',
    body: JSON.stringify({ refreshToken })
  });
  
  const { accessToken } = await response.json();
  localStorage.setItem('accessToken', accessToken);
  return accessToken;
}

Безопасность

Хорошие практики:

  • Используйте HTTPS (токен может быть перехвачен)
  • Храните в HttpOnly Cookie, если возможно
  • Устанавливайте короткое время жизни (15-60 минут)
  • Используйте Refresh токен для обновления
  • Проверяйте подпись на сервере ВСЕГДА
  • Не храните чувствительные данные в Payload

Плохие практики:

  • Хранение в localStorage для XSS-уязвимых приложений
  • Отправка пароля в токене
  • Беспроверочное использование токена

Ключевые выводы

  • JWT = закодированные данные + подпись
  • Клиент отправляет в каждом запросе: Authorization: Bearer token
  • Сервер проверяет подпись - уверен, что токен не поддельный
  • Токен живёт ограниченное время - нужно обновлять
  • Не зашифрован, только закодирован - не передавайте secrets в payload
  • Refresh tokens помогают обновлять доступ без повторного логина
Как работает Token? | PrepBro