Аутентификация
После входа или подтверждения телефона API выдаёт пару токенов. Access-токен подписывает запросы, refresh-токен обменивается на новую пару, когда access-токен истёк.
| Токен | Формат | Срок жизни | Где хранить |
|---|---|---|---|
| access | JWT | 15 минут | в памяти приложения |
| refresh | непрозрачная строка | 30 дней | мобильный клиент — в защищённом хранилище; веб — httpOnly-кука |
Точные сроки приходят в ответе: accessTokenExpiresIn — время жизни access-токена в секундах,
refreshTokenExpiresAt — момент истечения refresh-токена. Ориентируйтесь на них, а не на цифры
из таблицы.
Ответ с токенами
Заголовок раздела «Ответ с токенами»Такой ответ возвращают /v1/auth/verify-phone, /v1/auth/login,
/v1/auth/login/sms и /v1/auth/refresh.
{ "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "accessTokenExpiresIn": 900, "refreshToken": "3f1c2d9e-6b7a-4c55-9a51-0d8e7f6a1b2c.kq3Vb8...", "refreshTokenExpiresAt": "2026-10-24T09:15:00.000Z"}| Поле | Тип | Описание |
|---|---|---|
accessToken |
string | JWT для заголовка Authorization: Bearer |
accessTokenExpiresIn |
integer | через сколько секунд истечёт access-токен |
refreshToken |
string | только мобильным клиентам; веб получает его в куке |
refreshTokenExpiresAt |
string | ISO 8601, только мобильным клиентам |
Веб и мобильные клиенты
Заголовок раздела «Веб и мобильные клиенты»Способ доставки refresh-токена выбирает заголовок X-Client.
Заголовок X-Client не передаётся. Refresh-токен приходит в теле ответа; храните его в Keychain
(iOS) или EncryptedSharedPreferences / Keystore (Android). Для обновления передайте его в теле:
curl -X POST https://api.rekassa.uz/v1/auth/refresh \ -H 'Content-Type: application/json' \ -d '{"refreshToken": "3f1c2d9e-6b7a-4c55-9a51-0d8e7f6a1b2c.kq3Vb8..."}'Передавайте X-Client: web. API ставит refresh-токен в куку, а в теле ответа остаются только
accessToken и accessTokenExpiresIn.
Set-Cookie: rk_refresh=3f1c2d9e-...; Path=/v1/auth; HttpOnly; Secure; SameSite=Strict; Expires=...Кука httpOnly — скрипты страницы её не видят, поэтому XSS не может её украсть. Она ограничена
путём /v1/auth и уходит только на методы аутентификации. Для обновления тело не нужно — важно
отправить куку:
const response = await fetch('https://api.rekassa.uz/v1/auth/refresh', { method: 'POST', credentials: 'include', headers: { 'X-Client': 'web' },})const { accessToken, accessTokenExpiresIn } = await response.json()Обновление токенов
Заголовок раздела «Обновление токенов»POST /v1/auth/refresh выдаёт новую пару и сразу отзывает предъявленный refresh-токен: каждый
refresh-токен одноразовый (ротация). Срок жизни сессии при этом продлевается ещё на 30 дней от
момента обновления.
-
Отправьте запрос с access-токеном. Если API ответил
401с кодомunauthorized, access-токен истёк или недействителен. -
Вызовите
POST /v1/auth/refresh— ровно один раз, даже если в этот момент401получили несколько запросов. -
Сохраните новую пару и повторите исходные запросы с новым access-токеном.
-
Если refresh ответил
401с кодомsession_expired, сессия закончилась: удалите токены и отправьте пользователя на экран входа.
let refreshing = null
/** Все запросы, получившие 401, ждут одно и то же обновление. */function refreshTokens() { refreshing ??= fetch('https://api.rekassa.uz/v1/auth/refresh', { method: 'POST', credentials: 'include', headers: { 'X-Client': 'web' }, }) .then((response) => { if (!response.ok) throw new Error('session_expired') return response.json() }) .finally(() => { refreshing = null }) return refreshing}session_expired возвращается, когда refresh-токен не передан, повреждён, истёк, уже был
использован, сессия завершена или пользователь заблокирован. Браузерному клиенту при этом API
удаляет куку rk_refresh.
POST /v1/auth/logout завершает текущую сессию и удаляет куку. Access-токен в заголовке не нужен —
сессию определяет refresh-токен: мобильный клиент передаёт его в теле, браузер — куку.
curl -X POST https://api.rekassa.uz/v1/auth/logout \ -H 'Content-Type: application/json' \ -d '{"refreshToken": "3f1c2d9e-6b7a-4c55-9a51-0d8e7f6a1b2c.kq3Vb8..."}'Ответ — 204 No Content, в том числе если сессия уже была завершена. Завершить сессию на другом
устройстве можно через DELETE /v1/me/sessions/{id}.
Когда сессии завершаются
Заголовок раздела «Когда сессии завершаются»| Событие | Что происходит |
|---|---|
| Сброс пароля по SMS | завершаются все сессии пользователя |
| Смена пароля в профиле | завершаются все сессии, кроме текущей |
| Смена пароля или блокировка сотрудником портала | завершаются все сессии пользователя |
| Повторное использование refresh-токена | завершается эта сессия |
POST /v1/auth/logout, DELETE /v1/me/sessions/{id} |
завершается указанная сессия |