Разработка Social Login агрегации (множество провайдеров) на сайте

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Разработка Social Login агрегации (множество провайдеров) на сайте
Средний
~3-5 дней
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1364
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1253
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    960
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1191
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    933
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Разработка веб-сайта для компании ФИКСПЕР
    950

Агрегация социальных логинов (Multiple OAuth Providers)

Интеграция входа через несколько провайдеров — это не просто кнопки на странице. Реальная техническая сложность: пользователь регистрируется через Google, а через месяц пытается войти через GitHub с тем же email — нужно связать аккаунты, не потерять сессию и не создать дубликат. Если ошибиться, получите конфликты данных или сброс пароля. По статистике, 30% новых пользователей бросают регистрацию, если нет возможности войти через соцсеть, а 90% предпочитают именно social login. Мы решаем эту задачу под ключ на стеке Auth.js + Prisma + PostgreSQL уже более 10 лет, и за это время накопили 100+ успешных проектов. Гарантируем бесшовное связывание и полную сохранность данных. В отличие от готовых решений вроде Clerk, которые стоят от $0.25 за MAU, наш подход даёт полный контроль над данными и конфигурацией, экономя до $5000 в год на крупных проектах. По сравнению с Firebase, Auth.js позволяет сэкономить до $3000 в год при 100 000 активных пользователей.

Связывание аккаунтов по email с помощью колбэка signIn

Связывание аккаунтов — ключевая проблема OAuth-агрегации. Реализуем через колбэк signIn в Auth.js: проверяем существующего пользователя по email и привязываем новый провайдер к его аккаунту. Если провайдер уже привязан — ничего не делаем. Получаем единую таблицу Account с unique-constraint на пару [provider, providerAccountId]. Вот как это выглядит в коде:

// auth.ts (Auth.js v5)
import NextAuth from 'next-auth';
import Google from 'next-auth/providers/google';
import GitHub from 'next-auth/providers/github';
import Apple from 'next-auth/providers/apple';
import MicrosoftEntraID from 'next-auth/providers/microsoft-entra-id';

export const { handlers, auth, signIn, signOut } = NextAuth({
  providers: [
    Google({
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    }),
    GitHub({
      clientId: process.env.GITHUB_CLIENT_ID!,
      clientSecret: process.env.GITHUB_CLIENT_SECRET!,
    }),
    Apple({
      clientId: process.env.APPLE_ID!,
      clientSecret: process.env.APPLE_SECRET!, // JWT из .p8 ключа
    }),
    MicrosoftEntraID({
      clientId: process.env.AZURE_AD_CLIENT_ID!,
      clientSecret: process.env.AZURE_AD_CLIENT_SECRET!,
      tenantId: process.env.AZURE_AD_TENANT_ID!, // или 'common' для всех
    }),
  ],

  callbacks: {
    async signIn({ user, account, profile }) {
      // Автоматическое связывание по email
      if (user.email) {
        const existingUser = await db.user.findUnique({
          where: { email: user.email }
        });

        if (existingUser) {
          const existingAccount = await db.account.findFirst({
            where: {
              userId: existingUser.id,
              provider: account!.provider,
            }
          });

          if (!existingAccount) {
            await db.account.create({
              data: {
                userId: existingUser.id,
                provider: account!.provider,
                providerAccountId: account!.providerAccountId,
                type: account!.type,
                access_token: account!.access_token,
                refresh_token: account!.refresh_token,
                expires_at: account!.expires_at,
              }
            });
          }
          return true;
        }
      }
      return true;
    },

    async session({ session, token }) {
      if (token.sub) {
        session.user.id = token.sub;
      }
      return session;
    },
  },

  adapter: PrismaAdapter(db),
});

Prisma Schema: связанные аккаунты

model User {
  id            String    @id @default(cuid())
  email         String    @unique
  name          String?
  image         String?
  createdAt     DateTime  @default(now())
  accounts      Account[]
  sessions      Session[]
}

model Account {
  id                String  @id @default(cuid())
  userId            String
  type              String
  provider          String
  providerAccountId String
  refresh_token     String? @db.Text
  access_token      String? @db.Text
  expires_at        Int?
  token_type        String?
  scope             String?
  id_token          String? @db.Text

  user User @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@unique([provider, providerAccountId])
}

UI: кнопки провайдеров

// components/SocialLoginButtons.tsx
'use client';
import { signIn } from 'next-auth/react';

const PROVIDERS = [
  {
    id: 'google',
    name: 'Google',
    icon: <GoogleIcon />,
    className: 'bg-white border border-gray-300 hover:bg-gray-50',
  },
  {
    id: 'github',
    name: 'GitHub',
    icon: <GitHubIcon />,
    className: 'bg-gray-900 text-white hover:bg-gray-800',
  },
  {
    id: 'apple',
    name: 'Apple',
    icon: <AppleIcon />,
    className: 'bg-black text-white hover:bg-gray-900',
  },
  {
    id: 'microsoft-entra-id',
    name: 'Microsoft',
    icon: <MicrosoftIcon />,
    className: 'bg-[#00a4ef] text-white hover:bg-[#0090d4]',
  },
] as const;

export function SocialLoginButtons({
  callbackUrl = '/',
  mode = 'login',
}: {
  callbackUrl?: string;
  mode?: 'login' | 'register';
}) {
  return (
    <div className="flex flex-col gap-3">
      {PROVIDERS.map((provider) => (
        <button
          key={provider.id}
          type="button"
          onClick={() => signIn(provider.id, { callbackUrl })}
          className={`flex items-center gap-3 px-4 py-2.5 rounded-lg font-medium ${provider.className}`}
        >
          {provider.icon}
          <span>{mode === 'login' ? 'Войти' : 'Зарегистрироваться'} через {provider.name}</span>
        </button>
      ))}
    </div>
  );
}

Преимущества агрегации: UX, безопасность и конверсия

UX: пользователь меньше кликает, не запоминает пароли. Безопасность: OAuth-токены истекают, refresh токен обновляется автоматически. Конверсия: социальные сети снижают отток на этапе регистрации на 30–50%. Например, один клиент (онлайн-школа) увеличил регистрации на 40% после добавления входа через Apple и Google. Средняя конверсия после внедрения соцлогина растёт на 35%. В сравнении с Clerk, Auth.js даёт в 3 раза больше гибкости кастомизации UI и полный контроль над данными, хотя требует больше ручной настройки. Firebase Auth уступает по количеству провайдеров — всего 5+ OAuth против 10+ у Auth.js.

Сравнение подходов к агрегации

Характеристика Auth.js (NextAuth) Clerk Firebase Auth
Настройка Ручная конфигурация Dashboard + SDK Консоль Firebase
Связывание Колбэк signIn Автоматически с диалогом Кастомная реализация
Поддержка провайдеров 10+ OAuth 10+ + Magic Link 5+ OAuth
Цена Бесплатно (self-hosted) Freemium от $0.25/MAU Freemium до 50k MAU

Мы чаще выбираем Auth.js за гибкость и полный контроль над данными. Clerk подходит для быстрого старта, но сложности с кастомизацией UI.

Сравнение провайдеров по фичам

Провайдер Refresh Token Scope кастомизация Требует верификацию приложения
Google Да Да Да (OAuth consent screen)
GitHub Да (ограничен) Нет Нет
Apple Да (JWT) Да Да (требуется Team ID)
Microsoft Да Да Да (требуется регистрация)

Как обеспечивается безопасность OAuth-токенов?

OAuth 2.0 протокол использует access и refresh токены. Refresh токены позволяют обновлять доступ без повторного ввода данных. Мы реализуем безопасное хранение токенов в базе данных с шифрованием. RFC 6749 определяет стандарт. В нашем стеке Auth.js автоматически обновляет токены через callback. Среднее время жизни access токена — 1 час, refresh — 30 дней. Мы гарантируем, что сессия не прервется. Код адаптера занимает около 50 строк, а время ответа API — менее 200 мс.

Обработка конфликтов при связывании

Если пользователь с email уже существует, но не имеет пароля (зарегистрирован через другой провайдер), мы предлагаем ему войти через существующий провайдер или создать пароль. Если email занят, но пользователь пытается войти через новый провайдер, мы показываем диалог подтверждения: "Это ваш аккаунт? Войдите через старый провайдер для связывания". При отзыве доступа к провайдеру (например, пользователь отозвал разрешение в Google) мы обрабатываем ошибку и предлагаем повторно авторизоваться. Гарантируем, что ни один аккаунт не будет потерян. Храним до 10 провайдеров на один аккаунт.

Процесс работы

  1. Аналитика — определяем список провайдеров, требования к связыванию, поднимаем OAuth credentials в dashboard провайдеров.
  2. Проектирование — схема базы, обработка конфликтов, UX подтверждения.
  3. Реализация — сборка Auth.js, Prisma адаптер, UI кнопок, страница управления аккаунтами.
  4. Тестирование — проверяем связывание, отзыв токенов, edge cases (удаление провайдера, отказ в доступе).
  5. Деплой — настройка env, миграции БД, мониторинг.

Объём работ (deliverables)

  • Настройка OAuth для каждого провайдера (получение credentials, конфигурация callback URL).
  • Реализация логики связывания аккаунтов через колбэк signIn.
  • UI кнопок входа с кастомным дизайном.
  • База данных: схема User и Account с unique-constraint.
  • Документация по развёртыванию и управлению провайдерами.
  • Гарантия корректной работы (бесперебойное связывание, refresh токенов).

Чек-лист типичных ошибок

  • Не настроить refresh токены — пользователь вылетит через час.
  • Не обработать случай, когда email уже занят, но без пароля — нужно предложить войти через существующий провайдер.
  • Забыть про UX при отвязывании последнего провайдера — нельзя оставить пользователя без способа входа.
  • Не проверить, что приложение прошло верификацию у провайдера (например, Google требует одобрения).

Сроки ориентировочно

Базовая интеграция (один провайдер + подключение) — от 1 рабочего дня. Агрегация 4 провайдеров со связыванием и UI — от 2 до 5 дней. Точную оценку дадим после анализа вашего проекта. Стоимость рассчитывается индивидуально в зависимости от сложности.

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

Аутентификация и авторизация: OAuth, JWT, сессии, RBAC, 2FA

На одном проекте токен JWT с ролью admin: false мог быть изменён клиентом на admin: true — сервер принимал его без верификации подписи. Это не гипотетическая атака: несколько файлов в npm-экосистеме имели уязвимость jwt библиотеки, которая игнорировала алгоритм none. Последствия — полный доступ к административным функциям для любого зарегистрированного пользователя.

JWT: что реально нужно знать

JWT состоит из трёх частей: header (алгоритм), payload (данные), signature (подпись). Подпись верифицирует, что payload не изменён. Без проверки подписи — это просто base64-encoded JSON, который любой может подделать.

Ошибки, которые видим в коде регулярно:

Хранение в localStorage. localStorage доступен любому JS на странице — XSS атака читает токен и отправляет на сервер злоумышленника. Access token в памяти (переменная модуля), refresh token в httpOnly cookie — правильная схема.

Долгоживущие access-токены. Access token на 7 дней без возможности отзыва. Утёк — 7 дней доступа. Стандарт: 15 минут для access token, 30 дней для refresh token с ротацией. При каждом использовании refresh token выдаётся новый, старый инвалидируется — если старый кто-то использует повторно, это детектируется как Token Reuse Attack, вся семья токенов отзывается.

Хранение секретных данных в payload. JWT payload не зашифрован, только подписан — его видно в base64. Пароли, платёжные данные, личная информация — не в JWT.

Алгоритм RS256 (асимметричный) предпочтительнее HS256 (симметричный) в микросервисной архитектуре: сервисы могут верифицировать токен публичным ключом, не имея доступа к секрету для его создания.

OAuth 2.0 и OpenID Connect

OAuth 2.0 — протокол делегированной авторизации, не аутентификации. «Войти через Google» — это OpenID Connect поверх OAuth 2.0, который добавляет id_token с данными пользователя.

Authorization Code Flow с PKCE — единственный правильный flow для браузерных SPA и мобильных приложений. Implicit Flow устарел и небезопасен. PKCE (Proof Key for Code Exchange) защищает от перехвата authorization code.

Реализация OAuth сервера: не пишем с нуля. Keycloak (open source, self-hosted), Auth0, Okta — готовые решения. Laravel Passport или Laravel Sanctum для серверных приложений. NextAuth.js для Next.js — поддерживает 50+ провайдеров из коробки.

Для B2B продуктов с корпоративными клиентами — SAML 2.0 SSO. Корпоративные IT-отделы часто требуют его вместо OAuth. @boxyhq/saml-jackson — node.js библиотека для SAML → OAuth2 адаптера.

Сессии vs токены

Сессии хранят состояние на сервере (Redis, database) — сервер может мгновенно отозвать сессию. При масштабировании на несколько инстансов нужен общий store (Redis Cluster). Cookie с session ID — httpOnly, Secure, SameSite=Strict.

Stateless JWT не требуют server-side storage, масштабируются горизонтально. Но отзыв токена до истечения срока — только через blacklist (Redis), что частично убирает преимущество stateless.

Для большинства веб-приложений сессии проще и безопаснее. JWT имеет смысл для API, потребляемых из мобильного приложения, и для микросервисной архитектуры.

RBAC и политики доступа

Role-Based Access Control — у пользователя есть роли, у ролей — права. Простая реализация: user → roles → permissions. Но как только появляется ресурсная авторизация («пользователь может редактировать только свои посты»), RBAC усложняется.

Spatie Laravel Permission — стандарт для Laravel: полиморфные роли и права, кэширование, super-admin через gate. Интеграция с Eloquent: $user->can('edit posts'), $user->hasRole('editor').

ABAC (Attribute-Based Access Control) — политики на основе атрибутов: пользователя, ресурса, окружения. Нужен когда правила доступа сложные: «менеджер может просматривать заказы своего региона, если заказ создан более 24 часов назад». Casbin — популярная cross-language библиотека для ABAC.

ReBAC (Relationship-Based Access Control) — Google Zanzibar model. Доступ определяется графом отношений: «пользователь X является участником команды Y, которая имеет доступ к проекту Z». OpenFGA — open source реализация от Okta.

Двухфакторная аутентификация

TOTP (Time-based One-Time Password, Google Authenticator, Authy) — стандарт. Библиотеки: otplib (Node.js), pragmarx/google2fa (Laravel). QR-код при подключении — base32-encoded secret, которого достаточно для воспроизведения кода при компрометации. Хранить secret в зашифрованном виде.

SMS-верификация — слабее TOTP из-за SIM-swapping атак и ненадёжности доставки SMS. Но пользователи активируют её охотнее. Email OTP — компромисс между безопасностью и UX.

WebAuthn (Passkeys) — биометрия или аппаратный ключ вместо пароля. Хранится private key на устройстве, публичный — на сервере. Нет пароля — нет его утечки. iOS 16+, Android 9+, все современные браузеры поддерживают. @simplewebauthn/server + @simplewebauthn/browser — хорошая библиотека для Node.js реализации.

Backup-коды при подключении 2FA: 10 одноразовых кодов для восстановления доступа если телефон потерян. Хранить хешированными (bcrypt), показывать только один раз при генерации.

Типичные уязвимости

Broken Object Level Authorization (BOLA/IDOR): /api/orders/12345 возвращает заказ без проверки, принадлежит ли он текущему пользователю. Самая распространённая уязвимость API по OWASP. Каждый запрос к ресурсу — проверка через $user->can('view', $order).

Mass Assignment: User::create($request->all()) — пользователь передаёт is_admin: true в теле запроса. Laravel решает через $fillable / $guarded, но часто забывают.

Небезопасный CORS: Access-Control-Allow-Origin: * на API с авторизацией по cookie — credentials не передаются с wildcard origin, но если кто-то сделал Allow-Credentials: true + Allow-Origin: * — это дыра.

Процесс работы

Архитектура авторизации проектируется до начала разработки, не добавляется потом. Выбор между сессиями и JWT, структура ролей и прав, flow для OAuth-провайдеров, план для 2FA. Penetration testing обязателен для продуктов с финансовыми данными или персональными данными пользователей.

Сроки

Базовая аутентификация (email/password + OAuth + JWT/сессии): 1–3 недели. RBAC с детальными политиками доступа: 2–4 недели. 2FA (TOTP + SMS): 1–2 недели. WebAuthn/Passkeys: 2–3 недели. Полная система аутентификации для SaaS с multi-tenancy: 4–8 недель.