Вход по QR-коду — Device Authorization Flow

Device Authorization Flow позволяет войти в приложение на одном устройстве, подтвердив вход в REGOS Auth на другом. Например, StoreManagement показывает QR-код на компьютере, а пользователь открывает раздел «Вход на другом устройстве» в REGOS Auth на телефоне и нажимает «Сканировать QR-код».

Протокол соответствует OAuth 2.0 Device Authorization Grant, RFC 8628. Сканер внутри REGOS Auth — интерфейс подтверждения этого запроса. Камера работает по HTTPS; изображения обрабатываются на телефоне и не отправляются на сервер. Если камера недоступна, пользователь вводит короткий код вручную.

Подготовка клиента

Администратор должен разрешить приложению Device Authorization и нужные scopes. Public-приложение использует client_id без секрета. Confidential-клиент аутентифицируется через client_secret_basic либо client_secret_post; смешивать эти способы в одном запросе нельзя.

Для последующего входа без телефона запросите offline_access; клиенту должны быть разрешены этот scope и Refresh Token. В Device Flow refresh token выдаётся только при разрешённом offline_access. Без него приложение получает access token с ограниченным сроком действия.

redirect_uri, code_challenge и code_verifier в этом потоке не используются. Если клиент также использует Authorization Code, его существующие redirect URI и PKCE остаются обязательными для того потока.

1. Получить коды

Найдите device_authorization_endpoint в /.well-known/openid-configuration. Discovery также публикует urn:ietf:params:oauth:grant-type:device_code в grant_types_supported, когда этот способ входа включён.

curl -X POST https://auth.regos.uz/oauth/device_authorization \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'client_id=your_client_id' \
  -d 'scope=openid profile offline_access' \
  -d 'device_id=your_installation_id'

scope нужно передать явно. Необязательный device_id — расширение REGOS для идентификации установки приложения. Создайте случайный UUID один раз, сохраните локально и передавайте при последующих входах из этой установки, в том числе при переключении аккаунта. Не используйте модель компьютера, IP или идентификатор телефона, которым подтверждают вход.

Допустима непустая строка до 128 символов без управляющих символов. Сервер убирает пробелы по краям и приводит значение к нижнему регистру. Если параметр отсутствует, сервер создаёт идентификатор сам. В обоих случаях сохраняйте device_id из ответа и используйте его дальше. Пример ответа:

{
  "device_code": "opaque_device_code",
  "user_code": "BCDF-GHJK",
  "verification_uri": "https://auth.regos.uz/oauth/device",
  "verification_uri_complete": "https://auth.regos.uz/oauth/device?user_code=BCDF-GHJK",
  "expires_in": 600,
  "interval": 5,
  "device_id": "your_installation_id"
}

Используйте значения expires_in и interval из ответа, не фиксируйте их в приложении. device_code хранится только в приложении, которое начало вход. Не помещайте его в QR-код, URL, логи или сообщения пользователю.

2. Показать QR-код и короткий код

Создайте QR-код из полного значения verification_uri_complete. Рядом обязательно покажите user_code, оставшееся время и инструкцию: «Откройте REGOS Auth на телефоне → Вход на другом устройстве → Сканировать QR-код». Вместо сканирования пользователь может ввести код вручную в этом же разделе.

Оставьте альтернативу: открыть verification_uri и ввести код вручную. QR может показывать обычное desktop-приложение — браузер на компьютере не требуется.

3. Подтвердить в REGOS Auth

Пользователь входит в REGOS Auth, сканирует QR-код и видит приложение, текущий аккаунт, короткий код и запрашиваемый доступ. Он сверяет код с экраном приложения и подтверждает либо отклоняет вход.

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

4. Дождаться токенов

Приложение, которое начало вход, опрашивает /oauth/token, выдерживая как минимум interval секунд перед первым запросом и между последующими запросами. Не запускайте параллельные опросы одного кода.

curl -X POST https://auth.regos.uz/oauth/token \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'grant_type=urn:ietf:params:oauth:grant-type:device_code' \
  -d 'client_id=your_client_id' \
  -d 'device_code=opaque_device_code'

Пока вход не подтверждён, сервер возвращает HTTP 400 с OAuth-ошибкой. Это ожидаемое состояние протокола:

error Действие приложения
authorization_pending Продолжать опрос с текущим интервалом.
slow_down Увеличить текущий интервал на 5 секунд для всех дальнейших запросов.
access_denied Прекратить опрос: доступ отклонён.
expired_token Прекратить опрос и предложить начать вход заново.
invalid_grant Прекратить опрос: код неверен, использован или выдан другому клиенту.
Остальные OAuth-ошибки Прекратить опрос и обработать ошибку настройки или аутентификации.

При сетевом таймауте увеличивайте интервал, например вдвое. HTTP 429 означает ограничение частоты: учитывайте Retry-After. Не продолжайте опрос после истечения expires_in.

При успехе HTTP 200 содержит access_token, token_type, expires_in, scope и, когда применимо, refresh_token и id_token. В REGOS access token — opaque строка. При openid проверяйте подпись, iss, aud и срок действия ID token. Сверяйте фактически выданные scopes с необходимыми приложению. Прекратите опрос после первого успешного ответа: повторное получение токенов по этому коду запрещено. Если успешный ответ потерян, начните новый вход.

Ответы выдачи кодов и токенов содержат Cache-Control: no-store и Pragma: no-cache.

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

После успешного получения токенов установка уже отображается в разделе «Безопасность → Устройства». Чтобы добавить версию приложения, платформу или push-токен, вызовите POST /api/devices/register с выданным access token и тем же device_id, который вернулся при получении кодов. Для этого нужен scope auth.api.device.register. Регистрация обновит существующее устройство, не создавая второе.

При необходимости GET /api/devices/self с этим access token возвращает идентификатор установки приложения независимо от браузерной cookie. Для метода нужен scope auth.api.device.self. Эти scopes нужны только для соответствующих API; сам вход по QR не требует их.

Для токена Device Flow регистрация с другим device_id отклоняется: API возвращает ok: false и ошибку валидации 9003. Используйте сохранённый идентификатор или получите его через /api/devices/self. Идентификатор не является секретом и сам по себе не предоставляет доступ к аккаунту.

Сессии, обновление и выход

Приложение получает отдельную сессию и собственные токены. Токены телефона в приложение не передаются. Выход из браузерного профиля на телефоне не отзывает выданный приложению offline-доступ. Его можно завершить в «Безопасность → Устройства» или отозвать разрешение приложения.

При обновлении сохраняйте новый refresh token вместо предыдущего. Повторное использование старого refresh token отзывает всю семью токенов. Смена пароля, блокировка пользователя и отзыв доступа прекращают действие соответствующих разрешений. Access tokens проверяются через интроспекцию с учётом отзыва.

При каждом новом входе по коду создаётся отдельное подключение приложения. Подключения одного пользователя с одинаковым device_id отображаются в одной карточке устройства. Действие завершения доступа на устройстве отзывает все его подключения у этого пользователя; другие аккаунты и другие установки не затрагиваются. Повторный вход сохраняет ранее зарегистрированные сведения об установке и действующую push-привязку. Если устройство было отключено, вход по QR не восстанавливает старую push-привязку: для получения уведомлений повторно передайте актуальный push-токен через /api/devices/register.

Лимит активных записей устройств в реестре не отзывает уже выданные токены и подключения приложения. Установка с действующими подключениями остаётся видна в разделе «Устройства», где можно завершить доступ сразу для всех её подключений, даже если запись устройства стала неактивной или была удалена.

Если каждый раз не передавать сохранённый device_id, сервер будет создавать новые идентификаторы и отдельные карточки. Совпадение IP или ОС не используется для объединения устройств.