Реализация SSO (Single Sign-On) для веб-приложения

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

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

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Реализация SSO (Single Sign-On) для веб-приложения
Сложная
~1-2 недели
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1214
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    852
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    823
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    815

Реализация SSO (Single Sign-On) для веб-приложения

SSO — это не просто «войти через Google». Это архитектурное решение, которое затрагивает сессионную модель, безопасность токенов, жизненный цикл аутентификации и интеграцию с корпоративной инфраструктурой. Неправильно спроектированный SSO становится единой точкой отказа — в буквальном смысле: если Identity Provider недоступен, пользователи не могут войти ни в одно приложение.

Протоколы и их применимость

Два актуальных стандарта: SAML 2.0 и OpenID Connect (OIDC). SAML используется в корпоративной среде (Azure AD, Okta, ADFS) — XML-based, громоздкий, но повсеместно поддерживаемый. OIDC — поверх OAuth 2.0, JSON, нативен для веба и мобайла.

Для новых проектов выбор почти всегда OIDC. Исключение — интеграция с legacy enterprise IdP, которые умеют только SAML. В этом случае можно поставить брокер (Keycloak, Dex), который принимает SAML и отдаёт OIDC дальше.

Базовый flow Authorization Code с PKCE:

Browser → /authorize?response_type=code&code_challenge=... → IdP
IdP → callback?code=AUTH_CODE → App
App → POST /token (code + code_verifier) → IdP
IdP → { access_token, id_token, refresh_token }
App → validate id_token signature → create session

PKCE обязателен для публичных клиентов (SPA, мобайл) — защита от перехвата кода авторизации.

Архитектура с несколькими приложениями

В классическом SSO центральная сессия хранится у IdP, приложения держат свои короткоживущие сессии. Механизм Single Logout (SLO) требует отдельного внимания: при выходе из одного приложения IdP должен уведомить остальные через backchannel (server-to-server) или front-channel (редиректы через браузер).

Схема с несколькими Service Provider:

┌──────────┐    ┌──────────┐    ┌──────────┐
│  App A   │    │  App B   │    │  App C   │
└────┬─────┘    └────┬─────┘    └────┬─────┘
     │               │               │
     └───────────────┴───────────────┘
                     │
              ┌──────▼──────┐
              │  IdP        │
              │  (Keycloak) │
              └─────────────┘

Каждое приложение — это client в терминологии IdP с собственными настройками: разрешённые redirect URI, области (scopes), время жизни токена.

Валидация токенов

id_token — это JWT. Валидация обязательна на каждом запросе, если токен передаётся как credentials. Минимальный набор проверок:

from jwt import PyJWT, algorithms
import requests

def validate_id_token(token: str, client_id: str, issuer: str) -> dict:
    # Получаем публичные ключи IdP
    jwks_uri = f"{issuer}/.well-known/openid-configuration"
    config = requests.get(jwks_uri).json()
    jwks = requests.get(config["jwks_uri"]).json()

    header = PyJWT.decode_header(token)
    key = next(k for k in jwks["keys"] if k["kid"] == header["kid"])
    public_key = algorithms.RSAAlgorithm.from_jwk(key)

    claims = PyJWT.decode(
        token,
        public_key,
        algorithms=["RS256"],
        audience=client_id,
        issuer=issuer,
        options={"verify_exp": True}
    )
    return claims

Ключи IdP нужно кешировать с TTL, а не запрашивать при каждом вызове. Одновременно нужна возможность инвалидировать кеш при ротации ключей (событие keys_changed или просто короткий TTL 1–6 часов).

Интеграция в Laravel-приложение

Для Laravel есть пакет socialite для простых провайдеров (Google, GitHub) и league/oauth2-client для кастомных OIDC. Для корпоративного SSO чаще используют aacotroneo/laravel-saml2 или прямую интеграцию через firebase/php-jwt.

Пример OIDC callback:

// routes/web.php
Route::get('/auth/callback', [SsoController::class, 'callback']);

// SsoController.php
public function callback(Request $request): RedirectResponse
{
    $code = $request->input('code');
    $state = $request->input('state');

    // Проверка state против CSRF
    if ($state !== session('oauth_state')) {
        abort(400, 'Invalid state');
    }

    $tokens = $this->oidcClient->exchangeCode($code);
    $claims = $this->oidcClient->validateIdToken($tokens['id_token']);

    $user = User::updateOrCreate(
        ['sub' => $claims['sub']],
        [
            'email'      => $claims['email'],
            'name'       => $claims['name'],
            'provider'   => 'corporate_sso',
            'last_login' => now(),
        ]
    );

    Auth::login($user, remember: true);

    return redirect()->intended('/dashboard');
}

Поле sub (subject) — стабильный идентификатор пользователя от IdP. Email может меняться, sub — нет. Линковать аккаунты нужно по sub, а не по email.

Single Logout

SLO — сложнее, чем кажется. Backchannel logout: IdP отправляет POST на logout endpoint каждого приложения с logout_token (JWT с sid). Приложение находит сессию по sid и уничтожает её.

Route::post('/auth/backchannel-logout', function (Request $request) {
    $logoutToken = $request->input('logout_token');
    $claims = validateLogoutToken($logoutToken); // аналогично id_token

    $sessionId = $claims['sid'];

    // Удаляем все сессии с данным SSO session ID
    DB::table('sessions')
        ->where('sso_session_id', $sessionId)
        ->delete();

    return response()->noContent();
})->middleware('throttle:60,1');

Front-channel logout работает через iframe: IdP открывает logout URL каждого приложения в скрытых фреймах. Надёжность ниже — зависит от браузерной политики (ITP в Safari блокирует сторонние cookies в iframe).

Обработка ошибок и edge cases

  • IdP недоступен: нужен fallback — локальная форма логина с паролем или graceful degradation с сообщением «SSO временно недоступен»
  • Истечение сессии IdP при активной работе: token refresh через refresh_token должен происходить прозрачно, без прерывания пользователя
  • Смена email у пользователя: если IdP обновил email, приложение должно реагировать корректно — не создавать дубль аккаунта
  • Мультитенантность: у разных клиентов могут быть разные IdP. Определяем IdP по домену email или по tenant_id в URL (app.example.com/{tenant}/login)

Сроки реализации

  • Интеграция с одним OIDC провайдером (Google Workspace, Azure AD) — 3–5 дней
  • Собственный IdP на Keycloak с несколькими приложениями — 2–3 недели
  • SAML + OIDC брокер с мультитенантностью — от 4 недель

Основное время уходит не на код, а на конфигурацию IdP, тестирование edge cases аутентификации и настройку SLO. Токены, которые «вроде работают», могут содержать неверные claims или не проходить валидацию в продакшне из-за расхождения часов серверов (claim iat/exp).