Skip to content

Microsoft Teams Integration

Release status: not production-ready

The backend contains Teams tools and Microsoft Graph client code, but the frontend catalogue currently sets live: false. Treat this integration as unavailable for general user use until the connection flow and all release gates in this document have been verified.

Initial release must be strictly read-only

Message sending must be blocked server-side. OAuth security, delegated permissions, tenant restrictions, token resolution, and the complete user-facing connection flow must be tested before production approval. A confirmation prompt is not a substitute for denying write operations.

This page documents the implementation represented in the source repository. Source code presence is not proof of end-to-end functionality or production readiness. Findings and verification requirements are distinguished throughout.

At a glance

Area Current source baseline Release implication
Frontend catalogue live: false Teams is not marked live in the frontend catalogue.
Backend tools Read and write tools are registered Enforce a server-side read-only allowlist.
OAuth scopes Includes write-capable scopes Reduce scopes to the minimum required for approved read operations.
OAuth protection PKCE is not demonstrated; JWT is passed in a query parameter Review and harden the authorization flow.
Token resolution Integrations endpoint plus a fallback path Verify fail-closed behavior and use one authoritative resolver.
Graph behavior Pagination and message-search support require verification Validate actual tenant behavior before promising completeness.

How to read this page

Current implementation describes behavior indicated by the source. Required before release identifies work or verification that remains outstanding. Do not interpret a listed test or requirement as evidence that it has already passed.

Implementation status: Backend tools, Microsoft Graph client functions, and OAuth handlers exist in the repository. The frontend integration catalogue currently marks Microsoft Teams as live: false.

Initial release requirement: The intended release is read-only. Message sending must be blocked, OAuth and Graph permissions must be validated, and the complete user-facing connection flow must be verified before production approval.

1. Purpose

The Microsoft Teams integration is intended to let WhiteLotusAI retrieve authorized Microsoft 365 and Teams information.

The current source defines tools for:

  • Listing teams the user has joined.

  • Listing channels in a team.

  • Retrieving recent channel messages.

  • Retrieving the current user's profile.

  • Listing team members.

  • Searching messages in a team.

  • Sending a message to a Teams channel.

The initial release must be read-only. Sending messages is a state-changing operation and must remain unavailable until explicitly approved for a later release.

The existence of backend code does not prove that all operations work with the configured Microsoft tenant, delegated permissions, or frontend connection flow.

2. Current implementation status

The frontend catalogue is defined in frontend/src/lib/plugins.ts. The Microsoft Teams entry has:

  • Provider ID: teams

  • Display name: Microsoft Teams

  • Authentication label: Sign in with Microsoft

  • live: false

Treat this as the current frontend catalogue status. It does not establish that the integration is enabled for users or that every backend endpoint is functional.

The chat plugin is implemented in chat/package/app/plugins/teams/plugin.py. Its health_check checks the Microsoft identity platform's OpenID configuration endpoint; this verifies identity-provider connectivity, not successful access to the user's Teams data.

3. Registered tools

The Teams plugin registers the following tools.

Tool Category Purpose Initial read-only release
list_teams READ List teams the user has joined Allowed after verification
list_channels READ List channels for a team Allowed after verification
get_messages READ Retrieve recent messages from a channel Allowed after verification
get_user_info READ Retrieve the current user's Microsoft 365 profile Allowed after verification
list_members READ List members of a team Allowed after verification
search_messages READ Search messages in a team Allowed after verification
send_message WRITE Send a message to a channel Must be blocked

The send_message tool requires confirmation and has a configured rate limit of 10. Confirmation is not equivalent to a strict read-only boundary. The server-side execution path must reject message sending before it reaches Microsoft Graph.

The read tools have configured rate limits of 30. These are application-level rate-limit settings, not substitutes for Microsoft Graph throttling handling.

4. Architecture and request flow

The principal source files are:

  • chat/package/app/plugins/teams/plugin.py — tool definitions, token retrieval, dispatch, and result sanitization.

  • chat/package/app/plugins/teams/client.py — Microsoft Graph requests made by the chat-side plugin.

  • integrations/package/app/handlers/integration_handlers.py — Teams OAuth handlers, token resolution, and HTTP routes.

  • integrations/package/app/managers/teams_client.py — Microsoft Graph client functions used by the integrations service.

  • chat/package/app/plugins/registry.py — tool registration, permission checks, and dispatch.

  • chat/package/app/plugins/permissions.py — default tool-category permission policy.

  • frontend/src/lib/plugins.ts — frontend catalogue status.

The intended user-facing flow is:

  1. The user authenticates with WhiteLotusAI.

  2. The user connects Microsoft Teams through the Microsoft identity platform.

  3. The OAuth callback stores the resulting credentials against the correct WhiteLotusAI user.

  4. The chat service selects an approved Teams tool.

  5. The plugin retrieves a valid access token.

  6. The client calls Microsoft Graph.

  7. The result is sanitized and returned through the chat service.

The current implementation contains both a chat-side Graph client and an integrations-service Graph client. Verify which paths are active in the deployed application and ensure that they follow the same authorization, timeout, error-handling, and read-only policies.

Request-flow overview

flowchart TD
    U["User request"] --> AUTH["WhiteLotusAI authentication"]
    AUTH --> O["Chat orchestrator"]
    O --> P{"Approved read tool?"}
    P -- "No" --> DENY["Reject request"]
    P -- "Yes" --> TOK["Resolve user's Teams token"]
    TOK --> GRAPH["Microsoft Graph API"]
    GRAPH --> SAN["Sanitize and limit result"]
    SAN --> RESP["Return result through chat"]
    DENY --> RESP

    classDef primary fill:#e8eaf6,stroke:#5e35b1,color:#202124
    classDef safe fill:#e0f2f1,stroke:#00897b,color:#173b37
    classDef blocked fill:#fff3e0,stroke:#ef6c00,color:#4e342e
    class U,AUTH,O,TOK,GRAPH,SAN,RESP primary
    class P safe
    class DENY blocked

The diagram shows the intended guarded flow, not proof that every deployed path currently enforces these controls. Mermaid's neutral text and contrasting fills are chosen to remain legible in light and dark documentation themes; if the configured renderer overrides diagram colors, confirm contrast in both modes.

5. Microsoft Graph operations

The client uses Microsoft Graph API v1.0 at https\://graph.microsoft.com/v1.0.

5.1 List teams

The client calls:

GET /me/joinedTeams

It returns the value array from the Graph response.

The implementation does not paginate through all results. Do not claim exhaustive team listing for users who belong to many teams unless pagination is implemented and tested.

5.2 List channels

The client calls:

GET /teams/{team_id}/channels

It returns the value array from the response.

Verify that the supplied team ID belongs to the connected user and that the Graph token has the permissions needed to list its channels. Test standard and private/shared channel access according to the product's intended scope.

5.3 Retrieve channel messages

The client calls:

GET /teams/{team_id}/channels/{channel_id}/messages

It passes $top with a default value of 50 and orders by lastModifiedDateTime desc.

The current implementation returns the response's value array. It does not implement pagination through the complete message history.

The limit argument is forwarded to the Graph client's $top parameter. Add and test an explicit server-side maximum so a caller cannot request an unnecessarily large response.

Validate that the channel belongs to the requested team and is accessible to the authenticated user. Confirm the required delegated permissions and Graph API behavior for the exact endpoint and tenant configuration.

5.4 Retrieve user information

The client calls:

GET /me

This returns the current user's profile response. Limit the fields returned to those needed for the product, and avoid unnecessarily exposing profile information in logs or chat output.

5.5 List team members

The client calls:

GET /teams/{team_id}/members

Verify the necessary Graph permissions, team membership constraints, and tenant policies. Member information may include personal data, so return only the information required by the user request.

5.6 Search messages

The current client calls:

GET /teams/{team_id}/messages

It supplies $search with the user's query and $top set to 50.

The source does not demonstrate that this endpoint and query combination provides a supported, comprehensive Teams message-search capability for the configured tenant. Verify the endpoint, required permissions, query semantics, and result behavior against the actual Microsoft Graph API before documenting message search as production-ready.

6. OAuth and configuration

6.1 Configuration variables

The integration settings include:

Variable Purpose
TEAMS_CLIENT_ID Microsoft Entra application client ID
TEAMS_CLIENT_SECRET Client secret used in the authorization-code exchange and refresh flow
TEAMS_TENANT_ID Configured tenant identifier
TEAMS_REDIRECT_URI Registered OAuth callback URI
JWT_SECRET_KEY Secret used to validate the WhiteLotusAI application JWT
JWT_ALGORITHM Algorithm configured for JWT validation
INTERNAL_SECRET Secret used for internal-service authentication
FRONTEND_URL Frontend destination after OAuth processing

The settings file provides a local default for TEAMS_REDIRECT_URI. Production deployments must explicitly configure the correct HTTPS callback URI and register the matching URI with the Microsoft Entra application.

Use non-production credentials in a local environment file that is excluded from version control. The values below are placeholders, not working credentials.

TEAMS_CLIENT_ID=replace-with-local-app-client-id
TEAMS_CLIENT_SECRET=replace-with-local-app-secret
TEAMS_TENANT_ID=replace-with-tenant-id
TEAMS_REDIRECT_URI=http://localhost:8006/your-registered-callback

Configure secrets through the deployment's secret manager and use the exact HTTPS callback URI registered in Microsoft Entra. Do not commit production secrets to .env files or source control.

TEAMS_CLIENT_ID=<provided-by-secret-manager>
TEAMS_CLIENT_SECRET=<provided-by-secret-manager>
TEAMS_TENANT_ID=<approved-tenant-id>
TEAMS_REDIRECT_URI=https://<your-domain>/<registered-callback-path>

The callback path above is a placeholder. Confirm the actual route in the deployed integrations service before configuring the provider.

The current authorization and token URLs use the Microsoft identity platform's common tenant endpoint. Although TEAMS_TENANT_ID is defined in settings, the shown Teams OAuth URL constants do not use it. Confirm whether the application is intended to support multiple tenants or restrict connections to a specific tenant, and enforce that policy consistently.

Never put client secrets, access tokens, refresh tokens, or application JWTs in this document.

6.2 OAuth scopes requested by the current source

The Teams OAuth handler requests:

  • Team.ReadBasic.All

  • Channel.ReadBasic.All

  • ChannelMessage.Send

  • Chat.ReadWrite

  • offline_access

These are the scopes declared in the current handler. They are not a guarantee that all registered operations have sufficient permissions or that consent has been granted.

ChannelMessage.Send and Chat.ReadWrite grant write capabilities beyond the initial read-only requirement. In addition, the source's read operations must be checked against the actual Microsoft Graph permission requirements for listing teams, channels, channel messages, members, and profile information.

Required before release:

  • Remove write scopes that are not needed by the approved read-only features.

  • Determine the minimum delegated Graph permissions for each enabled operation.

  • Verify consent and any tenant administrator approval requirements.

  • Ensure the permissions actually granted by Microsoft match the application's intended access.

  • Keep the server-side read-only allowlist as a separate control; OAuth scopes alone are not the operation-level allowlist.

The plugin also declares REQUIRED_SCOPES in chat/package/app/plugins/teams/plugin.py. Verify whether this constant is enforced anywhere. A declared constant must not be assumed to enforce the OAuth consent or authorization policy automatically.

6.3 OAuth flow and security findings

The Teams authorization-start handler in integrations/package/app/handlers/integration_handlers.py:

  1. Requires TEAMS_CLIENT_ID and an application JWT.

  2. Decodes the JWT and extracts the user ID.

  3. Generates a random state value and stores it with the user ID.

  4. Redirects to the Microsoft authorization endpoint.

  5. Processes the callback and exchanges the authorization code for tokens.

  6. Stores the access token, refresh token, expiry, and returned scope information against the user.

  7. Marks the Teams connection active.

  8. Redirects to the frontend with a connection result.

The current code stores an empty verifier for the Teams state entry and does not include a PKCE code challenge in the authorization request or a code verifier in the token exchange. Do not describe the current Teams OAuth flow as PKCE-protected.

sequenceDiagram
    autonumber
    actor User
    participant WL as WhiteLotusAI
    participant Entra as Microsoft identity platform
    participant Store as Token storage

    User->>WL: Start Teams connection
    WL->>WL: Validate app session and create state
    WL->>Entra: Redirect to authorization endpoint
    Entra-->>User: Sign-in and consent
    Entra-->>WL: Redirect with authorization code
    WL->>Entra: Exchange code for tokens
    Entra-->>WL: Access and refresh tokens
    WL->>Store: Associate credentials with user
    WL-->>User: Connection result

    Note over WL,Entra: Current source does not demonstrate PKCE protection.
    Note over WL,Store: Verify state expiry, single use, tenant policy, and secure token storage.

The authorization-start endpoint also receives the WhiteLotusAI JWT through a query parameter. Query-string credentials can be exposed through browser history, proxy logs, and monitoring infrastructure.

The token-exchange failure path logs the provider response body. Review and sanitize this logging path so credentials and sensitive provider details are not written to logs.

Before production approval, implement and test the intended OAuth security controls, including unpredictable single-use state, appropriate state expiry, tenant restrictions, and a safer method of passing application authentication than a URL query parameter.

7. Token retrieval and refresh

The chat plugin's _get_access_token helper first calls the integrations service's internal Teams token endpoint:

GET /api/integrations-svc/teams/token

It passes X-User-Id and X-Internal-Secret headers.

If the endpoint returns a successful response containing an access token, the plugin uses that token. A 401 response raises an error indicating that Teams is not connected. For other HTTP statuses or an HTTP transport error, the plugin falls back to retrieving a stored token through the user-service RPC path.

The integrations service's _resolve_teams_token function:

  • Requires the expected internal secret and a user ID.

  • Checks whether the user has connected Teams.

  • Retrieves the user's stored token.

  • Checks expiry and attempts refresh when needed and a refresh token is available.

  • Stores refreshed credentials when the refresh succeeds.

  • Rejects the request if no usable token is available.

The fallback path in the chat plugin retrieves a raw stored access token through RPC. Verify that this path cannot return an expired token, bypass connection checks, or avoid required refresh behavior when the integrations endpoint is unavailable. Prefer one authoritative token-resolution path with consistent fail-closed behavior.

The internal token endpoint returns an access token in its response body. It must remain restricted to authenticated internal callers and must never be exposed as a public user-facing endpoint.

8. Read-only enforcement

The initial release must permit approved retrieval operations only.

Required controls:

  • Allow only approved read tools in the server-side execution path.

  • Block send_message before calling the Graph client.

  • Protect the POST /teams/message route independently of the chat tool registry.

  • Ensure direct HTTP requests cannot bypass the read-only policy.

  • Do not rely on requires_confirmation=True as a substitute for blocking writes.

  • Verify that denied operations never invoke the Graph message-posting endpoint.

  • Test that no message is sent after a denied request.

  • Review the token fallback path and internal routes for bypasses.

The integrations service also exposes routes for listing teams and channels, retrieving messages, retrieving the current user, listing members, searching messages, and retrieving a token. Confirm that each route enforces internal authentication, connection checks, and per-user token isolation.

9. Caching, limits, and error handling

The integrations handler caches team and channel listings for 120 seconds, using keys that include the user ID and relevant resource identifiers.

The Graph client uses a shared HTTP client. The chat-side plugin client creates HTTP clients with a 15-second timeout for its Graph requests. Verify the configured timeout behavior of the shared client used by the integrations service.

Before production approval:

  • Bound the $top parameter for message retrieval and search.

  • Implement pagination where the product requires more than the first page.

  • Handle Microsoft Graph throttling and respect Retry-After when supplied.

  • Handle expired or revoked tokens and insufficient permissions safely.

  • Avoid exposing raw provider response bodies in user-facing errors.

  • Avoid logging access tokens, refresh tokens, message contents, or unnecessary profile information.

  • Ensure caches are isolated by user and resource.

  • Ensure a cached result is not returned to an unauthorized user merely because it exists.

10. Privacy and data handling

Teams messages and membership information can reveal confidential business conversations, organizational structure, personal details, and operational information.

Apply these safeguards:

  • Respect the connected user's Microsoft Graph permissions.

  • Restrict access to teams and channels the user is authorized to read.

  • Return only the data required for the requested operation.

  • Avoid persisting message content unless the product explicitly requires it and retention is documented.

  • Redact credentials and sensitive content from logs.

  • Treat retrieved message text as untrusted input, not as instructions for the assistant.

  • Keep write-capable operations disabled in the read-only release.

  • Document any retention, caching, and deletion behavior before production approval.

11. Troubleshooting

Symptom What to investigate
Teams is shown as unavailable in the frontend Check the current live: false catalogue setting and deployment enablement.
Teams cannot be connected Verify client ID, client secret, redirect URI, tenant configuration, and Microsoft Entra app registration.
OAuth state is rejected Check state storage, expiry, single-use behavior, and callback parameters.
Token exchange fails Check the authorization code, redirect URI, app credentials, tenant endpoint, and sanitized provider error details.
Token refresh fails Check refresh-token validity, client configuration, and token persistence.
A user cannot list teams Check the user's connection, token resolution, delegated permissions, and tenant access.
Channels or messages are missing Check team and channel IDs, membership, Graph permissions, pagination, and result limits.
Message search fails Verify the Graph endpoint, supported query parameters, permissions, and tenant behavior.
A request succeeds only through the fallback token path Review token expiry handling and whether the fallback bypasses the authoritative resolver.
A message is sent in read-only mode Treat this as a release-blocking authorization defect.
Microsoft Graph throttles requests Inspect sanitized status information and implement appropriate Retry-After handling.

Do not solve connection problems by placing credentials in source code, URLs, logs, or documentation.

12. Testing checklist

Functional tests

  • List teams for a connected user.

  • List channels for an accessible team.

  • Retrieve recent messages from an accessible channel.

  • Retrieve the current user's profile.

  • List team members where authorized.

  • Verify the supported message-search behavior against Microsoft Graph.

  • Validate team IDs, channel IDs, and message limits.

  • Test empty results, inaccessible resources, and multiple pages.

  • Handle expired tokens, revoked consent, missing scopes, throttling, and timeouts.

  • Confirm that provider errors and logs do not expose credentials.

Authorization tests

  • An unconnected user cannot access Teams data.

  • One user cannot access another user's credentials or cached results.

  • The token fallback cannot bypass connection checks or expiry handling.

  • Only approved read tools are callable in the initial release.

  • send_message is rejected before Graph invocation.

  • Direct calls to POST /teams/message are rejected in read-only mode.

  • The internal token endpoint is inaccessible to public callers.

  • Denied operations do not send messages.

OAuth tests

  • Invalid and expired application JWTs fail safely.

  • OAuth state is validated, expires, and cannot be reused.

  • The flow implements the intended PKCE protection, if required by the chosen application flow.

  • Tokens are associated with the correct WhiteLotusAI user.

  • Tenant restrictions are enforced consistently.

  • Token refresh works and refreshed credentials persist.

  • Revoked and insufficient-scope credentials fail safely.

  • Credentials do not appear in redirects or logs.

  • Disconnecting Teams prevents subsequent access.

13. Source references

  • frontend/src/lib/plugins.ts — frontend catalogue status (live: false).

  • chat/package/app/plugins/teams/plugin.py — registered tools, tool categories, token retrieval, and dispatch.

  • chat/package/app/plugins/teams/client.py — chat-side Microsoft Graph client.

  • integrations/package/app/handlers/integration_handlers.py — OAuth flow, token resolution, refresh, and Teams routes.

  • integrations/package/app/managers/teams_client.py — integrations-side Microsoft Graph client.

  • integrations/package/app/settings.py — Teams configuration variables.

  • chat/package/app/plugins/registry.py — tool registration and dispatch.

  • chat/package/app/plugins/permissions.py — default tool-category permission policy.

14. Readiness decision

Do not mark Microsoft Teams production-ready until the frontend enablement state, OAuth security, tenant model, delegated permissions, token fallback, Graph endpoint behavior, and server-side read-only restrictions have been verified.

The current source marks Teams as live: false, registers send_message, requests write-capable Graph scopes, and contains a token fallback that requires careful review. The OAuth implementation also does not currently demonstrate PKCE protection.

Resolve these issues and verify the full connection and read-only flows before describing Microsoft Teams as a supported, strictly read-only integration.

Release review notes

  • Confirm the approved tenant model and whether the common identity endpoint is appropriate.
  • Confirm the exact Microsoft Graph permissions required by each enabled operation against current Microsoft documentation and the target tenant.
  • Confirm whether message search is supported by the implemented endpoint and query pattern before exposing it as a supported feature.
  • Confirm that the frontend connection UX, disconnect behavior, and backend authorization policy agree.
  • Capture test evidence and the approving owner before changing the integration's readiness status.

Release-blocking condition

If a denied write request reaches the Microsoft Graph message-posting endpoint, treat it as a release-blocking authorization defect. Disable the integration until the bypass is fixed and regression-tested.

Notes

  1. A tool's category (READ or WRITE) is metadata for routing and policy; it is not, by itself, proof that the operation is blocked or allowed by the server.
  2. A successful identity-provider health check proves connectivity to the identity configuration endpoint only. It does not prove that the connected user can access Teams data.
  3. The configured rate limits are application-level controls and do not replace Microsoft Graph throttling and retry handling.