Add exc_info=True to OAuth error logging and endpoint-level catch in google_oauth
Agent-Logs-Url: https://github.com/christianlouis/InboxConverge/sessions/8d0fb51a-ede5-4bb7-aad8-3d29a0d3d7d3 Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
0026afe131
commit
e98c81cce4
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
<!-- version list -->
|
<!-- version list -->
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- OAuth Google sign-in: added `exc_info=True` to the catch-all exception handler in `auth_service.py` so the full traceback is always emitted to the log instead of only `str(e)`.
|
||||||
|
- OAuth Google sign-in: added an endpoint-level try/except in the `/auth/google` handler to catch and log any unexpected errors (e.g. database failures) that occurred after the Google token exchange, which previously surfaced as silent 500s.
|
||||||
|
|
||||||
## v0.8.0 (2026-05-03)
|
## v0.8.0 (2026-05-03)
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|||||||
@@ -187,88 +187,102 @@ async def google_oauth(
|
|||||||
auth_request.redirect_uri,
|
auth_request.redirect_uri,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Get user info from Google
|
try:
|
||||||
user_info = await oauth_service.get_google_user_info(
|
# Get user info from Google
|
||||||
code=auth_request.code, redirect_uri=auth_request.redirect_uri
|
user_info = await oauth_service.get_google_user_info(
|
||||||
)
|
code=auth_request.code, redirect_uri=auth_request.redirect_uri
|
||||||
|
|
||||||
if not user_info.get("verified_email"):
|
|
||||||
OAUTH_CALLBACKS_TOTAL.labels(provider="google", status="error").inc()
|
|
||||||
logger.warning(
|
|
||||||
"OAuth [Google sign-in]: rejecting unverified email=%s",
|
|
||||||
user_info.get("email"),
|
|
||||||
)
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_400_BAD_REQUEST,
|
|
||||||
detail="Email not verified with Google",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
email = user_info["email"]
|
if not user_info.get("verified_email"):
|
||||||
google_id = user_info["google_id"]
|
OAUTH_CALLBACKS_TOTAL.labels(provider="google", status="error").inc()
|
||||||
|
logger.warning(
|
||||||
# Check if user exists
|
"OAuth [Google sign-in]: rejecting unverified email=%s",
|
||||||
result = await db.execute(
|
user_info.get("email"),
|
||||||
select(User).where((User.email == email) | (User.google_id == google_id))
|
)
|
||||||
)
|
raise HTTPException(
|
||||||
user = result.scalar_one_or_none()
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
detail="Email not verified with Google",
|
||||||
if user:
|
|
||||||
# Update Google ID if not set
|
|
||||||
if not user.google_id:
|
|
||||||
user.google_id = google_id # type: ignore[assignment]
|
|
||||||
user.oauth_provider = "google" # type: ignore[assignment]
|
|
||||||
logger.info(
|
|
||||||
"OAuth [Google sign-in]: linked Google ID to existing account "
|
|
||||||
"(email=%s)",
|
|
||||||
email,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Update last login
|
email = user_info["email"]
|
||||||
user.last_login_at = datetime.now(timezone.utc) # type: ignore[assignment]
|
google_id = user_info["google_id"]
|
||||||
|
|
||||||
# Domain restriction — superusers always bypass
|
# Check if user exists
|
||||||
if not user.is_superuser:
|
result = await db.execute(
|
||||||
|
select(User).where((User.email == email) | (User.google_id == google_id))
|
||||||
|
)
|
||||||
|
user = result.scalar_one_or_none()
|
||||||
|
|
||||||
|
if user:
|
||||||
|
# Update Google ID if not set
|
||||||
|
if not user.google_id:
|
||||||
|
user.google_id = google_id # type: ignore[assignment]
|
||||||
|
user.oauth_provider = "google" # type: ignore[assignment]
|
||||||
|
logger.info(
|
||||||
|
"OAuth [Google sign-in]: linked Google ID to existing account "
|
||||||
|
"(email=%s)",
|
||||||
|
email,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Update last login
|
||||||
|
user.last_login_at = datetime.now(timezone.utc) # type: ignore[assignment]
|
||||||
|
|
||||||
|
# Domain restriction — superusers always bypass
|
||||||
|
if not user.is_superuser:
|
||||||
|
_check_domain_allowed(email)
|
||||||
|
|
||||||
|
# Auto-promote to superuser if this is the configured admin email
|
||||||
|
if not user.is_superuser and _is_admin_email(email):
|
||||||
|
user.is_superuser = True # type: ignore[assignment]
|
||||||
|
logger.info(f"Auto-promoted admin user via Google OAuth: {user.email}")
|
||||||
|
|
||||||
|
logger.info(f"Existing user logged in with Google: {user.email}")
|
||||||
|
AUTH_LOGINS_TOTAL.labels(method="google", status="success").inc()
|
||||||
|
else:
|
||||||
|
# Domain restriction check before creating the account
|
||||||
_check_domain_allowed(email)
|
_check_domain_allowed(email)
|
||||||
|
|
||||||
# Auto-promote to superuser if this is the configured admin email
|
# Create new user
|
||||||
if not user.is_superuser and _is_admin_email(email):
|
user = User(
|
||||||
user.is_superuser = True # type: ignore[assignment]
|
email=email,
|
||||||
logger.info(f"Auto-promoted admin user via Google OAuth: {user.email}")
|
full_name=user_info.get("full_name"),
|
||||||
|
google_id=google_id,
|
||||||
|
oauth_provider="google",
|
||||||
|
subscription_tier=_default_tier(),
|
||||||
|
is_active=True,
|
||||||
|
last_login_at=datetime.now(timezone.utc),
|
||||||
|
is_superuser=_is_admin_email(email),
|
||||||
|
)
|
||||||
|
db.add(user)
|
||||||
|
|
||||||
logger.info(f"Existing user logged in with Google: {user.email}")
|
logger.info(f"New user registered with Google: {user.email}")
|
||||||
AUTH_LOGINS_TOTAL.labels(method="google", status="success").inc()
|
AUTH_REGISTRATIONS_TOTAL.labels(method="google", status="success").inc()
|
||||||
else:
|
|
||||||
# Domain restriction check before creating the account
|
|
||||||
_check_domain_allowed(email)
|
|
||||||
|
|
||||||
# Create new user
|
await db.commit()
|
||||||
user = User(
|
await db.refresh(user)
|
||||||
email=email,
|
|
||||||
full_name=user_info.get("full_name"),
|
# Create tokens
|
||||||
google_id=google_id,
|
tokens = oauth_service.create_tokens_for_user(user)
|
||||||
oauth_provider="google",
|
logger.debug(
|
||||||
subscription_tier=_default_tier(),
|
"OAuth [Google sign-in]: sign-in complete, JWT tokens issued for user_id=%s",
|
||||||
is_active=True,
|
user.id,
|
||||||
last_login_at=datetime.now(timezone.utc),
|
|
||||||
is_superuser=_is_admin_email(email),
|
|
||||||
)
|
)
|
||||||
db.add(user)
|
|
||||||
|
|
||||||
logger.info(f"New user registered with Google: {user.email}")
|
OAUTH_CALLBACKS_TOTAL.labels(provider="google", status="success").inc()
|
||||||
AUTH_REGISTRATIONS_TOTAL.labels(method="google", status="success").inc()
|
return tokens
|
||||||
|
|
||||||
await db.commit()
|
except HTTPException:
|
||||||
await db.refresh(user)
|
raise
|
||||||
|
except Exception:
|
||||||
# Create tokens
|
OAUTH_CALLBACKS_TOTAL.labels(provider="google", status="error").inc()
|
||||||
tokens = oauth_service.create_tokens_for_user(user)
|
logger.error(
|
||||||
logger.debug(
|
"OAuth [Google sign-in]: unhandled error during sign-in flow",
|
||||||
"OAuth [Google sign-in]: sign-in complete, JWT tokens issued for user_id=%s",
|
exc_info=True,
|
||||||
user.id,
|
)
|
||||||
)
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
OAUTH_CALLBACKS_TOTAL.labels(provider="google", status="success").inc()
|
detail="OAuth authentication failed",
|
||||||
return tokens
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.get("/google/authorize-url")
|
@router.get("/google/authorize-url")
|
||||||
|
|||||||
@@ -142,7 +142,11 @@ class OAuthService:
|
|||||||
except HTTPException:
|
except HTTPException:
|
||||||
raise
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("OAuth [Google sign-in]: unexpected error: %s", e)
|
logger.error(
|
||||||
|
"OAuth [Google sign-in]: unexpected error: %s",
|
||||||
|
e,
|
||||||
|
exc_info=True,
|
||||||
|
)
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
detail="OAuth authentication failed",
|
detail="OAuth authentication failed",
|
||||||
|
|||||||
Reference in New Issue
Block a user