locksyk/msteams-bundle

Microsoft Entra ID and Teams for Symfony APIs: Entra token verification, OIDC code-flow web login, Teams tab SSO, and SDK-free Bot Connector inbound authentication with invoke-response helpers.

Maintainers

Package info

github.com/LocksyK/msteams-bundle

Type:symfony-bundle

pkg:composer/locksyk/msteams-bundle

Transparency log

Statistics

Installs: 8

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.1.0 2026-08-09 11:18 UTC

This package is auto-updated.

Last update: 2026-08-09 11:23:14 UTC


README

Microsoft Entra ID and Teams for Symfony APIs - without the retired Bot Framework SDK.

  • EntraTokenVerifier - verifies Entra v2.0 tokens against the tenant JWKS (signature, issuer, audience, lifetime + leeway, tenant, ver): web-login id_tokens and Teams tab SSO access tokens alike.
  • OidcLoginService - the OIDC code-flow web-login ceremony: begin() parks state + nonce + PKCE in the request's session and returns the authorization URL; finish() checks state, exchanges the code as a confidential client, verifies the id_token, checks the nonce. Designed for session-establishing logins - with locksyk/api-session-bundle the ceremony rides a pre-auth anonymous session exactly like a WebAuthn challenge.
  • Bot\BotTokenVerifier - every check Microsoft documents for SDK-free bots, including the serviceUrl binding (the forged-activity defence), signing-key channel endorsements, and a tenant pin.
  • Bot\InvokeResponse - the response envelopes Teams expects from message-extension / task-module / card-action invokes, encoding the constraints that otherwise fail silently (previews, the 1.3 card ceiling, Action.Execute fallbacks).
  • Bot\BotConnectorClient - the outbound counterpart: replies to plain message activities (conversational "CLI" bots) POSTed to the Connector at the activity's verified serviceUrl, authenticated with a cached client-credentials service token. Enabled by bot.client_secret; only ever call it with a serviceUrl from an activity BotTokenVerifier accepted.
  • Bot\ReplyActivity and Bot\Cards - message-CLI plumbing (mention-stripped command text, text/card reply activities with previews stripped) and Adaptive Card envelopes with the hard-won rules baked in (mandatory previews, 1.3 ceiling, Action.Execute with OpenUrl fallback).
  • Test\FakeMicrosoft - a MockHttpClient standing in for login.microsoftonline.com and login.botframework.com, signing real RS256 tokens (Entra + Bot Connector, scriptable token endpoint) and capturing outbound Connector replies in $botReplies, so consumers functional-test every path with no tenant.

Your application keeps its own user-resolution policy, authenticators, controllers and card content - the bundle owns the protocol.

The browser half lives in frontend/ as @locksyk/msteams-client: Teams launch detection (the manifest's ?inTeams=1 flag) and the silent tab-SSO token exchange, with @microsoft/teams-js as a lazily-imported optional peer.

Configuration

# config/packages/ms_teams.yaml
ms_teams:
    tenant_id: '%env(OIDC_TENANT_ID)%'
    client_id: '%env(OIDC_CLIENT_ID)%'
    client_secret: '%env(OIDC_CLIENT_SECRET)%'
    app_id_uri: '%env(OIDC_APP_ID_URI)%'          # Teams tab SSO audience
    redirect_uri: '%env(OIDC_REDIRECT_URI)%'
    bot:
        app_id: '%env(TEAMS_BOT_APP_ID)%'         # Azure Bot registration
        client_secret: '%env(OIDC_CLIENT_SECRET)%'  # outbound replies; often the same app registration

when@test:
    ms_teams:
        http_client: LocksyK\MsTeamsBundle\Test\FakeMicrosoft

Empty tenant_id/client_id disable every SSO surface; empty bot.app_id disables Bot Connector verification. issuer / *_endpoint / jwks_uri overrides point the machinery at a broker or a fake without code changes.

Teams app tooling

The bundle also ships the provisioning/packaging toolkit an app's teams-app/ directory needs, so the mechanics live once:

  • LocksyK\MsTeamsBundle\TeamsApp\PackageBuilder builds the sideloadable zip from the app's manifest.template.json + icons, keeping a stable Teams app id and an auto-bumping version in a git-ignored state.local.json (Teams caches the definition against the version, so unchanged re-uploads silently do nothing). Bot / compose-extension / tab-SSO capabilities are dropped when their env values are unset - placeholder ids fail far more confusingly than absent capabilities. A thin app-side teams-app/package.php loads Dotenv and calls PackageBuilder::build(__DIR__, 'myapp', $_ENV).
  • LocksyK\MsTeamsBundle\TeamsApp\IconSet generates the required color.png (192x192 accent tile) and outline.png (32x32); the app supplies only its glyph-drawing callable.
  • resources/provisioning/provision.ps1 provisions - or, with -Check, verifies - the Entra app registration (redirect URI, access_as_user scope, Teams clients pre-authorized in the mandatory second PATCH, v2 tokens) and the Azure Bot resource + Teams channel. App-agnostic: consent strings derive from -DisplayName; apps keep a thin wrapper supplying theirs.

ext-zip and ext-gd are needed only when using this tooling.

License

GPL-2.0-only.