Documentation
¶
Overview ¶
Package teams implements the Microsoft Teams (Bot Framework) adapter for the orb chat gateway, speaking the raw connector REST API with no SDK: JWT-validated webhook ingress, typing plus final-only delivery, markdown-subset formatting with UTF-16 chunking, and authenticated attachment download. It plugs into the chat processor via chat.Adapter.
Inbound JWT validation is the trust boundary and is never skippable: New refuses to construct without the app id (the token audience) and secret, and the webhook rejects every request whose Bot Framework token fails the full check chain — RS256 signature against the cached JWKS (with the endorsements filter), issuer, audience, validity window with 5-minute skew, and the serviceUrl claim matching the activity's serviceUrl byte for byte. The endpoint overrides in Options redirect validation at test servers; no configuration disables it.
Index ¶
- Constants
- type APIError
- type Adapter
- func (a *Adapter) Account() string
- func (a *Adapter) Download(ctx context.Context, ref chat.AttachmentRef) (io.ReadCloser, string, error)
- func (a *Adapter) NewDelivery(key chat.ConversationKey, replyTo string, resumePreviewID string) chat.Delivery
- func (a *Adapter) Platform() string
- func (a *Adapter) Webhook(publish func(chat.Message) error) http.Handler
- type Options
Constants ¶
const DefaultIssuer = "https://api.botframework.com"
DefaultIssuer is the issuer of inbound Bot Framework connector tokens.
const DefaultOpenIDMetadataURL = "https://login.botframework.com/v1/.well-known/openidconfiguration"
DefaultOpenIDMetadataURL is the Bot Framework OpenID metadata document locating the JWKS for inbound token validation.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type APIError ¶
type APIError struct {
// Status is the HTTP status code.
Status int
// Code is the error.code string from the error envelope, when present.
Code string
// ErrorCode is the Teams-specific numeric errorCode (209 =
// MessageWritesBlocked), when present.
ErrorCode int
// Message is the error message text, when present.
Message string
// RetryAfter is the server-requested pause from a Retry-After header,
// when present (Teams does not guarantee one on 429).
RetryAfter time.Duration
// contains filtered or unexported fields
}
APIError is a decoded connector failure.
type Adapter ¶
type Adapter struct {
// contains filtered or unexported fields
}
Adapter is the Microsoft Teams implementation of chat.Adapter.
func New ¶
New creates a Teams adapter. It refuses to construct without AppID and AppPassword: the app id is the inbound token audience, so inbound validation — the trust boundary — could not run without it.
func (*Adapter) Account ¶
Account returns the bot app id, matching the Account set on every normalized message.
func (*Adapter) Download ¶
func (a *Adapter) Download(ctx context.Context, ref chat.AttachmentRef) (io.ReadCloser, string, error)
Download implements chat.Adapter: the attachment contentUrl is fetched directly, with the connector token attached only for known connector hosts (Teams file contentUrls on smba.* need it; sending it anywhere else would leak the token to whoever controls the URL).
ponytail: inline images and connector-served files only; SharePoint attachment URLs need Graph credentials the adapter does not hold.
func (*Adapter) NewDelivery ¶
func (a *Adapter) NewDelivery(key chat.ConversationKey, replyTo string, resumePreviewID string) chat.Delivery
NewDelivery implements chat.Adapter. replyTo is the inbound activity id (the EventID). Teams is final-only, so a recovered preview id is ignored. The serviceUrl comes from the per-conversation store fed by validated inbound activities.
func (*Adapter) Webhook ¶
Webhook returns the Bot Framework ingress handler. Every POST is authenticated by full inbound JWT validation (403 on any failure) before its body is trusted; message activities are normalized and handed to publish, then the request is acknowledged — ingress never waits on turn processing (publish is the durable enqueue). typing activities are ignored; conversationUpdate and every other type just refresh the stored per-conversation serviceUrl. A publish failure answers 500 so the connector redelivers (the activity id EventID dedupes downstream).
type Options ¶
type Options struct {
// AppID is the Azure bot application (client) id. Required: it is the
// outbound OAuth client id, the inbound token audience — validation
// cannot run without it — and the adapter [Adapter.Account] identity.
AppID string
// AppPassword is the app client secret used by the client-credentials
// grant. Required.
AppPassword string
// TenantID selects the single-tenant token endpoint
// (login.microsoftonline.com/{tenant}); empty means the multi-tenant
// "botframework.com" endpoint.
TenantID string
// TokenURL overrides the OAuth token endpoint (tests).
TokenURL string
// OpenIDMetadataURL overrides the OpenID metadata document used to
// locate the JWKS (tests). Default [DefaultOpenIDMetadataURL].
OpenIDMetadataURL string
// Issuer overrides the expected inbound token issuer (tests). Default
// [DefaultIssuer].
Issuer string
// HTTPClient overrides the HTTP client. Default: 30s timeout.
HTTPClient *http.Client
// Logger receives non-fatal diagnostics. Optional.
Logger *slog.Logger
// TypingInterval is the typing-activity refresh cadence (the indicator
// is transient). Default 3.5s.
TypingInterval time.Duration
// ChunkDelay paces consecutive Finalize chunk sends. Default 350ms.
ChunkDelay time.Duration
}
Options configures New.