microsoft / microsoft/simplechat

Logout returns 404 at /.auth/logout when App Service Easy Auth is not actually enabled

Open
#1,324 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug P2
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.