OAuth / авторизация

Как подключить вход и регистрацию на сайт через Yandex ID

admin · 29.10.2026 · 6 мин чтения · 22
5.0 (1)

Как подключить вход и регистрацию на сайт через Yandex ID

Вход через Яндекс — один из самых удобных способов авторизации для русскоязычной аудитории. В этой статье пошагово разберём, как подключить «Вход через Яндекс» к вашему сайту: от регистрации приложения в Яндекс OAuth до готового кода на примере Node.js/Express и чистого HTML.


Что такое OAuth 2.0 и как это работает

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

Схема входа через Яндекс:

  1. Пользователь нажимает «Войти через Яндекс».

  2. Мы перенаправляем его на страницу Яндекса (oauth.yandex.ru/authorize).

  3. Яндекс показывает окно согласия на передачу данных.

  4. После подтверждения Яндекс редиректит пользователя обратно на наш сайт с кодом авторизации.

  5. Сервер меняет этот код на access token.

  6. С access token сервер запрашивает данные пользователя (email, имя, аватар).

  7. Создаём/находим пользователя в БД и выдаём ему сессию.

Важно: обмен кода на токен и запрос данных выполняется на сервере, чтобы не раскрывать client_secret.


Шаг 1. Регистрация приложения в Яндексе

  1. Перейдите на https://oauth.yandex.ru/ и войдите в свой аккаунт.

  2. Нажмите «Создать приложение».

  3. Выберите «Для доступа к API или отладки» (или «Веб-сервисы»).

  4. Заполните форму:

    • Название — например, «Мой сайт».

    • Платформа — «Веб-сервисы».

    • Redirect URI — адрес, куда Яндекс вернёт пользователя, например:

      text
      https://example.com/auth/yandex/callback

      Для локальной разработки можно добавить http://localhost:3000/auth/yandex/callback.

  5. В разделе «Доступ к данным» отметьте нужные права. Для входа достаточно:

    • login:email — email пользователя;

    • login:info — имя, фамилия, аватар;

    • login:birthday, login:gender — опционально.

  6. Сохраните приложение. Вы получите:

    • ClientID (публичный идентификатор);

    • Client secret (секретный ключ — не публикуйте его).

Официальная документация: https://yandex.ru/dev/id/doc/ru/


Шаг 2. Настройка проекта

Рассмотрим пример на Node.js + Express. Установите зависимости:

bash
npm init -y
npm install express axios express-session dotenv

Создайте файл .env:

env
YANDEX_CLIENT_ID=ваш_client_id
YANDEX_CLIENT_SECRET=ваш_client_secret
YANDEX_REDIRECT_URI=http://localhost:3000/auth/yandex/callback
SESSION_SECRET=случайная_строка

Для продакшена добавьте .env в .gitignore и используйте менеджер секретов.


Шаг 3. Кнопка входа

На странице входа разместите ссылку на авторизацию Яндекса:

html
<a href="/auth/yandex" class="btn-yandex">
  Войти через Яндекс
</a>

Яндекс разрешает использовать свой логотип. Требования к оформлению: https://yandex.ru/dev/id/doc/ru/rules


Шаг 4. Редирект на Яндекс

Добавляем маршрут, который формирует URL авторизации:

js
// server.js
const express = require('express');
const axios = require('axios');
const session = require('express-session');
require('dotenv').config();

const app = express();

app.use(session({
  secret: process.env.SESSION_SECRET,
  resave: false,
  saveUninitialized: true,
  cookie: { secure: false } // true при HTTPS
}));

// 1. Начало авторизации
app.get('/auth/yandex', (req, res) => {
  // Генерируем state для защиты от CSRF
  const state = Math.random().toString(36).substring(2);
  req.session.oauthState = state;

  const authUrl = 'https://oauth.yandex.ru/authorize?' + new URLSearchParams({
    response_type: 'code',
    client_id: process.env.YANDEX_CLIENT_ID,
    redirect_uri: process.env.YANDEX_REDIRECT_URI,
    state
  }).toString();

  res.redirect(authUrl);
});

Параметр state — обязательная защита от CSRF-атак. Мы сохраняем его в сессии и проверяем на callback.


Шаг 5. Обработка callback

js
// 2. Callback: Яндекс вернул code
app.get('/auth/yandex/callback', async (req, res) => {
  const { code, state, error } = req.query;

  // Проверка ошибки от Яндекса
  if (error) {
    return res.status(400).send('Авторизация отклонена пользователем');
  }

  // Проверка state
  if (!state || state !== req.session.oauthState) {
    return res.status(400).send('Неверный state (возможна CSRF-атака)');
  }
  delete req.session.oauthState;

  try {
    // 3. Меняем code на access_token
    const tokenResponse = await axios.post(
      'https://oauth.yandex.ru/token',
      new URLSearchParams({
        grant_type: 'authorization_code',
        code,
        client_id: process.env.YANDEX_CLIENT_ID,
        client_secret: process.env.YANDEX_CLIENT_SECRET,
        redirect_uri: process.env.YANDEX_REDIRECT_URI
      }),
      { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
    );

    const { access_token } = tokenResponse.data;

    // 4. Получаем данные пользователя
    const userInfo = await axios.get(
      'https://login.yandex.ru/info?format=json',
      { headers: { Authorization: `OAuth ${access_token}` } }
    );

    const { id, default_email, real_name, first_name, last_name, default_avatar_id, is_avatar_empty } = userInfo.data;

    const user = {
      yandexId: id,
      email: default_email,
      name: real_name || `${first_name} ${last_name}`.trim(),
      avatar: is_avatar_empty
        ? null
        : `https://avatars.yandex.net/get-yapic/${default_avatar_id}/islands-200`
    };

    // 5. TODO: найти или создать пользователя в БД
    // const dbUser = await findOrCreateUser(user);

    // Сохраняем в сессии
    req.session.user = user;
    req.session.save(() => res.redirect('/profile'));
  } catch (err) {
    console.error('OAuth error:', err.response?.data || err.message);
    res.status(500).send('Ошибка авторизации');
  }
});

// Страница профиля
app.get('/profile', (req, res) => {
  if (!req.session.user) return res.redirect('/');
  const u = req.session.user;
  res.send(`
    <h1>Привет, ${u.name}!</h1>
    <p>Email: ${u.email}</p>
    ${u.avatar ? `<img src="${u.avatar}" alt="avatar">` : ''}
    <a href="/logout">Выйти</a>
  `);
});

app.get('/logout', (req, res) => {
  req.session.destroy(() => res.redirect('/'));
});

app.listen(3000, () => console.log('Server: http://localhost:3000'));

Шаг 6. Сохранение пользователя в базе данных

Чтобы вход работал как полноценная регистрация, свяжите Яндекс-ID с записью в БД. Пример на Prisma (PostgreSQL):

prisma
model User {
  id         Int      @id @default(autoincrement())
  yandexId   String   @unique
  email      String?  @unique
  name       String?
  avatar     String?
  createdAt  DateTime @default(now())
}

Логика «найти или создать»:

js
async function findOrCreateUser(yandexUser) {
  let user = await prisma.user.findUnique({
    where: { yandexId: yandexUser.yandexId }
  });

  if (!user) {
    user = await prisma.user.create({
      data: {
        yandexId: yandexUser.yandexId,
        email: yandexUser.email,
        name: yandexUser.name,
        avatar: yandexUser.avatar
      }
    });
  }
  return user;
}

Совет: связывайте аккаунты по email осторожно. Если у вас есть обычная регистрация по email, сначала проверьте, нет ли уже пользователя с таким адресом, и предложите «привязать» Яндекс к существующему аккаунту.


Шаг 7. Хранение токена обновления (refresh token)

Access token Яндекса живёт ограниченное время. Если нужен долгий доступ к API (например, Яндекс.Диск, Метрика), запросите refresh_token:

js
// В запросе на authorize добавьте scope
const authUrl = 'https://oauth.yandex.ru/authorize?' + new URLSearchParams({
  response_type: 'code',
  client_id: process.env.YANDEX_CLIENT_ID,
  redirect_uri: process.env.YANDEX_REDIRECT_URI,
  scope: 'login:email login:info',
  state
});

В ответе /token придёт refresh_token. Обновление токена:

js
const refreshed = await axios.post('https://oauth.yandex.ru/token',
  new URLSearchParams({
    grant_type: 'refresh_token',
    refresh_token: storedRefreshToken,
    client_id: process.env.YANDEX_CLIENT_ID,
    client_secret: process.env.YANDEX_CLIENT_SECRET
  }),
  { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
);

Храните refresh-токены в зашифрованном виде и никогда не отдавайте их на клиент.


Шаг 8. Безопасность: чек-лист

  • ✅ Client secret — только на сервере. Не кладите его в фронтенд-код.

  • ✅ Проверяйте state на каждом callback.

  • ✅ Используйте HTTPS в продакшене — Яндекс требует HTTPS для redirect URI (кроме localhost).

  • ✅ Валидируйте redirect URI — Яндекс вернёт пользователя только на адрес из настроек приложения.

  • ✅ Ограничивайте scope — запрашивайте только те права, которые реально нужны.

  • ✅ Rate limiting — защитите эндпоинты /auth/* от перебора.

  • ✅ Логируйте ошибки OAuth, но не пишите в логи токены и коды.


Частые ошибки и их решение

 
 
Ошибка Причина Решение
invalid_client Неверный client_id/client_secret Проверьте .env и настройки приложения
redirect_uri_mismatch URI не совпадает с настройками Добавьте точный URI в кабинете OAuth
invalid_grant Код истёк (живёт ~10 мин) или использован повторно Запрашивайте новый код
403 Forbidden при /info Неверный формат заголовка Используйте Authorization: OAuth <token>, не Bearer

Альтернатива: готовые библиотеки

Если не хочется писать вручную, используйте Passport.js со стратегией passport-yandex:

bash
npm install passport passport-yandex
js
const YandexStrategy = require('passport-yandex').Strategy;

passport.use(new YandexStrategy({
    clientID: process.env.YANDEX_CLIENT_ID,
    clientSecret: process.env.YANDEX_CLIENT_SECRET,
    callbackURL: process.env.YANDEX_REDIRECT_URI
  },
  (accessToken, refreshToken, profile, done) => {
    // profile содержит данные пользователя Яндекса
    return done(null, profile);
  }
));

Документация: https://www.passportjs.org/packages/passport-yandex/


Полезные ссылки


Итог

Подключение входа через Яндекс занимает около часа и состоит из пяти шагов: регистрация приложения → кнопка входа → редирект на Яндекс → обмен кода на токен → сохранение пользователя. Главное — держать client_secret на сервере, проверять state и использовать HTTPS. В результате вы получаете быструю регистрацию без пароля, подтверждённый email и доверие пользователей к знакомому бренду.

 

Автор статьи
admin
7 статей
Профиль

Комментарии 0

Email не публикуется

Комментариев пока нет. Будьте первым!