Подключение второго фактора к собственным веб-сервисам (API)

Статья описывает подключение Simple2FA к собственному веб-приложению заказчика через REST API локального инстанса. Сценарий: приложение само проверяет логин и пароль (первый фактор), затем передаёт пользователя в Simple2FA для подтверждения второго фактора и по возвращении проверяет результат.

Запросы выполняются к бэкенду локального инстанса — адресу, по которому опубликован сервис local-backend (значение LOCAL_URL из .env при установке; в примерах ниже — https://<адрес-бэкенда-локального-инстанса>). Адрес панели администратора для вызовов API не используется.

Используются два метода API локального инстанса:

  • POST /api/initiate-2fa — инициация сессии второго фактора, возвращает ссылку для редиректа пользователя;
  • POST /api/auth/status-external — получение результата аутентификации по идентификатору сессии.

Как это работает

  1. Пользователь вводит логин и пароль в вашем приложении. Приложение проверяет первый фактор своими средствами.
  2. Приложение вызывает /api/initiate-2fa, передавая логин пользователя, URL возврата и свой идентификатор сессии (externalAuthId).
  3. В ответ приходит wizardUrl — приложение перенаправляет браузер пользователя по этой ссылке.
  4. Пользователь подтверждает вход выбранным способом (PUSH, TOTP, Telegram, MAX). Если второй фактор ещё не настроен, визард сначала проведёт активацию.
  5. После подтверждения визард возвращает пользователя на redirectUrl.
  6. Приложение вызывает /api/auth/status-external с тем же externalAuthId и получает статус. Сессия в приложении создаётся только при статусе AUTHENTICATED.

Важно: сам факт возврата пользователя на redirectUrl не является подтверждением успешной аутентификации. Результат всегда проверяется серверным вызовом /api/auth/status-external.

Последовательность подключения второго фактора к веб-приложению через API локального инстанса

Подготовка: создание ресурса в локальном инстансе

В панели администратора локального инстанса перейдите в раздел Ресурсы, нажмите «+ Добавить» и создайте ресурс с протоколом HTTPS. Подробное описание всех полей — в статье Ресурсы; для протокола HTTPS блок «Настройки RADIUS» не отображается.

Основные настройки:

  • Название — произвольное имя вашего приложения. Отображается в журналах и в уведомлениях пользователю при подтверждении входа.
  • ПротоколHTTPS.
  • Порт443.
  • API ключ — генерируется автоматически при сохранении ресурса. После сохранения откройте карточку ресурса и скопируйте значение по ссылке «Скопировать». Ключ передаётся в поле apiKey каждого запроса к API. Храните его на стороне сервера приложения и не передавайте в браузер.

Блок «Пользователи и 2FA»:

  • Автоматическое создание пользователей — если включено, пользователь, которого ещё нет в Simple2FA, будет создан при первом вызове /api/initiate-2fa. Без этой опции для неизвестного логина API вернёт ошибку 404.
  • Группа пользователей по умолчанию — группа, в которую попадают автосозданные пользователи. Если автосоздание включено, а группа не задана, API вернёт ошибку 400.
  • Использовать кеширование сессий и Длительность кеша — после успешного подтверждения второй фактор не запрашивается повторно у той же пары «пользователь + IP» в течение заданного окна. В этом случае /api/initiate-2fa вернёт requires2fa: false.

Логин в запросах должен совпадать с логином пользователя в Simple2FA (созданного вручную, импортированного из каталога или автосозданного).

Шаг 1. Инициация второго фактора

POST /api/initiate-2fa

Параметры запроса (JSON):

  • apiKey — API-ключ ресурса. Обязательный.
  • username — логин пользователя. Обязательный.
  • redirectUrl — URL вашего приложения, на который пользователь вернётся после подтверждения.
  • externalAuthId — идентификатор сессии на стороне вашего приложения. Используется затем для запроса статуса. Рекомендуется генерировать случайное непредсказуемое значение (например, UUID) и хранить его в серверной сессии пользователя.
  • ip — необязательный. IP-адрес клиента определяется автоматически, когда пользователь открывает визард; передавать поле явно не требуется.

Пример запроса:

curl -X POST https://<адрес-бэкенда-локального-инстанса>/api/initiate-2fa \
  -H "Content-Type: application/json" \
  -d '{
    "apiKey": "<API-ключ ресурса>",
    "username": "john.doe",
    "redirectUrl": "https://myapp.example.com/auth/2fa/callback",
    "externalAuthId": "7d6a2d2f-4c5d-4e7d-8b9f-123456789abc"
  }'

Пример ответа:

{
  "requires2fa": true,
  "wizardUrl": "https://<адрес-визарда>/wizard/f7f06d6b-561b-416a-b1f0-008761a9c54f",
  "setupComplete": true,
  "selectedProviderName": "push",
  "isActive": true,
  "configuredMethods": [
    { "id": "push", "modelName": "iPhone 15" },
    { "id": "otp" }
  ]
}

Поля ответа:

  • requires2fa — требуется ли второй фактор для этого пользователя. Если false, второй фактор не запрашивается (для пользователя не включена политика 2FA либо сработало кеширование сессий ресурса) — приложение может завершить вход без редиректа.
  • wizardUrl — ссылка, на которую нужно перенаправить браузер пользователя. Последний сегмент ссылки — токен сессии второго фактора; его можно использовать вместо externalAuthId при запросе статуса (поле authToken).
  • setupComplete — настроен ли у пользователя второй фактор в соответствии с политикой. Если false, по ссылке wizardUrl пользователь сначала пройдёт активацию.
  • selectedProviderName — способ подтверждения по умолчанию.
  • isActive — активна ли учётная запись пользователя в Simple2FA.
  • configuredMethods — список настроенных и разрешённых политикой способов.

Коды ошибок:

  • 400 — не передан username или у ресурса не задана группа по умолчанию.
  • 401 — неверный API-ключ.
  • 402 — нет свободных лицензий для создания пользователя.
  • 404 — пользователь не найден и автосоздание запрещено.
  • 502 — облачный сервис недоступен.

Шаг 2. Редирект пользователя на визард

Приложение отвечает браузеру пользователя редиректом (HTTP 302) на wizardUrl. Пользователь подтверждает вход; по завершении визард перенаправляет его на redirectUrl, указанный на шаге 1.

Обработчик redirectUrl в приложении должен найти externalAuthId в серверной сессии пользователя (cookie) и перейти к шагу 3. Не следует принимать externalAuthId из параметров запроса браузера без сверки с сессией.

Шаг 3. Проверка результата

POST /api/auth/status-external

Параметры запроса (JSON):

  • apiKey — API-ключ ресурса. Обязательный.
  • externalAuthId — идентификатор, переданный на шаге 1;
  • authToken — токен сессии из конца wizardUrl. Альтернатива externalAuthId: достаточно передать одно из двух полей.

Пример запроса:

curl -X POST https://<адрес-бэкенда-локального-инстанса>/api/auth/status-external \
  -H "Content-Type: application/json" \
  -d '{
    "apiKey": "<API-ключ ресурса>",
    "externalAuthId": "7d6a2d2f-4c5d-4e7d-8b9f-123456789abc"
  }'

Пример ответа:

{
  "status": "AUTHENTICATED",
  "redirectUrl": "https://myapp.example.com/auth/2fa/callback",
  "selectedMethod": "push",
  "clientIp": "203.0.113.5",
  "resourceName": "Корпоративный портал"
}

Возможные значения status:

  • PENDING_SETUP — пользователь ещё не настроил второй фактор.
  • PENDING_AUTH — второй фактор настроен, подтверждение ещё не получено.
  • AUTHENTICATED — вход подтверждён. Единственный статус, при котором приложение создаёт сессию пользователя.
  • FAILED — подтверждение отклонено или код введён неверно.
  • EXPIRED — сессия второго фактора истекла. Время жизни сессии задаётся в разделе Глобальные настройки панели администратора.
  • AUTH_EXPIRED — истекло время ожидания подтверждения.
  • UNKNOWN — статус не установлен.

Коды ошибок:

  • 400 — некорректное тело запроса.
  • 401 — неверный API-ключ.
  • 404 — сессия с указанным externalAuthId / authToken не найдена.
  • 502 — облачный сервис недоступен.

Ограничений на число запросов статуса нет. Его можно запрашивать не только после возврата пользователя, но и периодически (polling) — например, если приложение показывает собственный экран ожидания вместо редиректа на визард. Рекомендуемый интервал опроса — 2–3 секунды.

Рекомендации по безопасности

  • API-ключ хранится только на сервере приложения. Вызовы /api/initiate-2fa и /api/auth/status-external выполняются сервер-сервер, не из браузера.
  • externalAuthId — случайное значение, уникальное для каждой попытки входа. Повторное использование не допускается.
  • Проверка статуса обязательна. Редирект на redirectUrl без проверки AUTHENTICATED не является подтверждением.
  • Привязка к сессии. externalAuthId должен быть связан с серверной сессией пользователя, в которой уже пройден первый фактор, чтобы исключить подмену.
  • Сетевой доступ. Доступ к API локального инстанса ограничивается адресами серверов приложения.

Типовые ситуации

  • Пользователь не настроил второй фактор. В ответе initiate-2fa придёт setupComplete: false; визард по wizardUrl проведёт активацию и затем подтверждение входа. Дополнительных действий от приложения не требуется.
  • requires2fa: false. Второй фактор не требуется для этого входа; приложение завершает аутентификацию по первому фактору.
  • Пользователь закрыл визард и вернулся позже. Статус будет EXPIRED или AUTH_EXPIRED; приложение инициирует новую сессию с новым externalAuthId. Время жизни сессии — в глобальных настройках.
  • Ответ 502. Нет связи локального инстанса с облаком. Приложение должно отказать во входе или показать сообщение о временной недоступности — не пропускать пользователя без второго фактора.

Связаться с нами

Укажите свои контактные данные, и мы свяжемся с вами в ближайшее время, чтобы ответить на все ваши вопросы.

Телефон: +7 (495) 120-01-18

Отдел продаж: sales@simple2fa.ru

Поддержка: support@simple2fa.ru

Заполняя форму, вы соглашаетесь на обработку персональных данных.

Телефон: +7 (495) 150-80-59

Отдел продаж: sales@simple2fa.ru

Поддержка: support@simple2fa.ru