fix: OAuth callback — recover mode from state when session cookie is lost
Root cause: request.session cookie expires during Gitea OAuth redirect
→ oauth_mode lost → link mode falls through to login mode
→ Creates gitea_bruno user instead of linking to local account
Fix: state now carries mode suffix (state:mode)
Callback recovers mode from state parameter even if session lost
Allows full session loss but still correctly enters link mode
This commit is contained in:
+14
-10
@@ -234,18 +234,22 @@ async def callback(
|
||||
state: str = Query(...),
|
||||
):
|
||||
"""Handle OAuth2 callback from Gitea."""
|
||||
# Validate state — try exact match first, then with mode suffix
|
||||
# Recover mode from state suffix (state:mode format), then validate
|
||||
expected_state = request.session.get("oauth_state", "")
|
||||
provider_name = request.session.get("oauth_provider", "gitea")
|
||||
if not expected_state:
|
||||
return HTMLResponse("<h1>Invalid state: session expired</h1>", status_code=400)
|
||||
# Check exact match or state:mode format
|
||||
if state != expected_state:
|
||||
parts = state.rsplit(":", 1)
|
||||
if len(parts) == 2 and parts[0] == expected_state:
|
||||
request.session["oauth_mode"] = parts[1]
|
||||
else:
|
||||
return HTMLResponse("<h1>Invalid state</h1>", status_code=400)
|
||||
|
||||
auth_mode = ""
|
||||
raw_state = state
|
||||
if ":" in state:
|
||||
raw_state, auth_mode = state.rsplit(":", 1)
|
||||
if auth_mode:
|
||||
request.session["oauth_mode"] = auth_mode
|
||||
|
||||
# Validate: state token must match session, unless session lost and mode present
|
||||
if expected_state and raw_state != expected_state:
|
||||
return HTMLResponse("<h1>Invalid state</h1>", status_code=400)
|
||||
if not expected_state and not auth_mode:
|
||||
return HTMLResponse("<h1>Session expired — please try connecting again</h1>", status_code=400)
|
||||
|
||||
from app.auth.providers import get_provider
|
||||
oauth_provider = get_provider(provider_name)
|
||||
|
||||
Reference in New Issue
Block a user