Skip to content

feat(msteams): support federated credentials and certificate auth#40884

Draft
fengyang0317 wants to merge 1 commit intoopenclaw:mainfrom
fengyang0317:feature/msteams-federated-credentials
Draft

feat(msteams): support federated credentials and certificate auth#40884
fengyang0317 wants to merge 1 commit intoopenclaw:mainfrom
fengyang0317:feature/msteams-federated-credentials

Conversation

@fengyang0317
Copy link
Copy Markdown

Summary

Adds support for alternative authentication methods in the MS Teams channel, enabling passwordless bot authentication for enterprise tenants that block client secrets via tenant-wide policy.

Fixes #40855

Changes

New config fields under channels.msteams:

  • authType: 'clientSecret' (default) | 'certificate' | 'federatedCredential'
  • certPemFile / certKeyFile / sendX5C: for certificate-based auth
  • ficClientId: FIC client ID for federated credential auth
  • widAssertionFile: workload identity assertion file path (K8s / workload identity)

Files changed:

  • src/config/types.msteams.ts — Added new config type fields
  • extensions/msteams/src/token.ts — Updated credential resolution to support all three auth types
  • extensions/msteams/src/sdk.ts — Updated buildMSTeamsAuthConfig to pass the right fields to the SDK based on auth type
  • extensions/msteams/src/errors.ts — Updated error hint message
  • extensions/msteams/src/probe.ts — Updated probe error message

How it works

The @microsoft/agents-hosting SDK's AuthConfiguration already supports certPemFile, certKeyFile, FICClientId, and WIDAssertionFile. This PR exposes those capabilities through OpenClaw's config schema.

Backward compatibility

Fully backward compatible — existing appId + appPassword configs continue to work unchanged (default authType is 'clientSecret').

Example configs

Certificate auth:

channels:
  msteams:
    appId: '<app-id>'
    tenantId: '<tenant-id>'
    authType: certificate
    certPemFile: /path/to/cert.pem
    certKeyFile: /path/to/key.pem

Federated credential:

channels:
  msteams:
    appId: '<app-id>'
    tenantId: '<tenant-id>'
    authType: federatedCredential
    ficClientId: '<managed-identity-client-id>'

…enclaw#40855)

Add support for alternative authentication methods in the MS Teams
channel, enabling passwordless bot authentication for enterprise
tenants that block client secrets via tenant-wide policy.

New config fields under channels.msteams:
- authType: 'clientSecret' (default) | 'certificate' | 'federatedCredential'
- certPemFile / certKeyFile / sendX5C: for certificate-based auth
- ficClientId: FIC client ID for federated credential auth
- widAssertionFile: workload identity assertion file path

Fully backward compatible: existing appId + appPassword configs
continue to work unchanged.
@openclaw-barnacle openclaw-barnacle bot added channel: msteams Channel integration: msteams size: S labels Mar 9, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 9, 2026

Greptile Summary

This PR extends the MS Teams channel to support certificate-based and federated credential (workload identity) authentication alongside the existing client-secret flow, enabling enterprise tenants that block client secrets to use the bot without passwords. The changes are additive and fully backward compatible — existing appId/appPassword configs continue to work unchanged via the default authType: "clientSecret" path.

Key observations:

  • The three-way switch on authType in both token.ts and sdk.ts is clean and the guard conditions are consistent between hasConfiguredMSTeamsCredentials and resolveMSTeamsCredentials.
  • The updated error hint in errors.ts drops the previously helpful env var references (MSTEAMS_APP_ID/MSTEAMS_APP_PASSWORD/MSTEAMS_TENANT_ID), which is a minor DX regression for env-var-based configurations.
  • appPassword in MSTeamsCredentials remains a required string field but is set to "" for certificate and federated credential auth paths; making it optional would better represent the type's actual contract.
  • MSTeamsAuthType is defined in token.ts but the identical union is inlined in types.msteams.ts rather than shared, creating a maintenance surface for future auth type additions.

Confidence Score: 4/5

  • PR is safe to merge — changes are additive and backward compatible, with only minor style/DX issues.
  • Core auth logic is correct and well-guarded. All three auth paths are properly validated before credentials are returned. No critical bugs were found. Minor issues: dropped env var hints in the error message, the appPassword required-but-empty pattern, and duplicated type definitions are style/maintainability concerns that don't affect runtime correctness.
  • extensions/msteams/src/errors.ts (dropped env var hints) and extensions/msteams/src/token.ts (appPassword type design).

Last reviewed commit: 6774bc8

): string | undefined {
if (classification.kind === "auth") {
return "check msteams appId/appPassword/tenantId (or env vars MSTEAMS_APP_ID/MSTEAMS_APP_PASSWORD/MSTEAMS_TENANT_ID)";
return "check msteams appId/tenantId and auth config (appPassword, certificate, or federated credential)";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Env var hints dropped from error message

The updated message removes mention of the MSTEAMS_APP_ID, MSTEAMS_APP_PASSWORD, and MSTEAMS_TENANT_ID environment variables. For users who configure credentials via env vars (rather than the YAML config), this is a regression — they lose the hint pointing to those vars when auth fails.

Consider keeping the env var guidance alongside the new auth type info:

Suggested change
return "check msteams appId/tenantId and auth config (appPassword, certificate, or federated credential)";
return "check msteams appId/tenantId and auth config (appPassword, certificate, or federated credential) — or env vars MSTEAMS_APP_ID/MSTEAMS_APP_PASSWORD/MSTEAMS_TENANT_ID";
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/msteams/src/errors.ts
Line: 196

Comment:
**Env var hints dropped from error message**

The updated message removes mention of the `MSTEAMS_APP_ID`, `MSTEAMS_APP_PASSWORD`, and `MSTEAMS_TENANT_ID` environment variables. For users who configure credentials via env vars (rather than the YAML config), this is a regression — they lose the hint pointing to those vars when auth fails.

Consider keeping the env var guidance alongside the new auth type info:

```suggestion
    return "check msteams appId/tenantId and auth config (appPassword, certificate, or federated credential) — or env vars MSTEAMS_APP_ID/MSTEAMS_APP_PASSWORD/MSTEAMS_TENANT_ID";
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 10 to 13
export type MSTeamsCredentials = {
appId: string;
appPassword: string;
tenantId: string;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

appPassword required but meaningless for non-clientSecret auth

appPassword: string is a required field in MSTeamsCredentials, yet for certificate and federatedCredential auth it's always set to the empty string "". Downstream consumers of this type may be confused by a field that is nominally required but silently unused. Making it optional better represents the actual contract:

Suggested change
export type MSTeamsCredentials = {
appId: string;
appPassword: string;
tenantId: string;
export type MSTeamsCredentials = {
appId: string;
appPassword?: string;
tenantId: string;
authType: MSTeamsAuthType;
certPemFile?: string;
certKeyFile?: string;
sendX5C?: boolean;
ficClientId?: string;
widAssertionFile?: string;
};

The clientSecret branch in sdk.ts already guards the field access with creds.appPassword, so making it optional there is safe. The resolveMSTeamsCredentials return for clientSecret already guarantees a non-empty value via the if (!appPassword) return undefined guard.

Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/msteams/src/token.ts
Line: 10-13

Comment:
**`appPassword` required but meaningless for non-`clientSecret` auth**

`appPassword: string` is a required field in `MSTeamsCredentials`, yet for `certificate` and `federatedCredential` auth it's always set to the empty string `""`. Downstream consumers of this type may be confused by a field that is nominally required but silently unused. Making it optional better represents the actual contract:

```suggestion
export type MSTeamsCredentials = {
  appId: string;
  appPassword?: string;
  tenantId: string;
  authType: MSTeamsAuthType;
  certPemFile?: string;
  certKeyFile?: string;
  sendX5C?: boolean;
  ficClientId?: string;
  widAssertionFile?: string;
};
```

The `clientSecret` branch in `sdk.ts` already guards the field access with `creds.appPassword`, so making it optional there is safe. The `resolveMSTeamsCredentials` return for `clientSecret` already guarantees a non-empty value via the `if (!appPassword) return undefined` guard.

How can I resolve this? If you propose a fix, please make it concise.

normalizeSecretInputString,
} from "./secret-input.js";

export type MSTeamsAuthType = "clientSecret" | "certificate" | "federatedCredential";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicated auth type union between token.ts and types.msteams.ts

MSTeamsAuthType is exported from token.ts as a named type, but MSTeamsConfig.authType in src/config/types.msteams.ts repeats the same union inline ("clientSecret" | "certificate" | "federatedCredential"). If a new auth method is added later, both locations need to be updated independently, risking a drift.

I understand types.msteams.ts cannot directly import from token.ts without creating a circular dependency (since token.ts imports MSTeamsConfig). One option is to extract MSTeamsAuthType into its own lightweight file (or into the shared plugin-sdk types) so it can be imported by both sides without a cycle.

Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/msteams/src/token.ts
Line: 8

Comment:
**Duplicated auth type union between `token.ts` and `types.msteams.ts`**

`MSTeamsAuthType` is exported from `token.ts` as a named type, but `MSTeamsConfig.authType` in `src/config/types.msteams.ts` repeats the same union inline (`"clientSecret" | "certificate" | "federatedCredential"`). If a new auth method is added later, both locations need to be updated independently, risking a drift.

I understand `types.msteams.ts` cannot directly import from `token.ts` without creating a circular dependency (since `token.ts` imports `MSTeamsConfig`). One option is to extract `MSTeamsAuthType` into its own lightweight file (or into the shared plugin-sdk types) so it can be imported by both sides without a cycle.

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6774bc82ef

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +71 to +73
authType?: "clientSecret" | "certificate" | "federatedCredential";
/** Path to the certificate PEM file (used when authType is "certificate"). */
certPemFile?: string;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Add runtime schema entries for new MS Teams auth fields

The new authType/certificate/federated fields are added to MSTeamsConfig here, but MSTeamsConfigSchema is still a strict object that only allows appId, appPassword, tenantId, etc. (src/config/zod-schema.providers-core.ts:1409-1449). In practice, any config that uses channels.msteams.authType, certPemFile, certKeyFile, ficClientId, or widAssertionFile will be rejected as unrecognized keys during config validation, so the feature introduced in this commit cannot be used.

Useful? React with 👍 / 👎.

@fengyang0317 fengyang0317 marked this pull request as draft March 9, 2026 11:19
@BradGroux BradGroux self-assigned this Mar 10, 2026
@BradGroux
Copy link
Copy Markdown
Contributor

Hi @fengyang0317 — thanks for the submission. I’m the new Microsoft Teams maintainer for OpenClaw. Please give me a day or two to work through the open Teams backlog. Also, join the Twitter community for daily MS Teams feedback + updates: https://x.com/i/communities/2031170403607974228

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: msteams Channel integration: msteams size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Support federated credentials / managed identity for MS Teams Bot Framework authentication

2 participants