JavaScript · API · Средний

JWT-аутентификация

5 задач

Используйте JSON Web Tokens для аутентификации и обрабатывайте обновление токенов.

JWT — access и refresh токены

#
JWT (JSON Web Token) аутентификация использует два токена вместо одного: - **Access token** — короткоживущий (минуты/часы). Отправляйте его в каждом запросе как `Bearer <access_token>`. - **Refresh token** — долгоживущий (дни/недели). Используется для получения нового access token после истечения срока действия старого. **Получить оба токена:** ```javascript const response = await fetch('https://apilearn.tukas.dev/api/auth/jwt/', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username: 'alice42', password: 'SecurePass123!' }), }); const { access, refresh } = await response.json(); ``` **Использовать access token — обратите внимание: `Bearer`, не `Token`:** ```javascript const profile = await fetch('https://apilearn.tukas.dev/api/users/profile/', { headers: { 'Authorization': `Bearer ${access}` }, }).then(r => r.json()); ``` **Обновление — получить новый access token:** ```javascript const response = await fetch('https://apilearn.tukas.dev/api/auth/jwt/refresh/', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ refresh }), }); const { access: newAccess, refresh: newRefresh } = await response.json(); ``` Эндпоинт обновления возвращает и новый access token, и новый refresh token — обновляйте оба.

Получение и обновление JWT-токенов

#
Полный JWT-поток с обновлением: ```javascript const BASE_URL = 'https://apilearn.tukas.dev'; async function getJwtTokens(username, password) { const response = await fetch(`${BASE_URL}/api/auth/jwt/`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }), }); return response.json(); // { access, refresh } } async function refreshTokens(refreshToken) { const response = await fetch(`${BASE_URL}/api/auth/jwt/refresh/`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ refresh: refreshToken }), }); return response.json(); // { access, refresh } } async function main() { // Шаг 1: получить начальные токены let { access, refresh } = await getJwtTokens('YOUR_USERNAME', 'YOUR_PASSWORD'); console.log('Access token:', access.slice(0, 20) + '...'); // Шаг 2: использовать access token const profile = await fetch(`${BASE_URL}/api/users/profile/`, { headers: { 'Authorization': `Bearer ${access}` }, }).then(r => r.json()); console.log('Профиль:', profile.username); // Шаг 3: симулируем обновление (на практике делайте это при получении 401) const refreshed = await refreshTokens(refresh); access = refreshed.access; refresh = refreshed.refresh; console.log('Новый access token:', access.slice(0, 20) + '...'); // Шаг 4: использовать новый access token const cart = await fetch(`${BASE_URL}/api/cart/`, { headers: { 'Authorization': `Bearer ${access}` }, }).then(r => r.json()); console.log('Товаров в корзине:', cart.items.length); } main(); ```

Справочник JWT

#
**Эндпоинты** ``` POST /api/auth/jwt/ Получить access + refresh токены тело: { username, password } возвращает: { access, refresh } POST /api/auth/jwt/refresh/ Получить новые токены через refresh token тело: { refresh } возвращает: { access, refresh } ``` **Использование access token** ```javascript headers: { 'Authorization': `Bearer ${access}` } // Обратите внимание: "Bearer", не "Token" — отличие от токен-аутентификации ``` **Сравнение Token и JWT** ``` Token auth Один токен, не истекает "Token <token>" JWT auth пара access + refresh "Bearer <access>" access истекает, refresh ротируется ``` **Паттерн обновления** ```javascript let { access, refresh } = await getJwtTokens(user, pass); // Когда access token истекает (401): const tokens = await refreshTokens(refresh); access = tokens.access; refresh = tokens.refresh; // также обновляем refresh ``` **Структура JWT (информационно)** ``` header.payload.signature — три части base64, разделённые точками atob(access.split('.')[1]) — декодировать payload (содержит exp, user_id и др.) ```
01

Получить JWT-токены

#

POST к `/api/auth/jwt/` с вашими учётными данными. Выведите оба токена — `access` и `refresh` (первых 30 символов достаточно).

const BASE_URL = 'https://apilearn.tukas.dev';

async function main() {
  // POST /api/auth/jwt/ и вывести access + refresh (первые 30 символов)
}

main();
Решение
const BASE_URL = 'https://apilearn.tukas.dev';

async function main() {
  const response = await fetch(`${BASE_URL}/api/auth/jwt/`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ username: 'YOUR_USERNAME', password: 'YOUR_PASSWORD' }),
  });
  const { access, refresh } = await response.json();
  console.log('access:', access.slice(0, 30) + '...');
  console.log('refresh:', refresh.slice(0, 30) + '...');
}

main();
02

Использовать access token для запроса

#

Получите JWT-токены, затем используйте `access` токен с префиксом `Bearer` для запроса к `/api/users/profile/`. Выведите `username` и `email`.

const BASE_URL = 'https://apilearn.tukas.dev';

async function main() {
  // получить JWT, использовать access token с префиксом Bearer для запроса профиля
}

main();
Решение
const BASE_URL = 'https://apilearn.tukas.dev';

async function main() {
  const { access } = await fetch(`${BASE_URL}/api/auth/jwt/`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ username: 'YOUR_USERNAME', password: 'YOUR_PASSWORD' }),
  }).then(r => r.json());

  const profile = await fetch(`${BASE_URL}/api/users/profile/`, {
    headers: { 'Authorization': `Bearer ${access}` },
  }).then(r => r.json());

  console.log(profile.username);
  console.log(profile.email);
}

main();
03

Обновить access token

#

Получите начальные JWT-токены, затем сразу вызовите `/api/auth/jwt/refresh/` с токеном `refresh`. Выведите новый `access` токен (первых 30 символов) и убедитесь, что он отличается от старого.

const BASE_URL = 'https://apilearn.tukas.dev';

async function main() {
  // получить токены, затем обновить, сравнить старый и новый access
}

main();
Решение
const BASE_URL = 'https://apilearn.tukas.dev';

async function main() {
  const { access: oldAccess, refresh } = await fetch(`${BASE_URL}/api/auth/jwt/`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ username: 'YOUR_USERNAME', password: 'YOUR_PASSWORD' }),
  }).then(r => r.json());

  const { access: newAccess } = await fetch(`${BASE_URL}/api/auth/jwt/refresh/`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ refresh }),
  }).then(r => r.json());

  console.log('Old:', oldAccess.slice(0, 30));
  console.log('New:', newAccess.slice(0, 30));
  console.log('Different:', oldAccess !== newAccess);
}

main();
04

Декодировать payload JWT

#

Получите access token. Payload JWT — это средняя часть (между двумя точками), закодированная в base64. Декодируйте её через `atob()` и `JSON.parse()`. Выведите `user_id` и `exp` из payload.

const BASE_URL = 'https://apilearn.tukas.dev';

async function main() {
  // получить access token
  // разбить по '.', взять индекс 1, декодировать через atob, распарсить JSON
  // вывести user_id и exp
}

main();
Решение
const BASE_URL = 'https://apilearn.tukas.dev';

async function main() {
  const { access } = await fetch(`${BASE_URL}/api/auth/jwt/`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ username: 'YOUR_USERNAME', password: 'YOUR_PASSWORD' }),
  }).then(r => r.json());

  const payload = JSON.parse(atob(access.split('.')[1]));
  console.log('user_id:', payload.user_id);
  console.log('exp:', payload.exp);
  console.log('expires:', new Date(payload.exp * 1000).toISOString());
}

main();
05

Полный JWT-поток

#

Напишите полный скрипт: получите токены, запросите профиль через `access`, обновите токены, затем запросите корзину с новым `access`. Выведите username из профиля и количество товаров в корзине.

const BASE_URL = 'https://apilearn.tukas.dev';

async function main() {
  // 1. получить JWT-токены
  // 2. запросить профиль через access
  // 3. обновить токены
  // 4. запросить корзину с новым access
}

main();
Решение
const BASE_URL = 'https://apilearn.tukas.dev';

async function main() {
  // 1. Initial tokens
  let { access, refresh } = await fetch(`${BASE_URL}/api/auth/jwt/`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ username: 'YOUR_USERNAME', password: 'YOUR_PASSWORD' }),
  }).then(r => r.json());

  // 2. Fetch profile
  const profile = await fetch(`${BASE_URL}/api/users/profile/`, {
    headers: { 'Authorization': `Bearer ${access}` },
  }).then(r => r.json());
  console.log('Username:', profile.username);

  // 3. Refresh
  ({ access, refresh } = await fetch(`${BASE_URL}/api/auth/jwt/refresh/`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ refresh }),
  }).then(r => r.json()));

  // 4. Fetch cart with new token
  const cart = await fetch(`${BASE_URL}/api/cart/`, {
    headers: { 'Authorization': `Bearer ${access}` },
  }).then(r => r.json());
  console.log('Cart items:', cart.items.length);
}

main();