# MsaAuthService `msaauthservice.h`, `msaauthservice.cpp` Вход через аккаунт Microsoft, то есть с лицензионной копией игры. Цепочка такая же, как у официального лаунчера: OAuth2 → Xbox Live → XSTS → Minecraft Services → проверка лицензии → профиль. Результат приходит в `AuthResult` из [AuthService](AuthService.md). Окно входа сервис не показывает. Страницу Microsoft открывает [MicrosoftLoginDialog](../qml/MicrosoftLoginDialog.md), а сервис даёт адрес этой страницы и умеет узнать адрес возврата. Класс компилируется всегда, но без Qt WebEngine показать страницу нечем, и [LauncherBackend](LauncherBackend.md) сразу отвечает ошибкой. ## Чьё это приложение Сейчас используется `client_id` официального лаунчера Mojang (`00000000402b5328`). Это старое приложение Live Connect, поэтому и адреса от `login.live.com`: | Константа | Значение | |-----------|----------| | `kAuthorizeUrl` | `https://login.live.com/oauth20_authorize.srf` | | `kTokenUrl` | `https://login.live.com/oauth20_token.srf` | | `kRedirectUri` | `https://login.live.com/oauth20_desktop.srf` | | `kScope` | `service::user.auth.xboxlive.com::MBI_SSL` | | `kRpsTicketPrefix` | пусто | Это временное решение. Чтобы перейти на своё приложение в Azure (с включённым «Allow public client flows»), меняются эти шесть констант. Что именно подставить, написано в комментарии в начале `msaauthservice.cpp`. Главное, что легко пропустить: у нового приложения в `RpsTicket` нужна приставка `d=`. `clientId()` отдаёт этот id наружу. Бэкенд подставляет его в `${clientid}`, потому что официальный лаунчер передаёт туда id приложения, а не случайный токен. ## Окно входа `authorizationUrl()` — адрес страницы входа с `client_id`, `response_type=code`, `redirect_uri`, `scope` и `prompt=select_account`. Последний параметр нужен, чтобы при повторном входе можно было выбрать другой аккаунт. `matchRedirect(url, &code, &error)` возвращает `true`, только если хост и путь совпадают с `kRedirectUri`. Код или ошибка ищутся сначала в query, потом во фрагменте. В `error` попадает `error_description`, а если его нет, то `error`. Эта проверка сделана в C++, а не в QML, чтобы она всегда совпадала с тем адресом, который сервис сам передаёт в `redirect_uri`. ## Цепочка `loginWithCode(code, callback)` меняет код на токен (`grant_type=authorization_code`). `loginWithRefreshToken(refreshToken, callback)` делает то же по refresh-токену. Дальше путь общий: 1. **Токен Microsoft.** Форма на `kTokenUrl`. Из ответа берутся `access_token` и `refresh_token`. 2. **Xbox Live.** `user.auth.xboxlive.com/user/authenticate`, `RpsTicket` = приставка + токен Microsoft. 3. **XSTS.** `xsts.auth.xboxlive.com/xsts/authorize` для `rp://api.minecraftservices.com/`. При 401 код `XErr` переводится в понятный текст: нет профиля Xbox, страна не поддерживается, нужна проверка возраста, детский аккаунт без разрешения взрослого. Отсюда же берутся `uhs` и `xid` (он станет `xuid`). 4. **Minecraft Services.** `login_with_xbox` с `XBL3.0 x=;`. В ответе токен Minecraft и `expires_in`, обычно сутки; от него считается `expiresAt`. 5. **Лицензия.** `entitlements/mcstore`. Результат только запоминается и сам вход не останавливает. 6. **Профиль.** `minecraft/profile`. Ответы 404 и 401 означают, что профиля нет: выставляется `licenseMissing`. Текст ошибки зависит от шага 5. Если игра куплена, значит, игрок ещё не выбрал ник. Если не куплена, значит, лицензии нет. `userType` = `msa`, `clientToken` = id приложения. Каждый шаг испускает `progress(message)` до отправки запроса. Таймаут на каждый запрос 20 секунд, повторных попыток нет. Сетевая ошибка и отказ сервера дают разные тексты. Refresh-токен Microsoft живёт намного дольше суточного токена Minecraft, поэтому при обычном запуске окно входа не нужно: бэкенд вызывает `loginWithRefreshToken()`. Если Microsoft не вернул новый refresh-токен, бэкенд оставляет старый. ## Колбэки Колбэк вызывается один раз в GUI-потоке. Шаги вызываются из колбэков предыдущих. Если удалить сервис посреди цепочки, она оборвётся вместе с менеджером сети, и колбэк не вызовется. --- При создании этого документа использовался ИИ.