Что происходит с Access Token при изменение Refresh Token?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Взаимоотношение Access Token и Refresh Token
Это часто задаваемый вопрос на собеседованиях. Важно понимать, что Access Token и Refresh Token независимы друг от друга.
Сценарий: Пользователь обновляет Refresh Token
Когда пользователь логинится, сервер выдаёт пару токенов:
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
"refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
"expires_in": 900,
"token_type": "Bearer"
}
Что происходит с Access Token
Ответ: НИЧЕГО НЕ ПРОИСХОДИТ. Access Token остаётся неизменным, пока не истечёт срок его действия.
Почему они независимы?
-
Разные сроки жизни
- Access Token: 15 минут (короткий)
- Refresh Token: 30 дней или больше (длинный)
-
Разные предназначения
- Access Token: используется в каждом запросе для аутентификации
- Refresh Token: используется ТОЛЬКО для получения нового Access Token
-
Разные место хранения
- Access Token: в памяти или localStorage (фронтенд)
- Refresh Token: в httpOnly cookie или защищённом хранилище
Пример из кода (FastAPI + JWT)
from fastapi import FastAPI, Depends
from jose import JWTError, jwt
from datetime import datetime, timedelta, timezone
app = FastAPI()
# Конфиги
ACCESS_TOKEN_EXPIRE_MINUTES = 15
REFRESH_TOKEN_EXPIRE_DAYS = 30
SECRET_KEY = "your-secret-key"
def create_access_token(data: dict) -> str:
to_encode = data.copy()
expire = datetime.now(timezone.utc) + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
to_encode["exp"] = expire
to_encode["type"] = "access"
encoded = jwt.encode(to_encode, SECRET_KEY, algorithm="HS256")
return encoded
def create_refresh_token(data: dict) -> str:
to_encode = data.copy()
expire = datetime.now(timezone.utc) + timedelta(days=REFRESH_TOKEN_EXPIRE_DAYS)
to_encode["exp"] = expire
to_encode["type"] = "refresh"
encoded = jwt.encode(to_encode, SECRET_KEY, algorithm="HS256")
return encoded
@app.post("/login")
async def login(username: str, password: str):
# Проверяем учётные данные
if verify_credentials(username, password):
user_id = get_user_id(username)
access_token = create_access_token({"sub": user_id})
refresh_token = create_refresh_token({"sub": user_id})
return {
"access_token": access_token,
"refresh_token": refresh_token,
"token_type": "Bearer"
}
@app.post("/refresh")
async def refresh(refresh_token: str):
try:
payload = jwt.decode(refresh_token, SECRET_KEY, algorithms=["HS256"])
if payload.get("type") != "refresh":
raise JWTError("Invalid token type")
user_id = payload.get("sub")
# ВАЖНО: старый Access Token остаётся в памяти клиента
# Мы создаём НОВЫЙ Access Token
new_access_token = create_access_token({"sub": user_id})
return {
"access_token": new_access_token,
"token_type": "Bearer"
}
except JWTError:
raise HTTPException(status_code=401, detail="Invalid refresh token")
Жизненный цикл токенов
Временная шкала:
0 мин — Пользователь логинится
→ Выдан Access Token (истекает через 15 мин)
→ Выдан Refresh Token (истекает через 30 дней)
14 мин — Клиент делает запрос с Access Token
→ Запрос успешен
→ Access Token НЕ изменяется
16 мин — Access Token истёк
→ Клиент отправляет Refresh Token на /refresh
→ Сервер создаёт НОВЫЙ Access Token (срок 15 мин)
→ Старый Access Token уже в памяти, его просто не используем
→ Refresh Token может остаться прежним или обновиться (зависит от реализации)
30 дней — Refresh Token истёк
→ Клиент должен снова залогиниться
Что может измениться?
✅ Можно обновить Refresh Token одновременно с Access Token (rotation strategy)
@app.post("/refresh")
async def refresh(refresh_token: str):
payload = jwt.decode(refresh_token, SECRET_KEY, algorithms=["HS256"])
user_id = payload.get("sub")
# Выдаём оба новых токена
new_access_token = create_access_token({"sub": user_id})
new_refresh_token = create_refresh_token({"sub": user_id})
# Опционально: инвалидируем старый refresh token в БД
invalidate_refresh_token(refresh_token)
return {
"access_token": new_access_token,
"refresh_token": new_refresh_token,
"token_type": "Bearer"
}
Частые ошибки разработчиков
❌ Инвалидировать Access Token при обновлении Refresh Token ❌ Хранить Refresh Token в localStorage ❌ Выдавать один токен вместо двух ❌ Не проверять тип токена (access vs refresh)
✅ Хранить Refresh Token в httpOnly cookie ✅ Проверять срок действия токенов ✅ Реализовать rotation (обновление refresh token) ✅ Добавить механизм blacklist для инвалидации
Итоговый ответ
При изменении (обновлении) Refresh Token с Access Token обычно ничего не происходит — он продолжает работать до истечения срока. Однако в некоторых реализациях (rotation strategy) оба токена обновляются одновременно.