Summary
Both GitHub OAuth callbacks assume the token/authorize responses are valid JSON and call .json() without checking the HTTP status or content type. If GitHub returns an error page (HTML) or a non-200 response, the unhandled ValueError/requests.JSONDecodeError produces an HTTP 500 instead of a graceful redirect to the auth-error path.
Evidence
src/routes/github_routes.py:46-47:
response = requests.post(token_url, json=payload, headers=headers)
data = response.json() # raises if GitHub returns HTML (e.g., rate-limited, 502, error page)
src/routes/auth_routes.py:28-29 (Authlib flow):
resp = github.get('user', token=token)
profile = resp.json() # same problem — no status check
If the token exchange returns e.g. {"error":"bad_verification_code"}, .json() succeeds but data.get("access_token") is None, which is handled (redirect to /?github_auth=error). The crash happens specifically when the response is not JSON (HTML error page, proxy 502, or empty body) — then .json() raises and the request 500s. This also applies to resp.json() in the Authlib authorize flow when GitHub is degraded.
Impact
- OAuth failures that should be user-visible ("GitHub auth error") instead surface as 500s.
- The callback also has no rate limiting (none of
/auth/* or /api/github/* is protected by the @rate_limit decorator that main_routes.py uses), so repeated bad requests hit the unhandled path with no throttling.
Suggested Fix
- Check
response.status_code and content type before .json(); wrap parsing in try/except and redirect to /?github_auth=error on any failure.
- Same for the Authlib flow: check
resp.status_code and resp.ok before parsing the profile.
- Optionally apply
@rate_limit to the OAuth endpoints to match the rest of the app.
Summary
Both GitHub OAuth callbacks assume the token/authorize responses are valid JSON and call
.json()without checking the HTTP status or content type. If GitHub returns an error page (HTML) or a non-200 response, the unhandledValueError/requests.JSONDecodeErrorproduces an HTTP 500 instead of a graceful redirect to the auth-error path.Evidence
src/routes/github_routes.py:46-47:src/routes/auth_routes.py:28-29(Authlib flow):If the token exchange returns e.g.
{"error":"bad_verification_code"},.json()succeeds butdata.get("access_token")isNone, which is handled (redirect to/?github_auth=error). The crash happens specifically when the response is not JSON (HTML error page, proxy 502, or empty body) — then.json()raises and the request 500s. This also applies toresp.json()in the Authlib authorize flow when GitHub is degraded.Impact
/auth/*or/api/github/*is protected by the@rate_limitdecorator thatmain_routes.pyuses), so repeated bad requests hit the unhandled path with no throttling.Suggested Fix
response.status_codeand content type before.json(); wrap parsing intry/exceptand redirect to/?github_auth=erroron any failure.resp.status_codeandresp.okbefore parsing the profile.@rate_limitto the OAuth endpoints to match the rest of the app.