Как настроить OAuth в React приложении?react-96

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

1. Подготовка

Регистрация приложения у провайдера

Для каждого OAuth-провайдера (Google, Facebook и др.) нужно:

  1. Создать проект в developer console провайдера
  2. Указать Authorized JavaScript Origins (Разрешенные источники):
    http://localhost:3000 (для разработки)
    https://yourdomain.com (для продакшена)
    
  3. Указать Authorized Redirect URIs (URI перенаправления):
    http://localhost:3000/auth/callback (пример)
    
  4. Получить:
    • Client ID
    • Client Secret (НЕ используется напрямую в React)

2. Выбор потока авторизации

Для React SPA рекомендуется:

  • PKCE (Proof Key for Code Exchange) - самый безопасный
  • Implicit Flow - устарел, не рекомендуется

3. Реализация OAuth с PKCE

Шаг 1: Генерация code_verifier и code_challenge

// utils/auth.js
export function generateCodeVerifier() {
  const array = new Uint32Array(56);
  window.crypto.getRandomValues(array);
  return Array.from(array, dec => ('0' + dec.toString(16)).slice(-2)).join('');
}

export async function generateCodeChallenge(verifier) {
  const encoder = new TextEncoder();
  const data = encoder.encode(verifier);
  const digest = await window.crypto.subtle.digest('SHA-256', data);
  return btoa(String.fromCharCode(...new Uint8Array(digest)))
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=+$/, '');
}

Шаг 2: Инициация OAuth-потока

// OAuthButton.jsx
import { generateCodeVerifier, generateCodeChallenge } from './utils/auth';

async function handleLogin() {
  const verifier = generateCodeVerifier();
  localStorage.setItem('code_verifier', verifier);

  const challenge = await generateCodeChallenge(verifier);
  const clientId = 'YOUR_CLIENT_ID';
  const redirectUri = encodeURIComponent('http://localhost:3000/callback');
  const scope = encodeURIComponent('openid profile email');

  window.location.href = `https://auth-provider.com/authorize?
    response_type=code&
    client_id=${clientId}&
    redirect_uri=${redirectUri}&
    scope=${scope}&
    code_challenge=${challenge}&
    code_challenge_method=S256`;
}

Шаг 3: Обработка callback

// CallbackPage.jsx
import { useEffect } from 'react';
import { useNavigate, useSearchParams } from 'react-router-dom';

function CallbackPage() {
  const [params] = useSearchParams();
  const navigate = useNavigate();

  useEffect(() => {
    const code = params.get('code');
    if (code) exchangeCodeForToken(code);
  }, []);

  async function exchangeCodeForToken(code) {
    const verifier = localStorage.getItem('code_verifier');

    const response = await fetch('https://auth-provider.com/token', {
      method: 'POST',
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      body: new URLSearchParams({
        client_id: 'YOUR_CLIENT_ID',
        grant_type: 'authorization_code',
        code,
        redirect_uri: 'http://localhost:3000/callback',
        code_verifier: verifier,
      }),
    });

    const { access_token } = await response.json();
    await verifyTokenWithBackend(access_token);
    navigate('/dashboard');
  }
}

4. Использование библиотек

Пример с Google OAuth

// Install: npm install @react-oauth/google
import { GoogleOAuthProvider, GoogleLogin } from '@react-oauth/google';

function GoogleAuth() {
  return (
    <GoogleOAuthProvider clientId="YOUR_GOOGLE_CLIENT_ID">
      <GoogleLogin
        onSuccess={({ credential }) => {
          // Отправляем credential на ваш бэкенд для верификации
          fetch('/api/auth/google', {
            method: 'POST',
            body: JSON.stringify({ token: credential })
          });
        }}
        onError={() => console.error('Login Failed')}
      />
    </GoogleOAuthProvider>
  );
}

5. Настройка бэкенда

Ваш сервер должен:

  1. Верифицировать OAuth-токен
  2. Создать JWT для вашего приложения
  3. Вернуть пользовательские данные

Пример маршрута для Express.js:

app.post('/api/auth/google', async (req, res) => {
  const { token } = req.body;
  const client = new OAuth2Client(process.env.GOOGLE_CLIENT_ID);

  const ticket = await client.verifyIdToken({
    idToken: token,
    audience: process.env.GOOGLE_CLIENT_ID,
  });

  const payload = ticket.getPayload();
  const user = await findOrCreateUser(payload);
  const jwt = generateJWT(user);

  res.json({ user, token: jwt });
});

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

  1. Никогда не храните Client Secret в коде фронтенда
  2. Всегда используйте HTTPS
  3. Ограничивайте scope запросов
  4. Реализуйте CSRF-защиту для callback
  5. Проверяйте state параметр

7. Провайдер-специфичные настройки

Для разных провайдеров есть нюансы:

Провайдер Особенности
Google Требует проверку домена
Facebook Нужно указывать версию API
GitHub Позволяет ограничить доступ к организациям
Apple Требует специальную конфигурацию

Резюмируем

настройка OAuth в React требует регистрации приложения у провайдера, реализации PKCE потока для безопасности и интеграции с вашим бэкендом. Для большинства случаев можно использовать готовые библиотеки, но понимание процесса важно для сложных сценариев. Всегда проверяйте токены на сервере и соблюдайте меры безопасности.