Skip to content

Handle GitHub OAuth failures in /auth/callback without a 500#54

Merged
tarekziade merged 1 commit into
mainfrom
fix/login-oauth-500-graceful-error
Jul 7, 2026
Merged

Handle GitHub OAuth failures in /auth/callback without a 500#54
tarekziade merged 1 commit into
mainfrom
fix/login-oauth-500-graceful-error

Conversation

@tarekziade

Copy link
Copy Markdown
Collaborator

What

A user hit Internal Server Error on https://serge.huggingface.tech/login today. The OAuth roundtrip got through the token exchange but GitHub rejected the freshly-issued token on GET /user:

POST github.com/login/oauth/access_token  → 200 OK
GET  api.github.com/user                   → 401 Unauthorized  ("Bad credentials")
GET  /auth/callback?...                     → 500 Internal Server Error

auth_callback called user_resp.raise_for_status(), so the 401 bubbled up as an unhandled httpx.HTTPStatusError → bare 500 with no logging of why.

Change

Each GitHub step in the callback (token exchange, /user, and the org-membership-derived allow-list check) now:

  • logs GitHub's own status + response body (so we can diagnose the next failure), and
  • redirects to /login?error=<code> instead of raising.

login.html maps the code to a readable message:

  • github_auth_failed — "GitHub couldn't verify your sign-in. This is usually temporary — please try again."
  • invalid_oauth_state — expired/reused sign-in link
  • not_allowed — account not on the allow-list

Testing

Drove the real 401 path with a FastAPI TestClient + mocked GitHub responses: the /user 401 now yields 302 → /login?error=github_auth_failed (no 500), and the log line reads oauth /user lookup failed: github returned 401: {"message":"Bad credentials"}. ruff format/check clean; no tests referenced the old error strings.

Note: the underlying 401 on a just-minted token is most likely transient (or an OAuth App client_secret drift) — this PR is the UX/robustness fix so it surfaces cleanly instead of a 500.

🤖 Generated with Claude Code

The login callback called raise_for_status() on the GitHub /user request,
so any non-2xx from GitHub (seen in prod as a 401 "Bad credentials" on a
freshly-issued token) bubbled up as an unhandled httpx.HTTPStatusError and
Starlette returned a bare 500 Internal Server Error to the user.

Each GitHub step in the callback (token exchange, /user, and the derived
allow-list check) now logs GitHub's own status/body and redirects to
/login?error=<code> instead. login.html turns the code into a readable
message (github_auth_failed / invalid_oauth_state / not_allowed) so the
user sees "couldn't verify your sign-in, please try again" rather than a 500.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@tarekziade tarekziade merged commit 8813ab8 into main Jul 7, 2026
3 checks passed
@tarekziade tarekziade deleted the fix/login-oauth-500-graceful-error branch July 7, 2026 13:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant