0Pricing
Frontend Academy · Урок

Потоки OAuth на фронтенде

Реализуйте поток кода авторизации с PKCE в SPA, обменивайте код на токены, безопасно храните токены доступа и избегайте неявного потока

«Потоки OAuth на фронтенде» — бесплатный урок Frontend Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Frontend Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Frontend Academy содержит 4 уроков всего.

Что такое OAuth

OAuth 2.0 — это протокол делегирования: ваше приложение получает разрешение действовать от имени пользователя в стороннем сервисе (Google, GitHub и т. д.), никогда не видя пароль пользователя. Он используется для вариантов «Войти через Google», приложений OAuth для GitHub и большинства современных систем аутентификации.

Основные роли

Владелец ресурса: пользователь. Клиент: ваше приложение. Сервер авторизации: поставщик OAuth (Google, Auth0). Сервер ресурсов: API, защищённый token доступа.

Поток кода авторизации

Стандартный безопасный поток для приложений на сервере: 1) Перенаправьте пользователя на страницу входа поставщика. 2) Пользователь входит в систему и даёт согласие. 3) Поставщик перенаправляет его обратно с кодом. 4) Сервер обменивает код на token доступа (секрет, доступный только серверу).

Зачем нужен PKCE в SPA

SPA не могут хранить секрет клиента, поскольку он оказался бы в браузерной сборке. PKCE (подтверждение ключа для обмена кодом) заменяет секрет одноразовыми verifier и challenge для каждого запроса. Теперь это стандарт для всех общедоступных клиентов OAuth.

Поток PKCE по шагам

1) Создайте случайный code_verifier. 2) Вычислите его хеш SHA-256 = code_challenge. 3) Перенаправьте пользователя на /authorize с challenge. 4) После согласия получите код обратно. 5) Обменяйте код + verifier на token доступа. Поставщик проверяет, что challenge = hash(verifier).

Создание verifier и challenge

Verifier — это случайная строка, а challenge — её значение SHA-256 в кодировке base64 для URL.

function base64url(arr) {
  return btoa(String.fromCharCode(...arr))
    .replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
}

async function generatePKCE() {
  const arr = new Uint8Array(32);
  crypto.getRandomValues(arr);
  const verifier = base64url(arr);
  const hash = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier));
  const challenge = base64url(new Uint8Array(hash));
  return { verifier, challenge };
}

Перенаправление к поставщику

Сформируйте URL авторизации с challenge, параметром state (защита от CSRF) и областями действия.

const { verifier, challenge } = await generatePKCE();
const state = crypto.randomUUID();
sessionStorage.setItem('pkce_verifier', verifier);
sessionStorage.setItem('oauth_state', state);

const url = new URL('https://accounts.google.com/o/oauth2/v2/auth');
url.searchParams.set('client_id', CLIENT_ID);
url.searchParams.set('redirect_uri', `${origin}/auth/callback`);
url.searchParams.set('response_type', 'code');
url.searchParams.set('scope', 'openid email profile');
url.searchParams.set('code_challenge', challenge);
url.searchParams.set('code_challenge_method', 'S256');
url.searchParams.set('state', state);

window.location.href = url.toString();

Обработка обратного вызова

Поставщик перенаправляет пользователя на ваш URL обратного вызова с параметрами ?code=...&state=.... Проверьте state для предотвращения CSRF, затем обменяйте код.

// /auth/callback page:
const params = new URLSearchParams(window.location.search);
const code = params.get('code');
const returnedState = params.get('state');
const expected = sessionStorage.getItem('oauth_state');
if (returnedState !== expected) throw new Error('Bad state');

const verifier = sessionStorage.getItem('pkce_verifier');

const tokens = await fetch('https://oauth2.googleapis.com/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  body: new URLSearchParams({
    grant_type: 'authorization_code',
    code,
    client_id: CLIENT_ID,
    redirect_uri: `${origin}/auth/callback`,
    code_verifier: verifier
  })
}).then(r => r.json());
// tokens: { access_token, id_token, refresh_token, expires_in }

Безопасное хранение токенов

Лучшая практика: не храните tokens доступа в localStorage, откуда их можно украсть через XSS. Варианты: 1) Только в памяти (очищается при обновлении страницы — требуется повторная аутентификация). 2) Файл cookie с HttpOnly (устанавливается вашим сервером после потока PKCE и недоступен для кражи через JS).

Избегайте неявного потока

Старый неявный поток возвращает token доступа непосредственно во фрагменте URL. Он объявлен устаревшим в OAuth 2.0 Security BCP, поскольку tokens попадают в историю браузера и рефереры. Всегда используйте Authorization Code + PKCE.

Tokens обновления

Tokens доступа истекают, обычно через 1 час. Долгоживущий token обновления незаметно получает новые tokens доступа. В SPA tokens обновления всё чаще передаются через файлы cookie с HttpOnly — никогда не используйте для них localStorage.

ID token и tokens доступа

ID token (OpenID Connect): JWT, подтверждающий личность пользователя. Access token: непрозрачный token или JWT, используемый для вызова API. Перед доверием проверьте подпись и утверждения ID token (iss, aud, exp, nonce).

Библиотеки аутентификации

Не создавайте собственную реализацию. Используйте: oidc-client-ts для низкоуровневого OIDC, auth0/spa-js для Auth0, @clerk/clerk-react для Clerk, NextAuth.js/Auth.js для Next, Nuxt-auth для Nuxt. Они обрабатывают PKCE, обновление и хранение.

Быстрая проверка

Почему одностраничные приложения должны использовать PKCE (подтверждение ключа для обмена кодом) вместе с потоком кода авторизации, а не только базовый поток кода авторизации?

Итоги: OAuth во фронтенде

Authorization Code + PKCE — современный стандарт для SPA. Создавайте verifier + challenge S256 для каждого запроса. Перенаправляйте пользователя на /authorize с challenge + state. Проверяйте state при обратном вызове. Обменивайте код + verifier на tokens. Никогда не используйте неявный поток. Для хранения tokens предпочтительнее файлы cookie с HttpOnly. Используйте библиотеки (auth0-spa-js, oidc-client-ts, NextAuth), а не собственную реализацию.

Часто задаваемые вопросы

Урок «Потоки OAuth на фронтенде» бесплатный?

Да — полный текст урока «Потоки OAuth на фронтенде» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Frontend Academy, подпишись на CoddyKit PRO. Курс Frontend Academy содержит 4 уроков всего.

Чему я научусь в уроке «Потоки OAuth на фронтенде»?

Реализуйте поток кода авторизации с PKCE в SPA, обменивайте код на токены, безопасно храните токены доступа и избегайте неявного потока Ты практикуешь Frontend Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Frontend Academy?

Предыдущий опыт не требуется. Frontend Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «Потоки OAuth на фронтенде»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Frontend Academy?

Да. Каждый урок Frontend Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Предотвращение XSS: кодирование вывода и CSP
  2. CSRF: файлы cookie SameSite и токены
  3. Политика безопасности содержимого: nonce и hash
  4. Потоки OAuth на фронтенде
← Назад к Frontend Academy