OAuth, Refresh Token и боевое тестирование
Гусинец Евгений
В первых двух частях мы разобрали основы и популярные механизмы (Session Token, JWT). Теперь переходим к продвинутому уровню: OAuth и Refresh Token – тем инструментам, которые делают авторизацию одновременно удобной для пользователя и головной болью для тестировщика
OAuth Access Token: когда вход через "чужих"
OAuth – это протокол, который позволяет приложению получить доступ к данным пользователя без передачи пароля. Классический пример: "Войти через Google", "Войти через GitHub".
Упрощенный flow (Authorization Code):
1. Пользователь нажимает "Войти через Google".
2. Приложение перенаправляет его на страницу Google.
3. Google спрашивает: "Приложение X хочет доступ к вашему email. Разрешить?"
4. Пользователь соглашается.
5. Google редиректит обратно в приложение с authorization code.
6. Приложение обменивает code на access token.
7. Теперь приложение может делать запросы к Google API от имени пользователя.
Что проверять QA:
· Redirect URI корректный и совпадает с зарегистрированным в OAuth-провайдере (иначе CORS errors).
· После успешной авторизации приложение получает access token.
· Access token дает доступ только к запрошенным scope (например, только email, но не календарь).
· Токен истекает через заявленное время (обычно 1-2 часа).
· При истечении API провайдера возвращает 401.
Типичные грабли:
· CORS errors: redirect_uri не в whitelist у провайдера.
· Invalid scope: запросили больше прав, чем разрешено.
· Token revoked: пользователь отозвал доступ в настройках своего аккаунта Google/Facebook – токен перестает работать мгновенно.
Refresh Token: как не выкидывать пользователя каждые 15 минут
Access Token обычно живет недолго (15 минут – стандарт для безопасности). Но заставлять пользователя логиниться заново каждые 15 минут – плохая идея.
Решение: Refresh Token — долгоживущий токен (дни, недели), который используется только для получения нового access token. Он не светится в обычных API-запросах и хранится максимально безопасно (httpOnly cookie или secure storage).
Как это работает:
1. При логине сервер выдает два токена: access_token (TTL: 15 мин) и refresh_token (TTL: 7 дней).
2. Клиент работает с API через access_token.
3. Когда access_token истекает, клиент отправляет refresh_token на специальный endpoint /auth/refresh.
4. Сервер проверяет refresh token и выдает новый access_token (а иногда и новый refresh_token – это называется rotation).
5. Клиент продолжает работать с новым access token.
Что проверять QA:
· При логине выдаются оба токена.
· Access token работает, пока не истек.
· После истечения access token – 401.
· Refresh token позволяет получить новый access token.
· Старый refresh token инвалидируется после использования (rotation– защита от replay attacks).
· Refresh token не работает после logout.
· Refresh token не работает после смены пароля.
· Нельзя использовать refresh token вместо access token для обычных API-запросов (должен вернуться 401/403).
Пример (упрощенно):
# Логин
POST /auth/login
{ "username": "user", "password": "pass" }
→ Response:
{
"access_token": "eyJhbG...", // TTL: 15 мин
"refresh_token": "dGhpc2lz...", // TTL: 7 дней
"expires_in": 900
}
# Access token истек, обновляем
POST /auth/refresh
{ "refresh_token": "dGhpc2lz..." }
→ Response:
{
"access_token": "eyJNEW...", // новый
"refresh_token": "NEW_REFRESH", // новый (rotation)
"expires_in": 900
}
Когда что использовать: шпаргалка для QA

Автоматизация: как не хардкодить токены в тестах
В Postman:
Используйте Pre-request Script для автоматического получения токена перед запросом:
// Pre-request Script в Collection
pm.sendRequest({
url: 'https://api.example.com/login',
method: 'POST',
header: { 'Content-Type': 'application/json' },
body: {
mode: 'raw',
raw: JSON.stringify({ username: 'user', password: 'pass' })
}
}, function (err, response) {
let token = response.json().access_token;
pm.environment.set("authToken", token);
});
// В Authorization секции запроса:
// Type: Bearer Token
// Token: {{authToken}}
В автотестах (пример для RestAssured):
// Получаем токен
String token = given()
.contentType("application/json")
.body("{\"username\":\"user\", \"password\":\"pass\"}")
.when()
.post("/auth/login")
.then()
.statusCode(200)
.extract().path("access_token");
// Используем в запросах
given()
.header("Authorization", "Bearer " + token)
.when()
.get("/api/profile")
.then()
.statusCode(200);
Troubleshooting: Топ-4 проблемы и как их чинить
Проблема 1: "401 Unauthorized при валидном токене"
Причины:
· Время на сервере/клиенте расходится → JWT поле exp считается истекшим.
· Токен получен для другого окружения (dev токен на stage).
· Токен передан неправильно (забыли "Bearer " или лишний пробел).
Как найти:
# Декодировать JWT и проверить exp
echo "eyJ1c2VyX2lkIjoxMjN9" | base64 -d
# Посмотреть на "exp" – это Unix timestamp
# Проверить текущее время сервера
date +%s
# Сравнить с curl verbose
curl -v -H "Authorization: Bearer <token>" https://api.example.com
Как решить:
· Синхронизировать системное время (NTP).
· Использовать правильные токены для окружения.
· Проверить формат: строго Bearer <token> с одним пробелом.
Проблема 2: "Токен работает в Postman, но не в автотестах"
Причины:
· В Postman используется переменная окружения, а в тестах – хардкод устаревшего токена.
· Разные окружения (Postman на dev, тесты на stage).
· Cookie не передаются автоматически в тестовом фреймворке.
Как решить:
· В автотестах получать токен динамически перед каждым прогоном.
· Использовать одинаковые конфиги окружения.
· Если используете Session Cookie – явно управляйте Cookie Jar в тестах.
Проблема 3: "Intermittent failures – токен истекает в середине теста"
Причины:
· Тест долго выполняется (например, E2E), access token имеет короткий TTL (5-15 мин).
Как решить:
· Использовать Refresh Token в тестах для обновления access token.
· Получать новый токен перед каждым критичным шагом.
· Для тестового окружения увеличить TTL (после согласования с командой).
Проблема 4: "CORS errors при OAuth flow"
Причины:
· Redirect URI не совпадает с зарегистрированным в OAuth-провайдере.
· Фронтенд пытается сделать запрос напрямую к провайдеру (нарушение CORS).
Как решить:
· Проверить whitelist redirect URI в настройках OAuth-приложения.
· OAuth flow должен идти через backend, а не с фронтенда напрямую.
Заключение
Теперь у вас есть полная карта токенов авторизации – от простого API Key до сложных OAuth-сценариев с rotation refresh token. Вы знаете, где искать баги, как автоматизировать проверки и что делать, когда всё сломалось.
Применяйте эти знания на практике. Ломайте системы правильно – так, чтобы находить проблемы до того, как их найдут пользователи.
___________________________________________________________________________
Автор: Евгений Гусинец Канал: QA❤️4Life Группа в ТГ: QA mistakes
___________________________________________________________________________