JavaRush /Курси /Модуль 4: FastAPI /Типи токенів в OAuth2: Access і Refresh Tokens

Типи токенів в OAuth2: Access і Refresh Tokens

Модуль 4: FastAPI
Рівень 4 , Лекція 1
Відкрита

Тепер ми заглибимось у деталі токенів, які є ключовим механізмом в OAuth2.

Сьогодні поговоримо про Access Tokens і Refresh Tokens — два головні види токенів, що забезпечують доступ і його оновлення.

Чому це важливо? Без них доведеться просити користувача вводити логін і пароль кожні п'ять хвилин. А це, погодьтесь, не дуже весело.

OAuth2 вже не здається чимось надприродним у веб-розробці.

Практично кожен сучасний сервіс — від API вашого улюбленого месенджера до платіжних шлюзів — використовує токени для керування доступом. Використання токенів дозволяє:

  1. Уникнути передачі логіна і пароля з кожним запитом (дякуємо, безпека).
  2. Розмежувати доступ, видавши токени з різним набором дозволів.
  3. Керувати часом життя токенів, щоб обмежити їх «владу» над ресурсами.

Access Tokens: токени для доступу

Access Token — це цифровий ключ, який дає клієнту доступ до захищених ресурсів через API.

Це як перепустка на корпоративну вечірку — пред'явив її на вході, і ти всередині.

Access Token відправляється клієнтом в кожному запиті до API. Зазвичай його додають у заголовок запиту у форматі:


Authorization: Bearer <access_token>

Приклад використання з бібліотекою httpx:


import httpx

access_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6..."
headers = {"Authorization": f"Bearer {access_token}"}

response = httpx.get("https://api.example.com/protected-route", headers=headers)
print(response.json())

Час життя (TTL, Time To Live)

Access Tokens мають обмежений час життя, зазвичай від 5 до 30 хвилин.

Це робиться задля безпеки: навіть якщо токен витече, зловмисник зможе ним скористатися тільки протягом обмеженого часу.

Важливо: після закінчення терміну дії токену сервер буде відхиляти запити з цим токеном, повертаючи помилку на кшталт 401 Unauthorized.


Refresh Tokens: оновлюємо доступ

Якщо Access Token — це перепустка на вечірку, то Refresh Token — це ваш «привілейований статус» для отримання нової перепустки, якщо стара вже не діє. Він використовується для видачі нового Access Token, коли термін дії поточного токену закінчився.

Refresh Tokens мають значно більший час життя (іноді дні або тижні), що робить їх зручним інструментом для автоматичного оновлення сесій користувачів.

Коли закінчується строк дії Access Token, клієнт може відправити Refresh Token на сервер, щоб отримати новий Access Token, не турбуючи користувача. Типовий запит виглядає так:


POST /token/refresh HTTP/1.1
Content-Type: application/json

{
    "refresh_token": "e60efbb7-1bda-4e5b-9aca-..."
}

Відповідь від сервера:


{
    "access_token": "new-access-token-12345",
    "refresh_token": "new-refresh-token-67890"
}

Приклад реалізації Refresh Token у FastAPI


from fastapi.security import OAuth2PasswordRequestForm
from fastapi import FastAPI, HTTPException, Depends
from datetime import datetime, timedelta
from jose import JWTError, jwt

# Конфігурація
SECRET_KEY = "your-secret-key"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
REFRESH_TOKEN_EXPIRE_DAYS = 7

app = FastAPI()

# Модель користувача (спрощена)
fake_users_db = {
    "johndoe": {
        "username": "johndoe",
        "hashed_password": "fakehashedpassword",  # Використовуйте реальне хешування!
    }
}


def create_access_token(data: dict, expires_delta: timedelta):
    to_encode = data.copy()
    expire = datetime.utcnow() + expires_delta
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt


def create_refresh_token(data: dict):
    expires_delta = timedelta(days=REFRESH_TOKEN_EXPIRE_DAYS)
    return create_access_token(data, expires_delta)


@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
    user = fake_users_db.get(form_data.username)
    if not user or user["hashed_password"] != form_data.password:
        raise HTTPException(status_code=400, detail="Incorrect username or password")
    
    # Генерація токенів
    access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = create_access_token({"sub": user["username"]}, access_token_expires)
    refresh_token = create_refresh_token({"sub": user["username"]})
    
    return {"access_token": access_token, "refresh_token": refresh_token, "token_type": "bearer"}


@app.post("/token/refresh")
async def refresh_token(refresh_token: str):
    try:
        payload = jwt.decode(refresh_token, SECRET_KEY, algorithms=[ALGORITHM])
        username = payload.get("sub")
        if username is None:
            raise HTTPException(status_code=401, detail="Invalid refresh token")
        # Створюємо новий Access Token
        access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
        access_token = create_access_token({"sub": username}, access_token_expires)
        return {"access_token": access_token, "token_type": "bearer"}
    except JWTError:
        raise HTTPException(status_code=401, detail="Invalid refresh token")

Як зберігати Refresh Tokens?

Refresh Tokens зазвичай зберігають більш безпечно, ніж Access Tokens. Добра практика:

  • На клієнті: зберігати Refresh Token в HttpOnly cookie (невидимий для JavaScript, щоб захистити від XSS-атак).
  • На сервері: можна зберігати Refresh Token у базі даних для перевірки валідності (хоча це не обов'язково).

Ризики і захист токенів

Ризики
  1. Витік токена: якщо токен потрапить в чужі руки, зловмисник зможе отримати доступ до ваших ресурсів.
  2. Повторне використання Refresh Token: якщо зловмисник вкраде Refresh Token, він зможе генерувати нові Access Tokens.
Заходи захисту
  1. HTTPs: завжди використовуйте HTTPS для передачі токенів.
  2. HttpOnly Cookies: зберігайте токени в захищених cookie.
  3. Короткий час життя Access Token: зменшуйте TTL для Access Tokens, щоб мінімізувати потенційну шкоду від їх витоку.
  4. Ротація Refresh Token: створюйте новий Refresh Token щоразу, коли створюється Access Token, щоб старий Refresh Token ставав недійсним.

Приклад використання токенів у реальних додатках

Припустимо, ви робите додаток для замовлення піци через FastAPI.

Користувач заходить у додаток, логіниться, і сервер видає Access і Refresh Tokens.

Access Token дозволяє йому замовляти піцу, а Refresh Token забезпечує автоматичне підзаряджання Access Token, поки користувач насолоджується своїм замовленням.

Тепер уявіть, що токени вкрали. Якщо ви налаштували механізм ротації і короткий час життя, зловмисники не зможуть використовувати вкрадені токени для подальших запитів. Бінго — ви врятували чиїсь «піца-день»!


На цьому все на сьогодні. У наступній лекції ми заглибимось у JWT і побачимо, як їх використовують для генерації і верифікації токенів.

Будьте готові, буде весело і цікаво!

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ