Нужно настроить авторизацию в Telegram mini app (генерацию токена). Главная проблема в том, что на бэкенде вычисленный хэш не совпадает с тем, что получен с клиента. Токен бота проверяли, если что. В коде бэкенда оставила только кусок до момента сравнения хэша.
Код на фронте:
export const login = async () => {
try {
const response = await axios.post(
`${API_URL}/auth/telegram`,
{
initData: window.Telegram?.WebApp?.initData,
},
{
headers: {
"Content-Type": "application/json",
},
}
);
localStorage.setItem("token", response.data.access_token);
axios.defaults.headers.common[
"Authorization"
] = `Bearer ${response.data.access_token}`;
return response.data;
} catch (error) {
console.error("Auth error:", error);
}
};
Обработка на бэкенде:
# Секретный ключ и алгоритм для генерации JWT-токена
JWT_SECRET = os.getenv("JWT_SECRET", "тут типа ключ")
JWT_ALGORITHM = "HS256"
# Инициализируем маршрутизатор FastAPI с префиксом /auth
router = APIRouter(prefix="/auth", tags=["Auth"])
# Настраиваем логгер для вывода отладочной информации в systemd
logger = logging.getLogger("uvicorn.error")
# Pydantic-модель для структуры тела запроса
class TelegramInitData(BaseModel):
initData: str # Ожидаем строку формата query_id=...&user=...&auth_date=...&hash=...
def verify_telegram_hash(init_data: str) -> dict[str, str]:
# Парсим строку initData
try:
parsed_data = dict(urllib.parse.parse_qsl(init_data))
except ValueError as e:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Неверный формат initData")
# Проверяем наличие обязательных параметров
required_keys = {'query_id', 'user', 'auth_date', 'hash'}
if not required_keys.issubset(parsed_data.keys()):
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=f"Отсутствуют обязательные параметры: {required_keys - set(parsed_data.keys())}")
# Копируем параметры
params = parsed_data.copy()
# Извлекаем hash
received_hash = params.pop("hash", None)
if not received_hash:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Отсутствует параметр hash")
# Формируем data_check_string
data_check_string = "\n".join(
f"{k}={v}" for k, v in sorted(params.items(), key=itemgetter(0))
)
# Проверяем наличие BOT_TOKEN
if not BOT_TOKEN:
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Ошибка конфигурации: нет BOT_TOKEN")
# Вычисляем secret_key
secret_key = hmac.new(
key=b"WebAppData", msg=BOT_TOKEN.encode(), digestmod=hashlib.sha256
)
# Вычисляем хеш
calculated_hash = hmac.new(
key=secret_key.digest(), msg=data_check_string.encode(), digestmod=hashlib.sha256
).hexdigest()
# Сравниваем хеши
if not hmac.compare_digest(calculated_hash, received_hash):
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Неверные данные аутентификации Telegram")