К содержимому
Инвойсбокс

Сессия и безопасность

Где держать токен

Токен доступа — это право действовать от имени человека. Он не должен попадать в JavaScript: любой сторонний скрипт на странице, любое расширение браузера и любая XSS-уязвимость немедленно превращаются в кражу доступа.

Рабочая схема:

  1. код обменивает сервер, а не браузер;
  2. полученный токен сервер кладёт в куку с флагами HttpOnly, Secure и SameSite=Lax;
  3. браузер к API напрямую не ходит — запросы идут через ваш сервер, который подставляет токен.
Set-Cookie: sid=<токен>; Path=/; HttpOnly; SameSite=Lax; Secure; Max-Age=43200

Срок жизни сессии выбирает сервис. Удобный вариант — 12 часов со скользящим продлением: пока человек работает, сессия продлевается, а забытая на чужом компьютере закрывается сама.

Если интерфейсу нужно показать, что сессия скоро истечёт, кладите рядом вторую куку без HttpOnly — с одной лишь отметкой времени. Токен при этом остаётся недоступным для скриптов.

Правило «токен не отдают в браузер» общее для всех токенов Инвойсбокс — где им место и где нет, разобрано в безопасности работы с API. Оттуда же берите порядок действий, если токен всё-таки утёк: для токена пользователя он тот же, только вместо смены ключа в кабинете — завершение сессии и отзыв доступа приложению.

Срок жизни и ротация из общих правил относятся к токену интеграции: у него нет владельца-человека, и он живёт месяцами. Сессия пользователя короткая по замыслу, продлевать её ротацией не нужно — истёкшую сессию заменяет новый вход.

Зачем state и PKCE

ЧтоОт чего защищает
stateподмена возврата: без сверки злоумышленник может привести пользователя по своей ссылке с чужим кодом
code_verifier (PKCE)перехват кода: код без исходной строки не обменивается на токен
зарегистрированный redirect_uriугон кода на чужой адрес

Все три проверки обязательны. state и code_verifier держите в sessionStorage — они нужны ровно до возврата и не должны жить дольше вкладки. После обмена удаляйте оба.

Требования к адресу возврата

  • Адрес присылается в службу поддержки вместе с заявкой на идентификатор приложения. Незарегистрированный адрес не сработает.
  • Боевой адрес — только https. Для разработки запросите отдельный адрес и отдельный идентификатор приложения, чтобы боевой не пришлось отдавать на локальную машину.
  • Адрес в запросе авторизации и в обмене кода должен совпадать посимвольно, включая завершающий слэш.
  • Не ведите возврат на страницу, которая сама по себе перенаправляет пользователя дальше по адресу из параметра: так открывается дыра в чужой сайт. Куда вернуть человека после входа, храните у себя — и принимайте только внутренние пути.

Ошибки при входе

Что произошлоЧто видноЧто делать
redirect_uri не зарегистрирован или не совпалвозврат не происходит, Инвойсбокс ID показывает ошибкусверить адрес с тем, что зарегистрирован, вплоть до слэша
state не совпалваша страница возврата не должна продолжать входначать вход заново; повторный переход по старой ссылке — нормальная причина
код уже использованобмен отвечает ошибкойкод одноразовый: повторный обмен не делают, нужен новый вход
токен не принят200 с userId: nullсчитать, что входа нет: очистить куки и предложить войти снова
срок токена истёкобмен или вызов API отвечает отказомэто не ошибка входа: обновите токен по refresh_token, а вход начинайте заново только если и он не подошёл
Инвойсбокс ID недоступенобмен не завершилсяпоказать человеку, что вход временно недоступен, и не создавать пустую сессию

Читайте также

Страница помогла?