Files
marquiz-metrics/app/api/v1/endpoints/auth.py
13orlov 8047844ad4
Some checks failed
continuous-integration/drone/push Build is failing
feat(auth): Add endpoint to get user info by token
2025-08-24 22:19:33 +01:00

83 lines
3.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from fastapi import APIRouter, HTTPException, status
from fastapi.responses import JSONResponse
import httpx
from loguru import logger
from app.core.config import settings
from app.api.v1.schemas.auth import TokenRequest, TokenResponse
router = APIRouter()
YANDEX_TOKEN_URL = "https://oauth.yandex.ru/token"
@router.post("/token", response_model=TokenResponse, summary="Обмен кода авторизации на токен доступа")
async def exchange_code_for_token(request: TokenRequest):
"""
Принимает временный 'code' от фронтенда, обменивает его на 'access_token'
у Яндекса и возвращает токен клиенту.
"""
logger.info("Attempting to exchange authorization code for an access token.")
payload = {
'grant_type': 'authorization_code',
'code': request.code,
'client_id': settings.YANDEX_CLIENT_ID,
'client_secret': settings.YANDEX_CLIENT_SECRET
}
try:
async with httpx.AsyncClient() as client:
response = await client.post(YANDEX_TOKEN_URL, data=payload)
response.raise_for_status() # Вызовет ошибку для статусов 4xx/5xx
token_data = response.json()
logger.success("Successfully received access token from Yandex.")
# Возвращаем только нужные нам поля
return TokenResponse(
access_token=token_data.get("access_token"),
token_type=token_data.get("token_type", "bearer")
)
except httpx.HTTPStatusError as e:
error_details = e.response.json()
logger.error(f"Yandex OAuth error: {e.response.status_code} - {error_details}")
raise HTTPException(
status_code=e.response.status_code,
detail=f"Yandex OAuth error: {error_details.get('error_description', 'Unknown error')}"
)
except Exception as e:
logger.opt(exception=True).error("An unexpected error occurred during token exchange.")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="An internal server error occurred."
)
# Получает информацию о пользователе Яндекса
@router.get("/userinfo", response_model=UserInfoResponse, summary="Получение информации о пользователе")
async def get_user_info(credentials: Annotated[HTTPAuthorizationCredentials, Depends(bearer_scheme)]):
token = credentials.credentials
headers = {'Authorization': f'OAuth {token}'}
try:
async with httpx.AsyncClient() as client:
response = await client.get(YANDEX_USERINFO_URL, headers=headers)
response.raise_for_status()
user_data = response.json()
logger.info(f"Fetched user info for login: {user_data.get('login')}")
return UserInfoResponse(**user_data)
except httpx.HTTPStatusError as e:
error_details = e.response.json()
logger.error(f"Yandex UserInfo API error: {e.response.status_code} - {error_details}")
raise HTTPException(
status_code=e.response.status_code,
detail=f"Yandex API Error: {error_details.get('error_description', 'Unknown error')}"
)
except Exception:
logger.opt(exception=True).error("An unexpected error occurred while fetching user info.")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="An internal server error occurred."
)