From 7136a60723ba437dc752481419e1308468cf4454 Mon Sep 17 00:00:00 2001 From: Chad Palmer Date: Fri, 7 Aug 2026 22:49:54 +0000 Subject: [PATCH 1/2] get-a-token-missing-auth-code-fix - updated missing auth code route to redirect to sign in index page. --- application/single_app/config.py | 2 +- .../route_frontend_authentication.py | 9 +- .../GETATOKEN_MISSING_CODE_REDIRECT_FIX.md | 37 +++++++ docs/explanation/release_notes.md | 9 ++ .../test_getatoken_missing_code_redirect.py | 100 ++++++++++++++++++ 5 files changed, 154 insertions(+), 3 deletions(-) create mode 100644 docs/explanation/fixes/GETATOKEN_MISSING_CODE_REDIRECT_FIX.md create mode 100644 functional_tests/test_getatoken_missing_code_redirect.py diff --git a/application/single_app/config.py b/application/single_app/config.py index ffb5634e..fe8f93be 100644 --- a/application/single_app/config.py +++ b/application/single_app/config.py @@ -96,7 +96,7 @@ EXECUTOR_TYPE = 'thread' EXECUTOR_MAX_WORKERS = 30 SESSION_TYPE = 'filesystem' -VERSION = "0.250.126" +VERSION = "0.250.127" IS_DEVELOPMENT = is_development_env_enabled() SESSION_COOKIE_SAMESITE = os.getenv('SESSION_COOKIE_SAMESITE', 'Lax') diff --git a/application/single_app/route_frontend_authentication.py b/application/single_app/route_frontend_authentication.py index 41f10bd0..c07b5151 100644 --- a/application/single_app/route_frontend_authentication.py +++ b/application/single_app/route_frontend_authentication.py @@ -217,8 +217,13 @@ def authorized(): code = request.args.get('code') if not code: - print("Authorization code not found in callback.") - return "Authorization code not found", 400 + log_event( + "[AUTH_CALLBACK] OAuth callback reached without an authorization code; redirecting to sign-in.", + extra={'path': request.path}, + level=logging.INFO, + debug_only=True, + ) + return redirect(url_for('public_app.index')) # Build MSAL app WITH session cache (will be loaded by _build_msal_app via _load_cache) msal_app = _build_msal_app(cache=_load_cache()) # Load existing cache diff --git a/docs/explanation/fixes/GETATOKEN_MISSING_CODE_REDIRECT_FIX.md b/docs/explanation/fixes/GETATOKEN_MISSING_CODE_REDIRECT_FIX.md new file mode 100644 index 00000000..b4ba7974 --- /dev/null +++ b/docs/explanation/fixes/GETATOKEN_MISSING_CODE_REDIRECT_FIX.md @@ -0,0 +1,37 @@ +# getAToken Missing Code Redirect Fix + +Fixed/Implemented in version: **0.250.127** + +## Issue Description + +Unauthenticated users who browsed directly to protected SimpleChat pages could be redirected to `/getAToken` without first completing Microsoft Entra sign-in. Because the OAuth callback did not receive an authorization `code`, the page returned an "Authorization code not found" error and created avoidable support tickets. + +## Root Cause Analysis + +The `/getAToken` frontend OAuth callback treated every request without a `code` query parameter as a failed callback. Direct browser visits to the callback path are not valid token exchanges, but they are recoverable user navigation events and should route users back to the normal sign-in entry point. + +## Technical Details + +Files modified: + +- `application/single_app/route_frontend_authentication.py` +- `application/single_app/config.py` +- `functional_tests/test_getatoken_missing_code_redirect.py` + +Code changes summary: + +- Updated the `/getAToken` callback missing-code branch to log the recoverable condition and redirect to `public_app.index`. +- Preserved the valid OAuth authorization-code exchange flow. +- Left `/getATokenApi` unchanged so API token callback callers still receive explicit request errors. +- Updated `config.py` version from `0.250.126` to `0.250.127`. + +## Validation + +Testing approach: + +- Added a focused functional regression test that verifies the `/getAToken` missing-code branch redirects to the home sign-in route instead of returning the previous error text. + +Impact analysis: + +- Users see the normal SimpleChat sign-in entry point rather than a technical OAuth callback error. +- Valid Microsoft Entra callback requests with authorization codes continue through the existing token redemption path. diff --git a/docs/explanation/release_notes.md b/docs/explanation/release_notes.md index 4085165f..15fc2334 100644 --- a/docs/explanation/release_notes.md +++ b/docs/explanation/release_notes.md @@ -2,6 +2,15 @@ For feature-focused and fix-focused drill-downs by version, see [Features by Version](/explanation/features/) and [Fixes by Version](/explanation/fixes/). +### **(v0.250.127)** + +#### Bug Fixes + +* **getAToken Missing Authorization Code Redirect** + * Redirects direct `/getAToken` browser visits without an OAuth authorization code back to the home sign-in page instead of showing a technical callback error. + * Preserves the normal Microsoft Entra authorization-code callback flow and keeps `/getATokenApi` explicit error behavior unchanged for API token callbacks. + * (Ref: `/getAToken` OAuth callback, `route_frontend_authentication.py`, `test_getatoken_missing_code_redirect.py`) + ### **(v0.250.126)** #### Bug Fixes diff --git a/functional_tests/test_getatoken_missing_code_redirect.py b/functional_tests/test_getatoken_missing_code_redirect.py new file mode 100644 index 00000000..d3ba4ecc --- /dev/null +++ b/functional_tests/test_getatoken_missing_code_redirect.py @@ -0,0 +1,100 @@ +# test_getatoken_missing_code_redirect.py +""" +Functional test for direct getAToken callback visits without an OAuth code. +Version: 0.250.127 +Implemented in: 0.250.127 + +This test ensures that users who reach /getAToken directly are redirected to +the home sign-in page instead of seeing an authorization-code error. +""" + +import ast +import sys +from pathlib import Path + + +ROOT_DIR = Path(__file__).resolve().parents[1] +AUTH_ROUTE_PATH = ROOT_DIR / "application" / "single_app" / "route_frontend_authentication.py" + + +def _find_authorized_function(tree): + for node in ast.walk(tree): + if isinstance(node, ast.FunctionDef) and node.name == "authorized": + return node + raise AssertionError("Could not find the /getAToken authorized route function.") + + +def _is_missing_code_branch(node): + return ( + isinstance(node, ast.If) + and isinstance(node.test, ast.UnaryOp) + and isinstance(node.test.op, ast.Not) + and isinstance(node.test.operand, ast.Name) + and node.test.operand.id == "code" + ) + + +def _returns_home_redirect(node): + if not isinstance(node, ast.Return): + return False + value = node.value + return ( + isinstance(value, ast.Call) + and isinstance(value.func, ast.Name) + and value.func.id == "redirect" + and len(value.args) == 1 + and isinstance(value.args[0], ast.Call) + and isinstance(value.args[0].func, ast.Name) + and value.args[0].func.id == "url_for" + and len(value.args[0].args) == 1 + and isinstance(value.args[0].args[0], ast.Constant) + and value.args[0].args[0].value == "public_app.index" + ) + + +def _returns_authorization_code_error(node): + if not isinstance(node, ast.Return): + return False + value = node.value + if isinstance(value, ast.Constant): + return value.value == "Authorization code not found" + if isinstance(value, ast.Tuple): + return any( + isinstance(element, ast.Constant) + and element.value == "Authorization code not found" + for element in value.elts + ) + return False + + +def test_getatoken_missing_code_redirects_home(): + """Validate that /getAToken without a code redirects to the sign-in entry point.""" + print("Testing /getAToken missing authorization-code redirect...") + + tree = ast.parse(AUTH_ROUTE_PATH.read_text(encoding="utf-8")) + authorized_function = _find_authorized_function(tree) + missing_code_branches = [ + node for node in ast.walk(authorized_function) if _is_missing_code_branch(node) + ] + + if len(missing_code_branches) != 1: + raise AssertionError(f"Expected exactly one missing-code branch, found {len(missing_code_branches)}.") + + missing_code_branch = missing_code_branches[0] + if not any(_returns_home_redirect(node) for node in missing_code_branch.body): + raise AssertionError("Expected missing-code branch to redirect to public_app.index.") + + if any(_returns_authorization_code_error(node) for node in missing_code_branch.body): + raise AssertionError("Missing-code branch must not return the authorization-code error to users.") + + print("/getAToken missing-code requests redirect to the sign-in entry point.") + + +if __name__ == "__main__": + try: + test_getatoken_missing_code_redirects_home() + except Exception as exc: + print(f"Test failed: {exc}") + sys.exit(1) + + print("All getAToken missing-code redirect tests passed") From 6b28e546a4b76b983a5c1ee461f52182cf1fb7ae Mon Sep 17 00:00:00 2001 From: Chad Palmer Date: Fri, 7 Aug 2026 23:04:08 +0000 Subject: [PATCH 2/2] get-a-token-missing-auth-code-fix - fixed metadata versions. --- docs/explanation/fixes/GETATOKEN_MISSING_CODE_REDIRECT_FIX.md | 4 ++-- docs/explanation/release_notes.md | 2 +- functional_tests/test_getatoken_missing_code_redirect.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/explanation/fixes/GETATOKEN_MISSING_CODE_REDIRECT_FIX.md b/docs/explanation/fixes/GETATOKEN_MISSING_CODE_REDIRECT_FIX.md index b4ba7974..72cd27a7 100644 --- a/docs/explanation/fixes/GETATOKEN_MISSING_CODE_REDIRECT_FIX.md +++ b/docs/explanation/fixes/GETATOKEN_MISSING_CODE_REDIRECT_FIX.md @@ -1,6 +1,6 @@ # getAToken Missing Code Redirect Fix -Fixed/Implemented in version: **0.250.127** +Fixed/Implemented in version: **0.250.129** ## Issue Description @@ -23,7 +23,7 @@ Code changes summary: - Updated the `/getAToken` callback missing-code branch to log the recoverable condition and redirect to `public_app.index`. - Preserved the valid OAuth authorization-code exchange flow. - Left `/getATokenApi` unchanged so API token callback callers still receive explicit request errors. -- Updated `config.py` version from `0.250.126` to `0.250.127`. +- Updated `config.py` version to `0.250.129` after merging the latest `Development` changes. ## Validation diff --git a/docs/explanation/release_notes.md b/docs/explanation/release_notes.md index 3808a1bc..cdbfa23d 100644 --- a/docs/explanation/release_notes.md +++ b/docs/explanation/release_notes.md @@ -10,7 +10,7 @@ For feature-focused and fix-focused drill-downs by version, see [Features by Ver * Redirects direct `/getAToken` browser visits without an OAuth authorization code back to the home sign-in page instead of showing a technical callback error. * Preserves the normal Microsoft Entra authorization-code callback flow and keeps `/getATokenApi` explicit error behavior unchanged for API token callbacks. * (Ref: `/getAToken` OAuth callback, `route_frontend_authentication.py`, `test_getatoken_missing_code_redirect.py`) - + ### **(v0.250.128)** #### Bug Fixes diff --git a/functional_tests/test_getatoken_missing_code_redirect.py b/functional_tests/test_getatoken_missing_code_redirect.py index d3ba4ecc..4b375828 100644 --- a/functional_tests/test_getatoken_missing_code_redirect.py +++ b/functional_tests/test_getatoken_missing_code_redirect.py @@ -1,8 +1,8 @@ # test_getatoken_missing_code_redirect.py """ Functional test for direct getAToken callback visits without an OAuth code. -Version: 0.250.127 -Implemented in: 0.250.127 +Version: 0.250.129 +Implemented in: 0.250.129 This test ensures that users who reach /getAToken directly are redirected to the home sign-in page instead of seeing an authorization-code error.