Skip to content

Commit daa54f0

Browse files
committed
fix(auth): make state optional in OAuth callback for app install flow
GitHub App installation redirects to the callback with code and installation_id but no state parameter. Accept both flows: OAuth login (with state/CSRF validation) and post-install redirect (with installation_id, no state).
1 parent cc23450 commit daa54f0

1 file changed

Lines changed: 20 additions & 6 deletions

File tree

  • apps/api/src/helprs/modules/identity

apps/api/src/helprs/modules/identity/router.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,17 +59,31 @@ async def github_login(request: Request, settings: GetSettings):
5959
async def github_callback(
6060
request: Request,
6161
code: str,
62-
state: str,
6362
session: DbSession,
6463
settings: GetSettings,
64+
state: str | None = None,
65+
installation_id: int | None = None,
66+
setup_action: str | None = None,
6567
):
66-
"""Handle GitHub OAuth callback: exchange code, create user, issue tokens."""
67-
# Validate CSRF state
68-
stored_state = request.cookies.get("oauth_state")
69-
if not stored_state or not secrets.compare_digest(stored_state, state):
68+
"""Handle GitHub OAuth callback: exchange code, create user, issue tokens.
69+
70+
Two flows land here:
71+
- OAuth login: has ``state`` (CSRF-validated against cookie).
72+
- GitHub App install: has ``installation_id`` + ``setup_action`` but no ``state``
73+
(user authorized the app during installation on github.com).
74+
"""
75+
if state is not None:
76+
# Normal OAuth login — validate CSRF state
77+
stored_state = request.cookies.get("oauth_state")
78+
if not stored_state or not secrets.compare_digest(stored_state, state):
79+
from helprs.core.exceptions import UnauthorizedError
80+
81+
raise UnauthorizedError("Invalid OAuth state parameter")
82+
elif installation_id is None:
83+
# Neither state nor installation_id — reject
7084
from helprs.core.exceptions import UnauthorizedError
7185

72-
raise UnauthorizedError("Invalid OAuth state parameter")
86+
raise UnauthorizedError("Missing OAuth state parameter")
7387

7488
# Exchange code for GitHub access token
7589
token_data = await exchange_code_for_token(code, settings)

0 commit comments

Comments
 (0)