microsoft / microsoft/simplechat
Logout returns 404 at /.auth/logout when App Service Easy Auth is not actually enabled
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 152
- Forks
- 116
- Avg merge
- 7h 7m
- Merged PRs (30d)
- 122
Description
## Summary
Logout can redirect to `/.auth/logout?post_logout_redirect_uri=%2Flogin` and return a **404** on Azure App Service deployments that are not actually serving App Service Easy Auth.
This was first reported on a development custom domain, but it is **not** limited to development environments. Any deployment matching the same conditions is affected, **including production**.
## Root Cause
`_use_app_service_easy_auth_logout()` in `application/single_app/route_frontend_authentication.py` treated the `WEBSITE_AUTH_AAD_ALLOWED_TENANTS` environment variable as proof that Easy Auth was intercepting requests:
```python
return any(easy_auth_headers) or bool(os.getenv('WEBSITE_AUTH_AAD_ALLOWED_TENANTS'))
```
That variable is **not** a reliable Easy Auth signal. SimpleChat's own advanced configuration guidance in `application/single_app/example_advance_edit_environment_variables.json` instructs operators to set it by hand:
```json
{ "name": "WEBSITE_AUTH_AAD_ALLOWED_TENANTS", "value": "", "slotSetting": false }
```
So any deployment that followed those documented instructions on App Service, without Easy Auth actually enabled, was misdetected. Logout then redirected to a platform endpoint the App Service was not serving, producing the 404.
A secondary case exists where Easy Auth genuinely **is** enabled but `/.auth/*` is not routed through to the App Service origin, for example behind a custom domain, gateway, or Front Door with restrictive path routing. Per-request detection cannot distinguish that case, so it needs an explicit opt-out.
## Impact
- User-initiated logout (`/logout`, `/logout/local`) returns a 404 instead of completing.
- Idle-timeout logout inherits the same behavior, since it routes through `local_logout` (`app.py:1003`).
- Affects production as well as non-production deployments.
**Not affected:** local development. `WEBSITE_HOSTNAME` is unset outside App Service, so the check returns early. The originally reported failure was a deployed non-production App Service, not a localhost session.
## Expected Behavior
| Environment | Easy Auth headers | Expected logout path |
| --- | --- | --- |
| Local machine (`python app.py`) | No | Local logout |
| App Service, Easy Auth enabled | Yes | Easy Auth logout via `/.auth/logout` |
| App Service, Easy Auth not enabled | No | Local logout |
| Easy Auth enabled, `/.auth/*` not routed | Yes | Local logout via explicit opt-out |
## Resolution
Detection now relies only on the `X-MS-CLIENT-PRINCIPAL`, `X-MS-CLIENT-PRINCIPAL-ID`, and `X-MS-CLIENT-PRINCIPAL-NAME` headers that App Service injects into requests it actually intercepts. This is a per-request signal, so it corrects both development and production while preserving Easy Auth logout wherever Easy Auth is genuinely active.
Supporting changes:
- Added `DISABLE_APP_SERVICE_EASY_AUTH_LOGOUT` for the unroutable-`/.auth/*` case.
- Added debug logging of the logout path decision, visible with `FLASK_DEBUG=1`.
- Documented behavior per environment and logout-404 troubleshooting in `docs/explanation/running_simplechat_locally.md` and `application/single_app/example.env`.
- Removed a hardcoded customer hostname from the test fixture, since this repository is public.
## Validation
- `functional_tests/test_app_service_easy_auth_logout.py` — 5/5 passing
- `functional_tests/test_idle_logout_timeout.py` — 4/4 passing
- `functional_tests/route_tests/` — 12/12 passing
- `scripts/check_swagger_routes.py`, `scripts/check_xss_sinks.py`, `scripts/check_broken_access_control.py` — all passing
## References
- Fix: #1321 (authored by @chadpalmer)
- Documentation: `docs/explanation/fixes/EASY_AUTH_LOGOUT_DETECTION_FIX.md`
- Released in version `0.260.019`
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with _use_app_service_easy_auth_logout() in application/single_app/route_frontend_authentication.py and review the configuration and documentation files named in the issue. Run functional_tests/test_app_service_easy_auth_logout.py and functional_tests/test_idle_logout_timeout.py, then verify the route tests and security checks listed under Validation. Done means logout uses the expected path in each environment without a 404.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- azure, python
- Domain
- authentication, cloud
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 25/100