13 KiB
API для разработчиков: Авторизация
Этот файл описывает именно этапы авторизации клиента, то есть как создать новую сессию и как войти в уже существующую.
Здесь четыре базовых метода обычной авторизации:
AuthChallengeCreateAuthSessionSessionChallengeSessionLogin
Логика раздела такая:
- сначала клиент либо начинает создание новой сессии через
deviceKey; - либо начинает вход в уже созданную сессию через
sessionKey; - сервер на первом шаге выдаёт challenge/nonce;
- на втором шаге клиент присылает подписанный ответ;
- сервер сверяет актуальные публичные ключи и только потом проверяет подпись.
Новые поля этого раздела:
sessionType— числовой код типа сессии;clientPlatform— свободная строка платформы клиента.
Текущие поддерживаемые коды sessionType:
1— обычный клиент;50— кошелёк;100— homeserver.
Правило проверки sessionType:
- если в
Solana PDAнет записи дляsessionKey, сервер принимаетsessionType, присланный клиентом; - если запись в
PDAесть,sessionTypeв запросе должен совпадать сsession_typeизPDA; - при несовпадении сервер возвращает
460 / SESSION_TYPE_MISMATCH.
Ниже в документе сначала описан сценарий, а потом зафиксированы точные форматы запросов и ответов.
Отдельно появился новый серверный сценарий pairing через доверенный homeserver/ESP. Он не заменяет обычный вход и описан в:
Dev_Docs/Протоколы/ESP_Pairing_и_режимы_подключения.md
Кратко:
AuthChallenge/CreateAuthSessionиSessionChallenge/SessionLoginостаются каноническими потоками обычной авторизации;- pairing через ESP идёт отдельными
opи только подготавливает безопасное добавление новой сессии; - решение об одобрении pairing принимает любая уже авторизованная доверенная сессия пользователя.
1. Поток авторизации
Поддерживаются два сценария:
- Создание новой сессии:
AuthChallenge->CreateAuthSession - Вход в существующую сессию:
SessionChallenge->SessionLogin
deviceKey используется для создания новой сессии.
sessionKey используется для входа в уже созданную сессию.
sessionKey передаётся и хранится целиком одной строкой, например:
ed25519/BASE64_PUBLIC_KEY
2. AuthChallenge
Запрос
{
"op": "AuthChallenge",
"requestId": "auth-001",
"payload": {
"login": "alice"
}
}
Успешный ответ
{
"op": "AuthChallenge",
"requestId": "auth-001",
"status": 200,
"ok": true,
"payload": {
"authNonce": "8f2f0f71-0b1c-4ab2-8f5d-0bc5d6f6aa11"
}
}
Специфические коды ошибок AuthChallenge
400 / EMPTY_LOGIN— пустойlogin.400 / ALREADY_AUTHED— по текущему соединению уже выполнена авторизация.422 / UNKNOWN_USER— пользователь с такимloginне найден.501 / SOLANA_IMPORT_FAILED— сервер не смог проверить/импортировать пользователя из Solana при lazy-import.500 / INTERNAL_ERROR— непредвиденная внутренняя ошибка сервера, если появится вне штатного сценария.
3. CreateAuthSession
Запрос
{
"op": "CreateAuthSession",
"requestId": "create-001",
"payload": {
"login": "alice",
"sessionKey": "ed25519/BASE64_PUBLIC_KEY",
"storagePwd": "BASE64_OR_APP_SPECIFIC_SECRET",
"timeMs": 1774600000123,
"authNonce": "nonce",
"deviceKey": "BASE64_DEVICE_PUBLIC_KEY",
"signatureB64": "BASE64_SIGNATURE",
"sessionType": 1,
"clientPlatform": "Web",
"clientInfo": "Android 15; Pixel 9"
}
}
Строка для подписи
AUTH_CREATE_SESSION:{login}:{sessionKey}:{storagePwd}:{timeMs}:{authNonce}
Дополнительная проверка ключа
Перед проверкой подписи сервер должен:
- взять актуальный
solana_users.device_key; - сравнить его с
payload.deviceKey; - только потом проверять подпись.
Если ключ не совпадает, сервер возвращает ошибку DEVICE_KEY_NOT_ACTUAL.
На будущее:
- для ротации
device_keyжелательно добавить перепроверку через Solana.
Успешный ответ
{
"op": "CreateAuthSession",
"requestId": "create-001",
"status": 200,
"ok": true,
"payload": {
"sessionId": "sess_7c5e5c4b"
}
}
Специфические коды ошибок CreateAuthSession
400 / NO_STEP1_CONTEXT— для данного соединения не был корректно выполненAuthChallenge.400 / EMPTY_LOGIN— пустойlogin.400 / LOGIN_MISMATCH—loginне совпадает с тем, для кого был выданauthNonce.501 / DB_ERROR_USER_LOOKUP— ошибка БД при повторном чтении пользователя.422 / USER_NOT_FOUND— пользователь не найден.501 / NO_LOGIN— у пользователя на сервере не заполненlogin.400 / EMPTY_STORAGE_PWD— пустойstoragePwd.400 / EMPTY_SESSION_KEY— пустойsessionKey.422 / UNSUPPORTED_KEY_ALGORITHM— префикс алгоритма вsessionKeyилиdeviceKeyне поддерживается текущим сервером.400 / BAD_BASE64— неверный Base64 вsessionKey,deviceKeyилиsignatureB64.400 / EMPTY_SIGNATURE— пустая подпись.400 / TIME_SKEW— время клиента отличается от серверного больше допустимого окна.400 / NO_DEVICE_KEY— у пользователя в БД отсутствуетdeviceKey.400 / EMPTY_AUTH_NONCE— пустойauthNonce.400 / AUTH_NONCE_MISMATCH—authNonceне соответствует значению изAuthChallenge.400 / EMPTY_DEVICE_KEY— в запросе не переданdeviceKey.422 / DEVICE_KEY_NOT_ACTUAL—deviceKeyне совпадает с актуальной версией на сервере.422 / BAD_SIGNATURE— подпись не прошла проверку.460 / SESSION_TYPE_MISMATCH—sessionTypeне совпадает с типом сессии, уже опубликованным для этогоsessionKeyв Solana PDA.501 / SESSION_TYPE_PDA_CHECK_FAILED— сервер не смог проверитьsessionTypeпо Solana PDA.501 / DB_ERROR_SESSION_CREATE— ошибка БД при создании записи активной сессии.500 / INTERNAL_ERROR— непредвиденная внутренняя ошибка сервера.
4. SessionChallenge
Запрос
{
"op": "SessionChallenge",
"requestId": "sch-001",
"payload": {
"sessionId": "sess_7c5e5c4b"
}
}
Успешный ответ
{
"op": "SessionChallenge",
"requestId": "sch-001",
"status": 200,
"ok": true,
"payload": {
"nonce": "0e5bb0f4-c7d8-4efb-b44d-bf31a6126c66"
}
}
Специфические коды ошибок SessionChallenge
400 / EMPTY_SESSION_ID— пустойsessionId.501 / DB_ERROR— ошибка БД при чтении сессии.422 / SESSION_NOT_FOUND— сессия не найдена.500 / INTERNAL_ERROR— непредвиденная внутренняя ошибка сервера.
5. SessionLogin
Запрос
{
"op": "SessionLogin",
"requestId": "slogin-001",
"payload": {
"sessionId": "sess_7c5e5c4b",
"sessionKey": "ed25519/BASE64_PUBLIC_KEY",
"timeMs": 1774600010456,
"signatureB64": "BASE64_SIGNATURE",
"sessionType": 1,
"clientPlatform": "Web",
"clientInfo": "Android 15; Pixel 9"
}
}
Строка для подписи
SESSION_LOGIN:{sessionId}:{timeMs}:{nonce}
Дополнительная проверка ключа
Перед проверкой подписи сервер должен:
- взять
active_sessions.session_key; - сравнить его с
payload.sessionKey; - только потом проверять подпись.
Если ключ не совпадает, сервер возвращает ошибку SESSION_KEY_NOT_ACTUAL.
Успешный ответ
{
"op": "SessionLogin",
"requestId": "slogin-001",
"status": 200,
"ok": true,
"payload": {
"storagePwd": "BASE64_OR_APP_SPECIFIC_SECRET"
}
}
Специфические коды ошибок SessionLogin
400 / EMPTY_SESSION_ID— пустойsessionId.400 / NO_CHALLENGE— передSessionLoginне был успешно выполненSessionChallengeлибо nonce уже истёк.400 / SESSION_ID_MISMATCH— nonce был выдан для другогоsessionId.400 / TIME_SKEW— время клиента отличается от серверного больше допустимого окна.400 / EMPTY_SIGNATURE— пустая подпись.400 / EMPTY_SESSION_KEY— пустойsessionKey.501 / DB_ERROR— ошибка БД при чтении сессии.422 / SESSION_NOT_FOUND— сессия не найдена.501 / NO_SESSION_KEY— у сессии отсутствуетsession_key.422 / SESSION_KEY_NOT_ACTUAL— переданныйsessionKeyне совпадает с актуальной версией на сервере.422 / UNSUPPORTED_KEY_ALGORITHM— префикс алгоритма вsessionKeyне поддерживается текущим сервером.400 / BAD_BASE64— неверный Base64 вsessionKeyилиsignatureB64.422 / BAD_SIGNATURE— подпись не прошла проверку.460 / SESSION_TYPE_MISMATCH—sessionTypeне совпадает с типом сессии, уже опубликованным для этогоsessionKeyв Solana PDA.501 / SESSION_TYPE_PDA_CHECK_FAILED— сервер не смог проверитьsessionTypeпо Solana PDA.501 / DB_ERROR_USER_LOOKUP— ошибка БД при чтении пользователя для этой сессии.422 / USER_NOT_FOUND_FOR_SESSION— пользователь, которому принадлежит сессия, не найден.500 / INTERNAL_ERROR— непредвиденная внутренняя ошибка сервера.
6. Pairing через homeserver/ESP
Новые op, относящиеся к этому сценарию:
UpsertEspPairingSettingsStartEspPairingListEspPairingRequestsApproveEspPairingRejectEspPairingGetEspPairingStatus
В этом потоке:
- новое устройство не владеет
deviceKeyи не проходит обычныйCreateAuthSession; - пароль проверяется сервером только как фильтр;
- решение об одобрении принимает уже авторизованная доверенная сессия пользователя;
- сервер не расшифровывает
encryptedPayloadи не становится источником приватных ключей.
Точные форматы этих операций см. в 03_Session_Management_API.md и в протокольном документе:
Dev_Docs/Протоколы/ESP_Pairing_и_режимы_подключения.md
6. Пример ошибки
{
"op": "SessionLogin",
"requestId": "slogin-001",
"status": 403,
"ok": false,
"error": "SESSION_KEY_NOT_ACTUAL",
"message": "session_key не соответствует актуальной версии",
"payload": {
}
}