Conversation
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
The current implementatoin is only for Teams so it's not consistent across the app. There's also no way to configure the expected origin, which means you would be able to run this app behind a proxy or in kubernetes. Holding off for more robust implementation.
There was a problem hiding this comment.
Pull request overview
Adds Microsoft Teams app + Teams SSO (OBO flow) support to SimpleChat, along with deployment/config updates and documentation so the app can be embedded and authenticated inside the Teams client.
Changes:
- Add a Teams-aware login experience (
login.html) and a new backend token exchange endpoint for Teams SSO (/auth/teams/token-exchange). - Introduce Teams SSO configuration/env vars and adjust security headers + session cookie settings to support iframe embedding.
- Add Teams app packaging assets (manifest template + icons), docs/how-to guidance, and update release notes + bicep deployment parameters.
Reviewed changes
Copilot reviewed 9 out of 13 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
docs/how-to/teams_app.md |
New how-to for configuring Teams app + SSO, env vars, and troubleshooting. |
docs/explanation/release_notes.md |
Release notes entry for Teams app/SSO and bicep fix. |
deployers/bicep/main.bicep |
Adds enableTeamsSso param; updates ACR suffix to environment-driven value. |
deployers/bicep/modules/appService.bicep |
Wires enableTeamsSso into app settings (ENABLE_TEAMS_SSO). |
application/teams_app/manifest.template.json |
Template Teams manifest for SSO-enabled tab. |
application/teams_app/color.png / outline.png |
Teams app icon assets. |
application/single_app/templates/login.html |
New Teams detection + SSO login page with fallback to normal AAD auth. |
application/single_app/static/js/MicrosoftTeams.min.js |
Bundled Teams JS SDK for offline/disconnected scenarios. |
application/single_app/route_frontend_authentication.py |
Adds Teams login routing behavior + token exchange endpoint. |
application/single_app/config.py |
Adds Teams SSO config + CSP frame-ancestors behavior; version bump. |
application/single_app/app.py |
Sets cookie attributes needed for Teams iframe embedding when Teams SSO enabled. |
.gitignore |
Ignores a generated application/teams_app/manifest.json. |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds Microsoft Teams app packaging + SSO support to SimpleChat, wiring a Teams-aware login experience into the existing Flask/MSAL auth flow and updating deployment/config/docs accordingly.
Changes:
- Added Teams-aware
login.html+ local Teams JS SDK and a new/auth/teams/token-exchangeendpoint for OBO token exchange. - Introduced Teams SSO configuration knobs (
ENABLE_TEAMS_SSO, CSPframe-ancestorshandling, session cookie settings). - Added Teams app package templates/assets + deployment plumbing (Bicep param + env var) and documentation/release notes.
Reviewed changes
Copilot reviewed 9 out of 13 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
docs/how-to/teams_app.md |
New how-to guide for Teams app + SSO configuration and troubleshooting. |
docs/explanation/release_notes.md |
Release notes entry for Teams SSO + related infra changes. |
deployers/bicep/modules/appService.bicep |
Adds enableTeamsSso param and sets ENABLE_TEAMS_SSO app setting. |
deployers/bicep/main.bicep |
Plumbs enableTeamsSso through and uses az.environment().suffixes.acrLoginServer for ACR suffix. |
application/teams_app/manifest.template.json |
Teams manifest template with SSO-ready webApplicationInfo and tab URLs. |
application/teams_app/color.png |
Teams app icon asset. |
application/teams_app/outline.png |
Teams app outline icon asset. |
application/single_app/templates/login.html |
New Teams-aware sign-in page that attempts Teams SSO and falls back to standard login. |
application/single_app/static/js/MicrosoftTeams.min.js |
Vendored Teams JS SDK for disconnected environments. |
application/single_app/route_frontend_authentication.py |
Adds Teams SSO branching in /login and implements /auth/teams/token-exchange. |
application/single_app/config.py |
Version bump + Teams SSO env vars + CSP frame-ancestors composition and conditional X-Frame-Options. |
application/single_app/app.py |
Adjusts session cookie settings for iframe embedding when Teams SSO is enabled. |
.gitignore |
Ignores generated application/teams_app/manifest.json. |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds Microsoft Teams app packaging + documentation and wires up Teams SSO (OBO flow) into the existing Flask auth flow, alongside a small Bicep improvement for ACR suffix portability.
Changes:
- Introduces Teams SSO login flow (
/loginTeams-detecting page +/auth/teams/token-exchangeOBO endpoint) and adjusts cookies/CSP to support iframe embedding. - Adds Teams app package assets (manifest template + icons) and a how-to guide for setup/troubleshooting.
- Updates Bicep to use
az.environment().suffixes.acrLoginServerand adds anenableTeamsSsodeployment parameter.
Reviewed changes
Copilot reviewed 9 out of 13 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| docs/how-to/teams_app.md | New how-to guide for Teams SSO configuration and troubleshooting. |
| docs/explanation/release_notes.md | Release notes entry for Teams integration + Bicep fix. |
| deployers/bicep/modules/appService.bicep | Adds enableTeamsSso param and sets ENABLE_TEAMS_SSO app setting. |
| deployers/bicep/main.bicep | Plumbs enableTeamsSso parameter; uses environment-derived ACR suffix. |
| application/teams_app/outline.png | Teams app outline icon asset. |
| application/teams_app/color.png | Teams app color icon asset. |
| application/teams_app/manifest.template.json | Teams manifest template configured for tab + SSO fields. |
| application/single_app/templates/login.html | New Teams-aware login page that attempts Teams SSO then falls back. |
| application/single_app/static/js/MicrosoftTeams.min.js | Bundled Teams JS SDK for disconnected environments. |
| application/single_app/route_frontend_authentication.py | Implements Teams login branching and token-exchange endpoint. |
| application/single_app/config.py | Adds Teams SSO config/env vars and CSP frame-ancestors handling; bumps version. |
| application/single_app/app.py | Sets session cookie attributes for Teams iframe compatibility when enabled. |
| .gitignore | Ignores generated Teams manifest.json. |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds Microsoft Teams tab packaging + Teams SSO (OBO) support to SimpleChat, including deployment toggles, CSP/cookie adjustments for iframe embedding, and documentation/templates for configuring the Teams app.
Changes:
- Adds Teams SSO login UX (
/login?teams=true) and a backend token-exchange endpoint (/auth/teams/token-exchange) using MSAL OBO. - Updates security headers and session cookie settings to support Teams iframe embedding.
- Adds Teams app packaging assets (manifest template + icons) and how-to documentation; updates Bicep and release notes.
Reviewed changes
Copilot reviewed 9 out of 13 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| docs/how-to/teams_app.md | New how-to guide for Teams app + SSO configuration. |
| docs/explanation/release_notes.md | Release notes entry for Teams app/SSO and Bicep ACR suffix fix. |
| deployers/bicep/modules/appService.bicep | Adds enableTeamsSso param and sets ENABLE_TEAMS_SSO app setting. |
| deployers/bicep/main.bicep | Plumbs enableTeamsSso into app service module; fixes ACR suffix via az.environment().suffixes.acrLoginServer. |
| application/teams_app/manifest.template.json | Teams manifest template for packaging a personal tab with SSO fields. |
| application/teams_app/color.png | Teams app icon asset (color). |
| application/teams_app/outline.png | Teams app icon asset (outline). |
| application/single_app/templates/login.html | New Teams-aware login page that attempts Teams SSO then falls back to standard Azure AD. |
| application/single_app/static/js/MicrosoftTeams.min.js | Bundled Teams JS SDK for offline/disconnected environments. |
| application/single_app/route_frontend_authentication.py | Adds Teams SSO entry path and /auth/teams/token-exchange endpoint. |
| application/single_app/config.py | Adds Teams SSO env vars; updates CSP frame-ancestors; bumps version. |
| application/single_app/app.py | Sets SameSite=None/Secure/HttpOnly session cookie flags when Teams SSO is enabled. |
| .gitignore | Ignores generated application/teams_app/manifest.json. |
|
@clarked-msft Could you resolve the conflicts so I can review? |
Fixed... release_notes probably needs work. Looks like merge conflicts had previously been merged to Development. |
There was a problem hiding this comment.
Pull request overview
Adds Microsoft Teams “tab app” support for SimpleChat with Teams SSO (OBO) login flow, plus deployment knobs and documentation so the app can be embedded in Teams and authenticate seamlessly.
Changes:
- Introduces a Teams-aware
/loginexperience and a new/auth/teams/token-exchangeendpoint to perform MSAL OBO token exchange. - Adds Teams SSO configuration and CSP/session-cookie adjustments for iframe embedding, plus a Bicep parameter to toggle Teams SSO.
- Adds Teams app manifest/icon templates and documentation, and updates release notes.
Reviewed changes
Copilot reviewed 9 out of 13 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| docs/how-to/teams_app.md | New how-to guide for configuring Teams app + SSO prerequisites/troubleshooting. |
| docs/explanation/release_notes.md | Documents Teams SSO feature + related deployment changes (currently duplicated in-file). |
| deployers/bicep/modules/appService.bicep | Adds enableTeamsSso param and wires ENABLE_TEAMS_SSO app setting. |
| deployers/bicep/main.bicep | Adds enableTeamsSso param + uses az.environment().suffixes.acrLoginServer for ACR suffix. |
| application/teams_app/manifest.template.json | Adds Teams manifest template placeholders for HOSTNAME/CLIENT_ID. |
| application/teams_app/color.png | Teams app icon asset. |
| application/teams_app/outline.png | Teams app icon asset. |
| application/single_app/templates/login.html | New Teams-detecting login page with SSO + fallback to standard Azure AD login. |
| application/single_app/static/js/MicrosoftTeams.min.js | Vendored Teams JS SDK for offline/disconnected environments. |
| application/single_app/route_frontend_authentication.py | Adds Teams-aware login path + token-exchange endpoint. |
| application/single_app/config.py | Adds Teams SSO env vars and updates CSP/X-Frame-Options behavior for Teams embedding. |
| application/single_app/app.py | Sets session cookie attributes required for cross-origin iframe scenarios when Teams SSO enabled. |
| .gitignore | Ignores application/teams_app/manifest.json (generated/customized manifest). |
| * **Microsoft Teams App Integration with SSO** | ||
| * Added full Microsoft Teams application support with Single Sign-On (SSO) using the On-Behalf-Of (OBO) flow. Users embedded in Teams are automatically authenticated without a separate login. | ||
| * New `/auth/teams/token-exchange` backend endpoint exchanges Teams SSO tokens for access tokens via MSAL OBO flow, with session persistence and activity logging. | ||
| * New `login.html` template with Teams SDK detection, automatic SSO authentication, consent-required handling, and graceful fallback to standard Azure AD login. | ||
| * Teams manifest template (`manifest.template.json`) with SSO-ready `webApplicationInfo`, static tab, and valid domain configuration. | ||
| * New environment variables: `TEAMS_FRAME_ANCESTORS`, `CUSTOM_TEAMS_ORIGINS`, and `ENABLE_TEAMS_SSO` for configurable Teams SSO behaviour. | ||
| * Content Security Policy `frame-ancestors` directive now dynamically includes Teams domains via `TEAMS_FRAME_ANCESTORS` setting. | ||
| * Session cookies updated to `SameSite=None`, `Secure=True`, `HttpOnly=True` to support cross-origin Teams iframe embedding. | ||
| * (Ref: `route_frontend_authentication.py`, `login.html`, `config.py`, `app.py`, `manifest.template.json`, Teams SSO, OBO flow) | ||
|
|
||
| * **Teams App Manifest and Icons** | ||
| * Added Teams app package files: `manifest.template.json`, `color.png` (192×192), and `outline.png` (32×32) under `application/teams_app/`. | ||
| * Template manifest includes placeholders for hostname, client ID, and Application ID URI for easy customisation per deployment. | ||
| * (Ref: `application/teams_app/`, Teams app packaging) | ||
|
|
||
| * **Teams App Configuration Documentation** | ||
| * Comprehensive how-to guide covering Azure AD app registration for Teams SSO, pre-authorised Teams client IDs, environment variables, manifest configuration, testing steps, and troubleshooting. | ||
| * (Ref: `docs/how-to/teams_app.md`) |
There was a problem hiding this comment.
The Teams SSO feature block is duplicated in two different places in the release notes (once under v0.241.006 at the top, and again later in the file). This makes the changelog confusing and risks the same content being maintained in multiple spots; keep a single entry in the appropriate version section and remove the duplicate block.
| ENABLE_TEAMS_SSO = os.getenv("ENABLE_TEAMS_SSO", "false").lower() == "true" | ||
| TEAMS_FRAME_ANCESTORS = os.getenv("TEAMS_FRAME_ANCESTORS", "") # e.g. "https://teams.microsoft.com https://*.teams.microsoft.com" - should be set to Teams domains if in airgap, otherwise can be left blank to allow from any domain since we validate the origin in the frontend against allowed Teams domains | ||
| CUSTOM_TEAMS_ORIGINS_RAW = os.getenv("CUSTOM_TEAMS_ORIGINS", "") # JSON array of valid domains for Teams SSO if in airgap, otherwise this is pulled from Teams, e.g. ["https://teams.microsoft.com", "https://*.teams.microsoft.com"] | ||
| CUSTOM_TEAMS_ORIGINS = json.loads(CUSTOM_TEAMS_ORIGINS_RAW) if CUSTOM_TEAMS_ORIGINS_RAW else [] |
There was a problem hiding this comment.
The comment on TEAMS_FRAME_ANCESTORS says it can be left blank to allow framing from any domain, but the CSP is always built as frame-ancestors 'self' {TEAMS_FRAME_ANCESTORS}; so a blank value will only allow 'self' and will block Teams iframe embedding. Either require/populate TEAMS_FRAME_ANCESTORS when ENABLE_TEAMS_SSO is true (especially for AZURE_ENVIRONMENT=="custom"), or update the comment/logic so the behavior matches the guidance.
| data = request.get_json() | ||
| teams_token = data.get('token') or {} | ||
|
|
There was a problem hiding this comment.
request.get_json() can return None (missing/invalid JSON body or wrong Content-Type). The next line calls data.get(...), which will raise and return a 500. Handle a non-dict JSON body explicitly and return a 400 with a clear error instead of falling into the generic exception handler.
| data = request.get_json() | |
| teams_token = data.get('token') or {} | |
| data = request.get_json(silent=True) | |
| if not isinstance(data, dict): | |
| return jsonify({ | |
| "error": "invalid_request", | |
| "error_description": "Request body must be a valid JSON object." | |
| }), 400 | |
| teams_token = data.get("token") |
| # Store user identity info from ID token claims | ||
| session["user"] = result.get("id_token_claims") | ||
|
|
||
| # Save the token cache to session | ||
| _save_cache(msal_app.token_cache) | ||
|
|
||
| user_name = session['user'].get('name', 'Unknown') | ||
| log_event(f"Teams SSO: User {user_name} authenticated successfully.") |
There was a problem hiding this comment.
This endpoint assumes result.get("id_token_claims") exists and is a dict, but config.SCOPE is Graph-only (no openid/profile/email), so the OBO result may not include ID token claims. If session["user"] becomes None, session['user'].get(...) will throw and the login will fail. Populate session user data from a reliable source (e.g., decode the incoming Teams JWT assertion claims, or call Graph /me with the acquired access token) and guard against missing claims.
| if "error" in result: | ||
| error_description = result.get("error_description", result.get("error")) | ||
| log_event(f"Teams token exchange failure: {error_description}", exceptionTraceback=True) | ||
| return jsonify({ | ||
| "error": result.get("error"), | ||
| "error_description": error_description | ||
| }), 400 |
There was a problem hiding this comment.
log_event(..., exceptionTraceback=True) is used here on a non-exception error path and with the default INFO level, which can emit misleading NoneType: None tracebacks. Log this as an error-level event (and include structured properties like MSAL error code/description) without forcing an exception traceback unless you’re inside an actual exception handler.
| <!DOCTYPE html> | ||
| <html lang="en"> | ||
| <head> | ||
| <meta charset="UTF-8"> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
| <title>Sign In - {{ app_settings.app_title or 'SimpleChat' }}</title> | ||
| <link href="{{ url_for('static', filename='css/bootstrap.min.css') }}" rel="stylesheet"> | ||
| <link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap-icons.min.css') }}"> | ||
| <style> | ||
| body { | ||
| font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; | ||
| display: flex; | ||
| justify-content: center; | ||
| align-items: center; | ||
| min-height: 100vh; | ||
| margin: 0; | ||
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | ||
| } | ||
| .login-container { | ||
| text-align: center; | ||
| max-width: 420px; | ||
| width: 100%; | ||
| padding: 3rem; | ||
| background: white; | ||
| border-radius: 12px; | ||
| box-shadow: 0 10px 40px rgba(0,0,0,0.2); | ||
| } | ||
| .logo-section { | ||
| margin-bottom: 2rem; | ||
| } |
There was a problem hiding this comment.
This PR introduces a new login.html page and client-side authentication flow (Teams detection + fallback) but doesn’t add/update any Playwright UI coverage. Add a UI test under ui_tests/ that at least validates the login page renders, the loading/error states toggle correctly, and the non-Teams fallback path is reachable (e.g., /login?teams=false).
| # Security Headers Configuration | ||
| SECURITY_HEADERS = { | ||
| 'X-Content-Type-Options': 'nosniff', | ||
| 'X-XSS-Protection': '1; mode=block', | ||
| 'Referrer-Policy': 'strict-origin-when-cross-origin', | ||
| 'Content-Security-Policy': ( | ||
| "default-src 'self'; " | ||
| "script-src 'self' 'unsafe-inline' 'unsafe-eval'; " | ||
| #"script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net https://code.jquery.com https://stackpath.bootstrapcdn.com; " | ||
| "style-src 'self' 'unsafe-inline'; " | ||
| #"style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://stackpath.bootstrapcdn.com; " | ||
| "img-src 'self' data: https: blob:; " | ||
| "font-src 'self'; " | ||
| #"font-src 'self' https://cdn.jsdelivr.net https://stackpath.bootstrapcdn.com; " | ||
| "connect-src 'self' https: wss: ws:; " | ||
| "media-src 'self' blob:; " | ||
| "object-src 'none'; " | ||
| f"frame-ancestors 'self' {TEAMS_FRAME_ANCESTORS}; " | ||
| "base-uri 'self';" | ||
| ) | ||
| } | ||
|
|
||
| if not ENABLE_TEAMS_SSO: | ||
| SECURITY_HEADERS['X-Frame-Options'] = 'DENY' # Prevent framing if Teams SSO is not enabled |
There was a problem hiding this comment.
This PR includes runtime and deployer changes (not just docs), but VERSION in config.py is still 0.241.006. Repo instructions require bumping only the 3rd segment after code changes; please increment the version (e.g., to 0.241.007) and keep release notes aligned.
No description provided.