Microsoft Teams
JWT + JWKS 검증 기반 Bot Framework 메시징. 멀티 테넌트 및 싱글 테넌트 지원.
🟡 아웃바운드 준비 완료, 인바운드 JWT 검증 적용. Bot Connector REST API를 통해 Teams와 통신합니다. 인바운드 활동은 Microsoft가 서명하며 동적으로 탐색된 JWKS로 검증되므로, 위조된 POST 요청은 401을 반환합니다.
제공 기능
- 아웃바운드 텍스트 전송. Bot Framework Conversation API를 사용합니다.
POST {serviceUrl}/v3/conversations/{conversationId}/activities형식으로{type:"message", text}를 전송합니다. 스레드(replyToActivityId)도 지원합니다. - 인바운드 webhook 엔드포인트:
/webhooks/teams. Microsoft는 모든 활동에 JWT로 서명하며, Minara는 OpenID 메타데이터 엔드포인트(https://login.botframework.com/v1/.well-known/openidconfiguration)를 통해 JWKS를 탐색하고 두 항목 모두 24시간 동안 캐싱합니다. - 아웃바운드용 OAuth 클라이언트 자격증명 token 캐시. TTL 1시간, 5분 사전 갱신.
- 현재 텍스트만 지원합니다. Adaptive Cards, Office 365 커넥터, 파일 업로드는 향후 추가될 예정입니다.
- 텍스트 한도: 28,000자.
설정
1. 봇 등록 (Azure)
- Azure 포털에서 Azure Bot 리소스를 생성합니다. 단일 리전 기준이며 개발 환경에는 "F0 무료" 요금제로 충분합니다.
- 프로비저닝 완료 후 "Configuration" 블레이드에서 Microsoft App ID (GUID)를 확인하고 Client Secret (App Password)을 생성합니다. 두 값 모두 저장해 둡니다.
- 테넌트 범위를 결정합니다. "Multi Tenant"는 tenant id에
common을 사용하고, "Single Tenant"는 Azure AD 테넌트 GUID를 사용합니다.
2. 봇을 Teams에 연결
- 동일한 Azure Bot 블레이드에서 "Channels" → "Microsoft Teams"로 이동합니다. 서비스 약관에 동의하고 활성화합니다.
- Teams 앱 매니페스트를 생성하거나 Developer Portal for Teams를 사용하여 봇의 Microsoft App ID를 지정합니다. 테스트용으로 테넌트에 사이드로드합니다.
- 봇을 팀에 추가하거나 테스트 사용자가 DM을 보냅니다. 첫 번째 인바운드 활동에 Minara가 필요로 하는
conversation.id와serviceUrl이 포함됩니다.
3. 봇 메시징 엔드포인트 설정
Azure Bot 블레이드에서 "Configuration" → "Messaging endpoint"로 이동하여 URL을 https://<your-host>/webhooks/teams로 설정합니다.
4. Minara 설정
minara auth messaging add
# 목록에서 `teams`를 선택하고 App ID, App Password, tenant id
# (또는 "common"), 기본 conversation id와 service URL을 입력합니다.또는 환경 변수로 설정합니다.
TEAMS_BOT_APP_ID=<봇 Microsoft App ID GUID>
TEAMS_BOT_APP_PASSWORD=<봇 Microsoft App Password>
TEAMS_BOT_TENANT_ID=common
TEAMS_DEFAULT_CONVERSATION_ID=<수신된 인바운드 활동에서 가져온 conversation id>
TEAMS_DEFAULT_SERVICE_URL=https://smba.trafficmanager.net/teams/위의 TEAMS_DEFAULT_SERVICE_URL 값은 멀티 테넌트 프로덕션 라우트입니다. 싱글 테넌트 또는 소버린 클라우드 배포의 경우, 테넌트에서 수신된 첫 번째 인바운드 활동에 포함된 serviceUrl로 재정의합니다.
5. 테스트
minara auth messaging test teams인바운드 webhook
Bot Framework는 Authorization: Bearer ... 헤더의 JWT로 인바운드 활동에 서명합니다. Minara는 다음 항목을 검증합니다.
| 클레임 | 예상 값 |
|---|---|
iss (발급자) | https://api.botframework.com |
aud (대상) | 멀티 테넌트: TEAMS_BOT_APP_ID / 싱글 테넌트: TEAMS_BOT_TENANT_ID GUID |
| 서명 | RS256, https://login.botframework.com/v1/.well-known/openidconfiguration에서 탐색된 키 |
| 클럭 스큐 | ±5분 |
JWKS와 OpenID 메타데이터는 24시간 동안 캐싱됩니다. Microsoft는 주기적으로 키를 교체합니다. kid 불일치가 발생하면 캐시를 무효화하고 한 번 재조회합니다.
수신 가능한 활동 타입: message. 그 외 타입(conversationUpdate, typing, installationUpdate)은 무시합니다.
제한 사항 및 주의점
serviceUrl은 대화별로 다릅니다. Bot Framework 문서에 따르면 각 인바운드 활동에서serviceUrl을 캡처하여 대화별로 저장해야 합니다. Minara는 인바운드serviceUrl이 있으면 이를 우선 사용하며, 환경 변수 기본값은 콜드 푸시 시 부트스트랩 폴백으로만 사용됩니다.- 멀티 테넌트 대상.
TEAMS_BOT_TENANT_ID=common으로 설정하면 봇은 모든 테넌트의 활동을 수락합니다. 이 경우 JWT audience는TEAMS_BOT_APP_ID와 같습니다. 싱글 테넌트로 설정할 경우 테넌트 GUID를 입력하면 audience도 해당 GUID가 됩니다. - Adaptive Cards는 아직 지원하지 않습니다. 봇은 일반 텍스트만 사용합니다.
- JWKS 탐색은 첫 인바운드 POST 시 네트워크 접근이 필요합니다.
login.botframework.com이 방화벽으로 차단된 경우 검증은 실패하며 401을 반환합니다.
문제 해결
"인바운드 요청마다 401 반환"
- 호스트와 Microsoft 간 클럭 스큐가 5분을 초과합니다.
TEAMS_BOT_APP_ID값이 Azure의 봇 Microsoft App ID와 일치하지 않습니다. Azure Bot에는 Application ID와 리소스 ID 두 가지가 있으며, Application ID를 사용해야 합니다. 붙여넣기 실수가 자주 발생하는 항목입니다.- 싱글 테넌트의 경우:
TEAMS_BOT_TENANT_ID가 인바운드 JWT의 audience와 일치하지 않습니다.
"아웃바운드 401 (token 엔드포인트)"
TEAMS_BOT_APP_PASSWORD가 교체되었거나 취소되었습니다. Azure Bot 설정 블레이드에서 새 Client Secret을 생성합니다.
"대화를 찾을 수 없음 (아웃바운드 404)"
- 기본
TEAMS_DEFAULT_CONVERSATION_ID가 오래된 값입니다. 사용자가 봇을 제거했거나 채널이 삭제된 경우 발생합니다. 최근 인바운드 활동에서 새 conversation id를 캡처합니다.
참조
- 환경 변수:
TEAMS_* - 아웃바운드:
apps/agent/src/messaging/teams.ts - 인바운드 사양:
apps/agent/src/messaging/inbound/specs/teams.ts - JWT 헬퍼:
apps/agent/src/messaging/_shared/jwt-verify.ts - Bot Connector 인증: learn.microsoft.com