Skip to content

Add option to enable redirect-based OAuth flow#1835

Open
thepatrickchin wants to merge 14 commits into
NVIDIA:developfrom
thepatrickchin:feat/redirect-auth
Open

Add option to enable redirect-based OAuth flow#1835
thepatrickchin wants to merge 14 commits into
NVIDIA:developfrom
thepatrickchin:feat/redirect-auth

Conversation

@thepatrickchin
Copy link
Copy Markdown
Member

@thepatrickchin thepatrickchin commented Apr 2, 2026

Description

This PR adds a use_redirect_auth option in auth provider configurations to enable redirect-based OAuth flows while preserving popup flow by default.

This features depends on the following NAT-UI PR: NVIDIA/NeMo-Agent-Toolkit-UI#127

Closes #1834

By Submitting this PR I confirm:

  • I am familiar with the Contributing Guidelines.
  • We require that all contributors "sign-off" on their commits. This certifies that the contribution is your original work, or you have rights to submit it under the same license, or a compatible license.
    • Any contribution which contains commits that are not Signed-Off will not be accepted.
  • When the PR is ready for review, new or existing tests cover these changes.
  • When the PR is ready for review, the documentation is up to date with these changes.

Summary by CodeRabbit

  • New Features

    • Configurable OAuth flow mode (use_redirect_auth) to choose redirect vs popup; redirect mode supports an optional return URL and serves redirect-aware success/error/cancel HTML.
  • Bug Fixes

    • Consent UI now has explicit Authorize/Cancel actions so cancellations return access_denied reliably; popup flows notify opener and close cleanly.
  • Documentation

    • API auth docs updated with use_redirect_auth and its default (popup).
  • Tests

    • Added tests for popup vs redirect flows, return-URL handling, origin allowlisting, and success/error/cancel UX.

@thepatrickchin thepatrickchin requested a review from a team as a code owner April 2, 2026 06:05
@copy-pr-bot
Copy link
Copy Markdown

copy-pr-bot Bot commented Apr 2, 2026

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 2, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds an opt-in redirect-based OAuth2 authorization flow via a new boolean config use_redirect_auth (default False). Updates provider config, interactive prompt model, WebSocket and HTTP handlers, origin allowlist logic, HTML success/error/cancel snippet builders, example OAuth2 server patch/Dockerfile, and tests to support popup vs redirect behaviors and propagate an allowed-origin-derived return_url.

Changes

OAuth2 redirect-vs-popup flow (single cohesive change DAG)

Layer / File(s) Summary
Data Shape / Config
packages/nvidia_nat_core/src/nat/authentication/oauth2/oauth2_auth_code_flow_provider_config.py, examples/front_ends/simple_auth/src/nat_simple_auth/configs/config.yml
Adds use_redirect_auth: bool to provider config (default False); example config sets use_redirect_auth: false.
Interactive Prompt Model
packages/nvidia_nat_core/src/nat/data_models/interactive.py
Adds _HumanPromptOAuthConsent.use_redirect: bool = False to signal UI whether to open popup or navigate.
WebSocket handler state & wiring
packages/nvidia_nat_core/src/nat/front_ends/fastapi/auth_flow_handlers/websocket_flow_handler.py, packages/nvidia_nat_core/src/nat/front_ends/fastapi/routes/websocket.py
FlowState gains return_url; WebSocketAuthenticationFlowHandler accepts return_url; handler enforces return_url when use_redirect_auth is true; outbound consent prompt includes use_redirect=config.use_redirect_auth; websocket endpoint computes return_url from Origin via origin-check helper and passes it into the handler.
Origin allowlist helper
packages/nvidia_nat_core/src/nat/front_ends/fastapi/routes/websocket.py
Adds _is_origin_allowed(origin, allowed_origins, allow_origin_regex) implementing wildcard, exact, and full-string regex matching used to decide whether to propagate origin as return_url.
Auth callback route & error handling
packages/nvidia_nat_core/src/nat/front_ends/fastapi/routes/auth.py
Callback now inspects error query param, removes outstanding flow, sets exceptions on flow futures for cancellations/errors, and returns HTTP 200 HTML selected by flow_state.config.use_redirect_auth (redirect builders vs popup templates) for cancelled/error/success cases; token-exchange exceptions also return HTML UX (200) instead of 5xx.
HTML snippet builders
packages/nvidia_nat_core/src/nat/front_ends/fastapi/html_snippets/auth_code_grant_success.py, .../auth_code_grant_error.py, .../auth_code_grant_cancelled.py
Adds popup constants and redirect templates plus builder functions that JSON-encode and escape <, >, / for return_url, producing either popup-close messages or redirect-to-return-url-with-fallback-to-history.
Frontend example patch & Dockerfile
examples/front_ends/simple_auth/patches/oauth2-server.patch, examples/front_ends/simple_auth/Dockerfile
Patch changes OAuth2 example server consent form to use explicit confirm="yes"/confirm="no" buttons; Dockerfile copies and applies the patch during image build so cancel yields error=access_denied.
Tests: model, websocket, routes, snippets, origin
packages/nvidia_nat_core/tests/... (multiple files)
Adds/updates tests: interactive prompt defaults; websocket flow tests for popup/redirect and missing return_url; origin allowlist tests; auth redirect route tests for access_denied vs other errors and returned HTML variants; unit tests for success/error/cancel HTML builders validating embedding, escaping, and script-injection resilience.

Sequence Diagrams

sequenceDiagram
    participant Browser as Browser (Client)
    participant UI as Frontend UI
    participant WS as WebSocket Handler
    participant OAuth as OAuth Server

    rect rgba(0,150,100,0.5)
        note over Browser,UI: Popup-based OAuth (use_redirect_auth: false)
    end

    Browser->>WS: Open WebSocket
    WS->>UI: Send OAuth prompt (use_redirect=false)
    UI->>UI: Open authorization URL in popup
    Browser->>OAuth: Authorize (popup)
    OAuth-->>Browser: Redirect callback (code)
    Browser->>WS: GET /auth/redirect?code=...
    WS->>OAuth: Exchange code for token
    OAuth-->>WS: Return token
    WS->>UI: Send success message (popup closes)
Loading
sequenceDiagram
    participant Browser as Browser (Client)
    participant UI as Frontend UI
    participant WS as WebSocket Handler
    participant OAuth as OAuth Server

    rect rgba(100,0,150,0.5)
        note over Browser,OAuth: Redirect-based OAuth (use_redirect_auth: true)
    end

    Browser->>WS: Open WebSocket
    WS->>UI: Send OAuth prompt (use_redirect=true) + return_url
    UI->>Browser: Full-page redirect to authorization URL
    Browser->>OAuth: Authorize (redirect)
    OAuth-->>Browser: Redirect callback (code)
    Browser->>WS: GET /auth/redirect?code=...
    WS->>OAuth: Exchange code for token
    OAuth-->>WS: Return token
    WS->>Browser: Return success HTML (redirect to return_url with marker)
    Browser->>Browser: Resume original session (redirect target)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 76.36% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and accurately describes the main change: adding a new configuration option to enable redirect-based OAuth flows, which is the primary objective of this pull request.
Linked Issues check ✅ Passed All code changes directly implement the requirements from issue #1834: adding use_redirect_auth configuration option (default false), supporting both popup and redirect-based OAuth flows, and preserving existing behavior.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the use_redirect_auth feature; no unrelated modifications to other features or systems are present.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@thepatrickchin thepatrickchin changed the title Feat/redirect auth Add option to enable redirect-based OAuth flow Apr 2, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@packages/nvidia_nat_core/src/nat/front_ends/fastapi/auth_flow_handlers/websocket_flow_handler.py`:
- Around line 120-121: The current WebSocketFlowHandler starts a same-tab
redirect flow even when config.use_popup_auth is False and self._return_url is
None; add a guard in the handler before constructing FlowState to fail fast: if
config.use_popup_auth is False and self._return_url is None, raise a clear
exception (or return an HTTP/WebSocket error) so the flow does not start without
a validated return URL; update the block where return_url is set and
FlowState(config=config, return_url=return_url) is created (references:
FlowState, config.use_popup_auth, self._return_url, websocket_flow_handler) to
implement this validation and error handling.

In `@packages/nvidia_nat_core/src/nat/front_ends/fastapi/routes/auth.py`:
- Around line 107-110: The redirect-mode failure paths currently leave the
browser on a raw /auth/redirect error page; update the exception handlers in the
auth redirect route (the function handling flow_state and the except blocks for
OAuthError, httpx.HTTPError, and generic Exception) to mirror the success
behavior: when flow_state.config exists and flow_state.config.use_popup_auth is
False use build_auth_redirect_success_html (or a new
build_auth_redirect_error_html) to construct a redirect-capable error HTML using
flow_state.return_url, otherwise fall back to the existing
AUTH_REDIRECT_SUCCESS_HTML/ERROR constant; ensure the same flow_state,
use_popup_auth, build_auth_redirect_* helper and AUTH_REDIRECT_* constants are
referenced so failures perform a UI redirect like successes.

In `@packages/nvidia_nat_core/src/nat/front_ends/fastapi/routes/websocket.py`:
- Around line 75-81: The origin membership check currently uses a literal
comparison against worker.front_end_config.cors.allow_origins which fails when
allow_origins contains the wildcard "*" and ignores allow_origin_regex; update
the logic before constructing WebSocketAuthenticationFlowHandler so that: if
allow_origins includes "*" accept any non-empty origin, otherwise check origin
equality against the list; additionally, if
worker.front_end_config.cors.allow_origin_regex is set, test origin against that
regex (treat a matching regex as allowed). Use the same variables (origin,
allowed_origins, allow_origin_regex) and pass the computed return_url into
WebSocketAuthenticationFlowHandler as before.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7940c9bf-52f2-4d57-886c-0a4ab5fae921

📥 Commits

Reviewing files that changed from the base of the PR and between 2490e5d and 33db54c.

📒 Files selected for processing (15)
  • docs/source/components/auth/api-authentication.md
  • examples/front_ends/simple_auth/Dockerfile
  • examples/front_ends/simple_auth/patches/oauth2-server.patch
  • examples/front_ends/simple_auth/src/nat_simple_auth/configs/config.yml
  • packages/nvidia_nat_core/src/nat/authentication/oauth2/oauth2_auth_code_flow_provider_config.py
  • packages/nvidia_nat_core/src/nat/data_models/interactive.py
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/auth_flow_handlers/websocket_flow_handler.py
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/html_snippets/auth_code_grant_cancelled.py
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/html_snippets/auth_code_grant_success.py
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/routes/auth.py
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/routes/websocket.py
  • packages/nvidia_nat_core/tests/nat/builder/test_interactive.py
  • packages/nvidia_nat_core/tests/nat/front_ends/auth_flow_handlers/test_websocket_flow_handler.py
  • packages/nvidia_nat_core/tests/nat/front_ends/fastapi/test_auth_code_grant_cancelled.py
  • packages/nvidia_nat_core/tests/nat/front_ends/fastapi/test_auth_code_grant_success.py

Comment thread packages/nvidia_nat_core/src/nat/front_ends/fastapi/routes/auth.py Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/nvidia_nat_core/src/nat/front_ends/fastapi/routes/auth.py (1)

84-123: 🛠️ Refactor suggestion | 🟠 Major

Use logger.exception() to preserve stack traces in these catch-and-respond blocks.

The three exception handlers (lines 85, 99, 112) catch exceptions without re-raising them, so they must use logger.exception() instead of logger.error() to capture the full stack trace information. This is mandatory per coding guidelines.

♻️ Suggested fix
-        except OAuthError as e:
-            logger.error("OAuth error during token exchange for state %s: %s (%s)", state, e.error, e.description)
+        except OAuthError as e:
+            logger.exception("OAuth error during token exchange for state %s: %s (%s)", state, e.error, e.description)
             if not flow_state.future.done():
                 flow_state.future.set_exception(
                     RuntimeError(f"Authorization server rejected request: {e.error} ({e.description})"))
             if flow_state.config and flow_state.config.use_redirect_auth:
                 error_html = build_auth_redirect_error_html(flow_state.return_url)
@@
-        except httpx.HTTPError as e:
-            logger.error("Network error during token fetch for state %s: %s", state, e)
+        except httpx.HTTPError as e:
+            logger.exception("Network error during token fetch for state %s: %s", state, e)
             if not flow_state.future.done():
                 flow_state.future.set_exception(RuntimeError(f"Network error during token fetch: {e}"))
             if flow_state.config and flow_state.config.use_redirect_auth:
                 error_html = build_auth_redirect_error_html(flow_state.return_url)
@@
-        except Exception as e:
-            logger.error("Unexpected error during authentication for state %s: %s", state, e)
+        except Exception as e:
+            logger.exception("Unexpected error during authentication for state %s: %s", state, e)
             if not flow_state.future.done():
                 flow_state.future.set_exception(RuntimeError(f"Authentication failed: {e}"))
             if flow_state.config and flow_state.config.use_redirect_auth:
                 error_html = build_auth_redirect_error_html(flow_state.return_url)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/nvidia_nat_core/src/nat/front_ends/fastapi/routes/auth.py` around
lines 84 - 123, Replace the three logger.error calls in the exception handlers
that catch OAuthError, httpx.HTTPError, and the generic Exception with
logger.exception so the stack traces are preserved; update the handlers around
the symbols OAuthError, httpx.HTTPError, and the final except Exception (the
blocks that reference flow_state, build_auth_redirect_error_html, and
AUTH_REDIRECT_ERROR_HTML) to call logger.exception with the same message format
and parameters instead of logger.error, leaving the rest of the error handling
(setting flow_state.future, building error_html, and returning the HTMLResponse)
unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/nvidia_nat_core/src/nat/front_ends/fastapi/routes/auth.py`:
- Around line 53-71: The code currently treats every OAuth callback error as a
user cancellation; change the logic to only treat error == "access_denied" as a
cancellation and keep the existing cancellation responses
(build_auth_redirect_cancelled_html, AUTH_REDIRECT_CANCELLED_POPUP_HTML,
flow_state.future.set_exception(...)) only in that branch; for all other error
values log the error (include error_description), set flow_state.future with a
clear exception mentioning the actual error (e.g. RuntimeError(f"OAuth error:
{error} ({error_description})")), call worker._remove_flow(state) as now, and
forward the request to the normal error UX path instead of the cancelled HTML
(i.e. do not return the cancelled HTML for non-access_denied errors).

---

Outside diff comments:
In `@packages/nvidia_nat_core/src/nat/front_ends/fastapi/routes/auth.py`:
- Around line 84-123: Replace the three logger.error calls in the exception
handlers that catch OAuthError, httpx.HTTPError, and the generic Exception with
logger.exception so the stack traces are preserved; update the handlers around
the symbols OAuthError, httpx.HTTPError, and the final except Exception (the
blocks that reference flow_state, build_auth_redirect_error_html, and
AUTH_REDIRECT_ERROR_HTML) to call logger.exception with the same message format
and parameters instead of logger.error, leaving the rest of the error handling
(setting flow_state.future, building error_html, and returning the HTMLResponse)
unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: afa34493-7660-47ca-8f78-9d28245e697c

📥 Commits

Reviewing files that changed from the base of the PR and between 33db54c and ce7ec06.

📒 Files selected for processing (12)
  • docs/source/components/auth/api-authentication.md
  • examples/front_ends/simple_auth/src/nat_simple_auth/configs/config.yml
  • packages/nvidia_nat_core/src/nat/authentication/oauth2/oauth2_auth_code_flow_provider_config.py
  • packages/nvidia_nat_core/src/nat/data_models/interactive.py
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/auth_flow_handlers/websocket_flow_handler.py
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/html_snippets/auth_code_grant_error.py
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/routes/auth.py
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/routes/websocket.py
  • packages/nvidia_nat_core/tests/nat/builder/test_interactive.py
  • packages/nvidia_nat_core/tests/nat/front_ends/auth_flow_handlers/test_websocket_flow_handler.py
  • packages/nvidia_nat_core/tests/nat/front_ends/fastapi/test_auth_code_grant_error.py
  • packages/nvidia_nat_core/tests/nat/front_ends/fastapi/test_websocket_route_origin.py
✅ Files skipped from review due to trivial changes (2)
  • docs/source/components/auth/api-authentication.md
  • packages/nvidia_nat_core/tests/nat/builder/test_interactive.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • examples/front_ends/simple_auth/src/nat_simple_auth/configs/config.yml
  • packages/nvidia_nat_core/src/nat/authentication/oauth2/oauth2_auth_code_flow_provider_config.py
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/auth_flow_handlers/websocket_flow_handler.py

Comment thread packages/nvidia_nat_core/src/nat/front_ends/fastapi/routes/auth.py Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/nvidia_nat_core/src/nat/front_ends/fastapi/routes/auth.py (1)

101-140: ⚠️ Potential issue | 🟠 Major

Use logger.exception() to preserve full stack traces in exception handlers.

Lines 102, 116, and 129 catch exceptions and log them with logger.error() but do not re-raise. Per coding guidelines, you must use logger.exception() to capture the full stack trace. The broad except Exception at line 128 (Ruff BLE001) is a secondary concern—prioritize fixing the logging pattern first.

Suggested fix
         except OAuthError as e:
-            logger.error("OAuth error during token exchange for state %s: %s (%s)", state, e.error, e.description)
+            logger.exception("OAuth error during token exchange for state %s: %s (%s)", state, e.error, e.description)
             if not flow_state.future.done():
                 flow_state.future.set_exception(
                     RuntimeError(f"Authorization server rejected request: {e.error} ({e.description})"))
             if flow_state.config and flow_state.config.use_redirect_auth:
                 error_html = build_auth_redirect_error_html(flow_state.return_url)
             else:
                 error_html = AUTH_REDIRECT_ERROR_HTML
             return HTMLResponse(content=error_html,
                                 status_code=200,
                                 headers={
                                     "Content-Type": "text/html; charset=utf-8", "Cache-Control": "no-cache"
                                 })
         except httpx.HTTPError as e:
-            logger.error("Network error during token fetch for state %s: %s", state, e)
+            logger.exception("Network error during token fetch for state %s: %s", state, e)
             if not flow_state.future.done():
                 flow_state.future.set_exception(RuntimeError(f"Network error during token fetch: {e}"))
             if flow_state.config and flow_state.config.use_redirect_auth:
                 error_html = build_auth_redirect_error_html(flow_state.return_url)
             else:
                 error_html = AUTH_REDIRECT_ERROR_HTML
             return HTMLResponse(content=error_html,
                                 status_code=200,
                                 headers={
                                     "Content-Type": "text/html; charset=utf-8", "Cache-Control": "no-cache"
                                 })
         except Exception as e:
-            logger.error("Unexpected error during authentication for state %s: %s", state, e)
+            logger.exception("Unexpected error during authentication for state %s: %s", state, e)
             if not flow_state.future.done():
                 flow_state.future.set_exception(RuntimeError(f"Authentication failed: {e}"))
             if flow_state.config and flow_state.config.use_redirect_auth:
                 error_html = build_auth_redirect_error_html(flow_state.return_url)
             else:
                 error_html = AUTH_REDIRECT_ERROR_HTML
             return HTMLResponse(content=error_html,
                                 status_code=200,
                                 headers={
                                     "Content-Type": "text/html; charset=utf-8", "Cache-Control": "no-cache"
                                 })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/nvidia_nat_core/src/nat/front_ends/fastapi/routes/auth.py` around
lines 101 - 140, The exception handlers in the auth route use logger.error which
loses stack traces; update the three handlers catching OAuthError,
httpx.HTTPError, and the generic Exception in the function handling the token
exchange so they call logger.exception(...) instead of logger.error(...),
leaving the message text and interpolation symbols (state, e, e.error,
e.description) intact; keep the existing flow_state.future.set_exception(...)
behavior and the HTMLResponse construction unchanged—only replace the logging
calls to use logger.exception to preserve full stack traces for OAuthError,
httpx.HTTPError, and the broad Exception handler.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/nvidia_nat_core/src/nat/front_ends/fastapi/routes/auth.py`:
- Around line 60-71: The code currently chooses redirect-cancel HTML whenever
flow_state.return_url is set, which ignores the configured popup vs redirect
mode; update the branching to use the flow state's mode flag
(flow_state.use_redirect_auth) instead of presence of flow_state.return_url.
Specifically, in the error == "access_denied" block, return
build_auth_redirect_cancelled_html(flow_state.return_url) only when
flow_state.use_redirect_auth is True (and return_url exists), otherwise return
AUTH_REDIRECT_CANCELLED_POPUP_HTML; keep the existing future.set_exception
behavior unchanged and reference flow_state, flow_state.use_redirect_auth,
flow_state.return_url, build_auth_redirect_cancelled_html, and
AUTH_REDIRECT_CANCELLED_POPUP_HTML when making the fix.

In
`@packages/nvidia_nat_core/tests/nat/front_ends/fastapi/test_auth_redirect_route.py`:
- Around line 77-96: Add a new test function (mirroring
test_access_denied_popup_returns_cancelled_html) that constructs
FlowState(config=_POPUP_CONFIG, return_url=_RETURN_URL), obtains a worker via
_make_worker(flow_state), calls _get with {"state": "teststate", "error":
"access_denied"}, and asserts response.status_code == 200 and that
"AUTH_CANCELLED" is present in response.text while "AUTH_ERROR" and any redirect
markers like _RETURN_URL.replace("/", "\\u002f") or "oauth_auth_completed" are
not; use the same helpers (_make_worker, _get) and constants (_POPUP_CONFIG,
_RETURN_URL, FlowState) to ensure popup mode remains independent of return_url.

---

Outside diff comments:
In `@packages/nvidia_nat_core/src/nat/front_ends/fastapi/routes/auth.py`:
- Around line 101-140: The exception handlers in the auth route use logger.error
which loses stack traces; update the three handlers catching OAuthError,
httpx.HTTPError, and the generic Exception in the function handling the token
exchange so they call logger.exception(...) instead of logger.error(...),
leaving the message text and interpolation symbols (state, e, e.error,
e.description) intact; keep the existing flow_state.future.set_exception(...)
behavior and the HTMLResponse construction unchanged—only replace the logging
calls to use logger.exception to preserve full stack traces for OAuthError,
httpx.HTTPError, and the broad Exception handler.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b57f31f0-f84d-4b39-ba5d-4ed124604737

📥 Commits

Reviewing files that changed from the base of the PR and between ce7ec06 and c792ba3.

📒 Files selected for processing (3)
  • examples/front_ends/simple_auth/src/nat_simple_auth/configs/config.yml
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/routes/auth.py
  • packages/nvidia_nat_core/tests/nat/front_ends/fastapi/test_auth_redirect_route.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • examples/front_ends/simple_auth/src/nat_simple_auth/configs/config.yml

Comment thread packages/nvidia_nat_core/src/nat/front_ends/fastapi/routes/auth.py
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@packages/nvidia_nat_core/tests/nat/front_ends/auth_flow_handlers/test_websocket_flow_handler.py`:
- Around line 173-179: Replace the NON-BREAKING HYPHEN in the comment "all
flow‑state cleaned up" with a regular HYPHEN-MINUS so tooling/encoding won't
break; locate the comment near the assertion checking worker._outstanding_flows
== {} in the test_websocket_flow_handler test and update the comment text to
"all flow-state cleaned up" (ensure file saved with UTF-8 and run tests/lint to
confirm no stray non-ASCII hyphen remains).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 84c61824-fad3-4044-8db0-d56a251fa79f

📥 Commits

Reviewing files that changed from the base of the PR and between c792ba3 and 1221391.

📒 Files selected for processing (19)
  • docs/source/components/auth/api-authentication.md
  • examples/front_ends/simple_auth/Dockerfile
  • examples/front_ends/simple_auth/patches/oauth2-server.patch
  • examples/front_ends/simple_auth/src/nat_simple_auth/configs/config.yml
  • packages/nvidia_nat_core/src/nat/authentication/oauth2/oauth2_auth_code_flow_provider_config.py
  • packages/nvidia_nat_core/src/nat/data_models/interactive.py
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/auth_flow_handlers/websocket_flow_handler.py
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/html_snippets/auth_code_grant_cancelled.py
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/html_snippets/auth_code_grant_error.py
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/html_snippets/auth_code_grant_success.py
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/routes/auth.py
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/routes/websocket.py
  • packages/nvidia_nat_core/tests/nat/builder/test_interactive.py
  • packages/nvidia_nat_core/tests/nat/front_ends/auth_flow_handlers/test_websocket_flow_handler.py
  • packages/nvidia_nat_core/tests/nat/front_ends/fastapi/test_auth_code_grant_cancelled.py
  • packages/nvidia_nat_core/tests/nat/front_ends/fastapi/test_auth_code_grant_error.py
  • packages/nvidia_nat_core/tests/nat/front_ends/fastapi/test_auth_code_grant_success.py
  • packages/nvidia_nat_core/tests/nat/front_ends/fastapi/test_auth_redirect_route.py
  • packages/nvidia_nat_core/tests/nat/front_ends/fastapi/test_websocket_route_origin.py
✅ Files skipped from review due to trivial changes (4)
  • docs/source/components/auth/api-authentication.md
  • packages/nvidia_nat_core/tests/nat/front_ends/fastapi/test_websocket_route_origin.py
  • packages/nvidia_nat_core/src/nat/authentication/oauth2/oauth2_auth_code_flow_provider_config.py
  • packages/nvidia_nat_core/tests/nat/front_ends/fastapi/test_auth_code_grant_error.py
🚧 Files skipped from review as they are similar to previous changes (8)
  • packages/nvidia_nat_core/src/nat/data_models/interactive.py
  • examples/front_ends/simple_auth/Dockerfile
  • examples/front_ends/simple_auth/patches/oauth2-server.patch
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/html_snippets/auth_code_grant_success.py
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/html_snippets/auth_code_grant_error.py
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/html_snippets/auth_code_grant_cancelled.py
  • examples/front_ends/simple_auth/src/nat_simple_auth/configs/config.yml
  • packages/nvidia_nat_core/tests/nat/front_ends/fastapi/test_auth_code_grant_cancelled.py

Signed-off-by: Patrick Chin <8509935+thepatrickchin@users.noreply.github.com>
Signed-off-by: Patrick Chin <8509935+thepatrickchin@users.noreply.github.com>
Signed-off-by: Patrick Chin <8509935+thepatrickchin@users.noreply.github.com>
Signed-off-by: Patrick Chin <8509935+thepatrickchin@users.noreply.github.com>
Signed-off-by: Patrick Chin <8509935+thepatrickchin@users.noreply.github.com>
Signed-off-by: Patrick Chin <8509935+thepatrickchin@users.noreply.github.com>
Signed-off-by: Patrick Chin <8509935+thepatrickchin@users.noreply.github.com>
Signed-off-by: Patrick Chin <8509935+thepatrickchin@users.noreply.github.com>
- "same-page" may be misleading as the popup is what keeps the user on the same page.

Signed-off-by: Patrick Chin <8509935+thepatrickchin@users.noreply.github.com>
Signed-off-by: Patrick Chin <8509935+thepatrickchin@users.noreply.github.com>
- Fail fast when redirect auth has no validated return URL.
- Handle redirect-mode failures the same way as redirect-mode success.
- Properly handle wildcard "*" in allow_origins

Signed-off-by: Patrick Chin <8509935+thepatrickchin@users.noreply.github.com>
- Only treat access_denied as a user cancellation.

Signed-off-by: Patrick Chin <8509935+thepatrickchin@users.noreply.github.com>
- Gate cancellation UX with use_redirect_auth, not return_url.
- Add a popup-mode regression test when return_url is present.

Signed-off-by: Patrick Chin <8509935+thepatrickchin@users.noreply.github.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/nvidia_nat_core/src/nat/front_ends/fastapi/routes/auth.py (1)

53-89: ⚡ Quick win

Behavior update is correct, but response selection is duplicated in 5 branches.

Please centralize the redirect/popup HTML selection to avoid future branch drift between cancellation/error/success paths.

♻️ Suggested consolidation
+        def _build_oauth_html(outcome: str) -> str:
+            use_redirect = bool(flow_state.config and flow_state.config.use_redirect_auth)
+            if outcome == "cancelled":
+                return (build_auth_redirect_cancelled_html(flow_state.return_url)
+                        if use_redirect else AUTH_REDIRECT_CANCELLED_POPUP_HTML)
+            if outcome == "error":
+                return (build_auth_redirect_error_html(flow_state.return_url)
+                        if use_redirect else AUTH_REDIRECT_ERROR_HTML)
+            return (build_auth_redirect_success_html(flow_state.return_url)
+                    if use_redirect else AUTH_REDIRECT_SUCCESS_HTML)

Also applies to: 106-114, 119-127, 132-140, 144-148

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/nvidia_nat_core/src/nat/front_ends/fastapi/routes/auth.py` around
lines 53 - 89, Centralize the HTML response selection and creation so the four
branches (cancellation/error/success) only set the response content source and
any flags, then a single HTMLResponse is constructed once; inside the oauth
redirect handler (around the block using state, error, flow_state,
worker._remove_flow), replace duplicated HTMLResponse return sites by setting a
local variable (e.g. response_html) to either
build_auth_redirect_cancelled_html(flow_state.return_url) or
AUTH_REDIRECT_CANCELLED_POPUP_HTML (for access_denied) and similarly set
response_html to build_auth_redirect_error_html(...) or AUTH_REDIRECT_ERROR_HTML
for other errors (and success paths elsewhere), then after branch logic call a
single return HTMLResponse(content=response_html, status_code=200,
headers={...}) so the use of build_auth_redirect_cancelled_html,
build_auth_redirect_error_html, AUTH_REDIRECT_CANCELLED_POPUP_HTML,
AUTH_REDIRECT_ERROR_HTML, flow_state.config.use_redirect_auth, and
flow_state.return_url are the only symbols to touch.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@examples/front_ends/simple_auth/Dockerfile`:
- Around line 28-35: The Dockerfile currently does an unpinned clone of
authlib/example-oauth2-server then applies a local patch to /app/oauth2-server;
make the build deterministic by pinning the cloned repo to a specific commit or
tag before applying the patch: after the RUN git clone ... oauth2-server step,
check out a chosen immutable revision (commit SHA or tag) in the oauth2-server
working directory, verify that the checked-out revision contains the files your
patch expects, and only then proceed to COPY patches/oauth2-server.patch and
apply it to /app/oauth2-server so the patching step is stable across builds.

In
`@packages/nvidia_nat_core/tests/nat/front_ends/fastapi/test_websocket_route_origin.py`:
- Around line 21-47: Add an explicit empty-string origin case to the
pytest.parametrize matrix for
"origin,allowed_origins,allow_origin_regex,expected": include ("", ["*"], None,
False) (or similar with other allowed_origins like ["http://localhost:3000"] and
regex r".*" expecting False) so the helper's falsy-origin guard (the if not
origin check) is exercised for "" as well as None; modify the parameter list
inside the pytest.mark.parametrize block in test_websocket_route_origin.py to
include this tuple.

---

Nitpick comments:
In `@packages/nvidia_nat_core/src/nat/front_ends/fastapi/routes/auth.py`:
- Around line 53-89: Centralize the HTML response selection and creation so the
four branches (cancellation/error/success) only set the response content source
and any flags, then a single HTMLResponse is constructed once; inside the oauth
redirect handler (around the block using state, error, flow_state,
worker._remove_flow), replace duplicated HTMLResponse return sites by setting a
local variable (e.g. response_html) to either
build_auth_redirect_cancelled_html(flow_state.return_url) or
AUTH_REDIRECT_CANCELLED_POPUP_HTML (for access_denied) and similarly set
response_html to build_auth_redirect_error_html(...) or AUTH_REDIRECT_ERROR_HTML
for other errors (and success paths elsewhere), then after branch logic call a
single return HTMLResponse(content=response_html, status_code=200,
headers={...}) so the use of build_auth_redirect_cancelled_html,
build_auth_redirect_error_html, AUTH_REDIRECT_CANCELLED_POPUP_HTML,
AUTH_REDIRECT_ERROR_HTML, flow_state.config.use_redirect_auth, and
flow_state.return_url are the only symbols to touch.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 493caccc-5cf4-4c09-92bf-9528d76f6828

📥 Commits

Reviewing files that changed from the base of the PR and between 1221391 and 9c846fd.

📒 Files selected for processing (19)
  • docs/source/components/auth/api-authentication.md
  • examples/front_ends/simple_auth/Dockerfile
  • examples/front_ends/simple_auth/patches/oauth2-server.patch
  • examples/front_ends/simple_auth/src/nat_simple_auth/configs/config.yml
  • packages/nvidia_nat_core/src/nat/authentication/oauth2/oauth2_auth_code_flow_provider_config.py
  • packages/nvidia_nat_core/src/nat/data_models/interactive.py
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/auth_flow_handlers/websocket_flow_handler.py
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/html_snippets/auth_code_grant_cancelled.py
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/html_snippets/auth_code_grant_error.py
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/html_snippets/auth_code_grant_success.py
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/routes/auth.py
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/routes/websocket.py
  • packages/nvidia_nat_core/tests/nat/builder/test_interactive.py
  • packages/nvidia_nat_core/tests/nat/front_ends/auth_flow_handlers/test_websocket_flow_handler.py
  • packages/nvidia_nat_core/tests/nat/front_ends/fastapi/test_auth_code_grant_cancelled.py
  • packages/nvidia_nat_core/tests/nat/front_ends/fastapi/test_auth_code_grant_error.py
  • packages/nvidia_nat_core/tests/nat/front_ends/fastapi/test_auth_code_grant_success.py
  • packages/nvidia_nat_core/tests/nat/front_ends/fastapi/test_auth_redirect_route.py
  • packages/nvidia_nat_core/tests/nat/front_ends/fastapi/test_websocket_route_origin.py
✅ Files skipped from review due to trivial changes (6)
  • examples/front_ends/simple_auth/src/nat_simple_auth/configs/config.yml
  • docs/source/components/auth/api-authentication.md
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/html_snippets/auth_code_grant_success.py
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/html_snippets/auth_code_grant_error.py
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/auth_flow_handlers/websocket_flow_handler.py
  • packages/nvidia_nat_core/tests/nat/front_ends/fastapi/test_auth_code_grant_success.py
🚧 Files skipped from review as they are similar to previous changes (6)
  • examples/front_ends/simple_auth/patches/oauth2-server.patch
  • packages/nvidia_nat_core/tests/nat/builder/test_interactive.py
  • packages/nvidia_nat_core/src/nat/data_models/interactive.py
  • packages/nvidia_nat_core/tests/nat/front_ends/fastapi/test_auth_code_grant_error.py
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/routes/websocket.py
  • packages/nvidia_nat_core/tests/nat/front_ends/fastapi/test_auth_code_grant_cancelled.py

Comment thread examples/front_ends/simple_auth/Dockerfile Outdated
- pin oauth2-server clone to deterministic commit
- add empty-string origin test cases

Signed-off-by: Patrick Chin <8509935+thepatrickchin@users.noreply.github.com>
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.

Add option to enable redirect-based OAuth flow

1 participant