feat(app): add OIDC federated app sign-in (start/exchange_token) - #1676
feat(app): add OIDC federated app sign-in (start/exchange_token)#1676mrunankpawar wants to merge 8 commits into
Conversation
Adds descope_client.app.start()/exchange_token() for OIDC Federated Apps configured in the Descope Console, with Descope acting as the IDP. - start() builds the authorize URL (and a fresh PKCE pair) locally, with no network call - the authorize endpoint 303-redirects rather than returning JSON. - exchange_token() does the real code->token exchange as a standard OAuth2 client (form-encoded body, no Descope bearer header), returning the raw OAuth2/OIDC token shape. - flow + login_hint support a "homegrown first factor, Descope for MFA only" integration: run only an MFA-only Descope Flow for an already-identified user. See samples/app_oidc_mfa_sample_app.py for a full runnable example. Verified end-to-end against a live confidential-client test app, including a full round trip through two real logins (default flow and a console-edited magic-link MFA flow) and real token exchange - see AppBase's docstring for exactly what was confirmed live vs. what's still open (public-client/PKCE-only path, redirect_uri validation timing, non-email login_hint). Only OIDC federated apps are supported; SAML/WS-Fed federated apps are IDP-initiated with no code/token/exchange_token step at all and are out of scope here. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
🐕 Review complete — View session on Shuni Portal 🐾 |
🐕 Suggested ReviewersThis PR adds OIDC federated app sign-in functionality with two primary components: OAuth2/OIDC token exchange. The key changed areas are: (1) Core client files (descope_client.py, descope_client_async.py) where the new app methods integrate, (2) Authentication method modules (app.py, app_async.py, _app_base.py) implementing the feature logic, (3) Common utilities (common.py) likely supporting PKCE and token handling, and (4) Documentation and samples. To ensure quality coverage, reviewers should span expertise in the client layer, async patterns, common utilities, and OIDC/OAuth2 flows.
Suggested by Shuni based on git history and PR context. Names are not @-mentioned to avoid notifying anyone — request a review from whoever fits best. |
…e cross-site scripting' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
… through an exception' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
… through an exception' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
There was a problem hiding this comment.
🐕 Shuni Review
Adds descope_client.app.start()/exchange_token() for OIDC Federated App sign-in, building the authorize URL/PKCE pair locally and doing a raw OAuth2 code→token exchange.
Actionable comments posted: 1
- 1 🟡 Minor:
exchange_tokenloses retry/rate-limit handling that every other SDK call gets
Merge risk: 🟢 Low: implementation, docstrings, and tests are internally consistent (verified client_id padding, PKCE, URL/body composition, and mock wiring line-by-line against the diff); the one finding is a bounded reliability gap in a new, isolated endpoint.
See inline comments for details.
Declared coverage: FULL — 10/10 changed files reviewed.
|
🐕 Review complete — View session on Shuni Portal 🐾 |
There was a problem hiding this comment.
🐕 Shuni Review
New commits fix two CodeQL findings (XSS + exception-message exposure) in samples/app_oidc_mfa_sample_app.py.
Actionable comments posted: 1
- 1 🟠 Major:
flask.escapeimport breaks the sample under the SDK's own locked Flask version
Merge risk: 🟡 Moderate: the XSS/info-exposure intent is right, but the escaping fix itself uses a name that doesn't exist in Flask 3.1.3 (this repo's locked version), so the sample would fail at import.
See inline comments for details.
⚠️ Review follow-up issue: Unresolved prior review threads: PRRT_kwDOHT_eGc6bx4Tt.
Declared coverage: PARTIAL — 4/10 changed files reviewed.
Co-authored-by: shuni-bot[bot] <251468265+shuni-bot[bot]@users.noreply.github.com>
|
🐕 Review complete — View session on Shuni Portal 🐾 |
Coverage reportThe coverage rate went from
Diff Coverage details (click to unfold)descope/descope_client_async.py
descope/authmethod/_app_base.py
descope/descope_client.py
descope/authmethod/app.py
descope/authmethod/app_async.py
|
|
@shuni can you please fix this:
|
|
🐕 Done! Updated PR: #1676 📋 Actions TakenView AI responseBoth fixes are committed on
Verified with |
Ruff F841 - the AuthException wasn't referenced in the except block.
exchange_token bypassed the SDK's normal HTTP layer entirely for its one-shot httpx call, so a transient 429/5xx from Descope's own token endpoint surfaced as a generic AuthException instead of being retried or raised as RateLimitException like every other call in the SDK. Keep the form-encoded body/headers bypass (justified - no bearer token), but reuse HTTPClient._execute_with_retry (sync) / _async_execute_with_retry (async) and _raise_from_response so retry/rate-limit behavior stays consistent with the rest of the SDK.
|
🐕 Review complete — View session on Shuni Portal 🐾 |
Related Issues
Fixes https://github.com/descope/etc/issues/10672
Description
Adds
descope_client.app.start()/exchange_token()for OIDC Federated Apps configured in the Descope Console, with Descope acting as the IDP.start()builds the authorize URL (and a fresh PKCE pair) locally, with no network callexchange_token()does the real code->token exchange as a standard OAuth2 client, returning the raw OAuth2/OIDC token shape.samples/app_oidc_mfa_sample_app.pyfor a full runnable example.Verified end-to-end against a live confidential-client test app, including a full round trip through two real logins (default flow and a console-edited magic-link MFA flow) and real token exchange - see AppBase's docstring for exactly what was confirmed live vs. what's still open (public-client/PKCE-only path, redirect_uri validation timing, non-email login_hint).
Only OIDC federated apps are supported; SAML/WS-Fed federated apps are IDP-initiated with no code/token/exchange_token step at all and are out of scope here.