fix(auth): логировать тело ответа при ошибке OAuth-обмена кода
Живая проверка Google-входа упала с "401 Unauthorized" на /token, но лог показывал только код статуса — тело ответа (там у Google/Яндекс error/ error_description с точной причиной: invalid_client и т.п.) терялось. _raise_for_status_verbose() оборачивает raise_for_status(), добавляя resp.text в сообщение исключения — на все 4 вызова (token+userinfo × google+yandex). Чисто диагностическое изменение, поведение не меняет. Тесты/линт/mypy — ок. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -20,6 +20,18 @@ class OAuthNotConfigured(Exception):
|
||||
"""Провайдер не настроен (пустой client_id/secret в конфиге)."""
|
||||
|
||||
|
||||
def _raise_for_status_verbose(resp: httpx.Response) -> None:
|
||||
"""Как raise_for_status(), но с телом ответа в сообщении — у Google/Яндекс
|
||||
там error/error_description с точной причиной (invalid_client и т.п.),
|
||||
без этого в логе только код статуса, причина не видна."""
|
||||
try:
|
||||
resp.raise_for_status()
|
||||
except httpx.HTTPStatusError as e:
|
||||
raise httpx.HTTPStatusError(
|
||||
f"{e}: {resp.text[:500]}", request=e.request, response=e.response
|
||||
) from e
|
||||
|
||||
|
||||
@dataclass
|
||||
class OAuthUserInfo:
|
||||
provider_id: str
|
||||
@@ -86,14 +98,14 @@ async def exchange_code(provider: str, code: str) -> OAuthUserInfo:
|
||||
"grant_type": "authorization_code",
|
||||
},
|
||||
)
|
||||
token_resp.raise_for_status()
|
||||
_raise_for_status_verbose(token_resp)
|
||||
access_token = token_resp.json()["access_token"]
|
||||
|
||||
info_resp = await client.get(
|
||||
"https://www.googleapis.com/oauth2/v3/userinfo",
|
||||
headers={"Authorization": f"Bearer {access_token}"},
|
||||
)
|
||||
info_resp.raise_for_status()
|
||||
_raise_for_status_verbose(info_resp)
|
||||
info = info_resp.json()
|
||||
email = info["email"]
|
||||
return OAuthUserInfo(
|
||||
@@ -113,7 +125,7 @@ async def exchange_code(provider: str, code: str) -> OAuthUserInfo:
|
||||
"client_secret": client_secret,
|
||||
},
|
||||
)
|
||||
token_resp.raise_for_status()
|
||||
_raise_for_status_verbose(token_resp)
|
||||
access_token = token_resp.json()["access_token"]
|
||||
|
||||
info_resp = await client.get(
|
||||
@@ -121,7 +133,7 @@ async def exchange_code(provider: str, code: str) -> OAuthUserInfo:
|
||||
params={"format": "json"},
|
||||
headers={"Authorization": f"OAuth {access_token}"},
|
||||
)
|
||||
info_resp.raise_for_status()
|
||||
_raise_for_status_verbose(info_resp)
|
||||
info = info_resp.json()
|
||||
|
||||
email = info.get("default_email") or next(iter(info.get("emails") or []), None)
|
||||
|
||||
Reference in New Issue
Block a user