Solutions2Share
Trust Center

Policy Enforcer

Policy Enforcer watches the Microsoft 365 groups and Teams that Teams Manager governs, detects changes that break your governance policies, and resolves them automatically or routes them to a reviewer in Microsoft Teams. It reads change events from the Microsoft Entra directory audit log through Microsoft Graph, compares them with the policies defined in Teams Manager, and — only where an administrator has configured an automatic resolution — restores the last known-good value in the customer’s tenant. All processing runs in Solutions2Share-operated Azure services in the EU.

Data Management Practices

All data is processed on behalf of the customer’s tenant and is isolated per tenant (see Architecture And Flow Diagram). Policy Enforcer is an add-on to Teams Manager: it reads policy definitions and governed spaces from Teams Manager read-only and never writes to Teams Manager. All Policy Enforcer services and data stores are hosted in Microsoft Azure data centres operated by Solutions2Share in the Germany West Central (EU) region. Sign-in, Microsoft Graph and the Azure Bot Service that delivers Teams messages are Microsoft 365 / Azure global services.

Policy Enforcer does not read chat or channel message content, e-mail, or document content.

The application accesses, processes and stores the following data types:

Governance configuration

Policy definitions and governed spaces (Microsoft 365 group ID, display name, template name and Teams Manager metadata values) read from the customer’s Teams Manager instance, plus the list of Teams Manager administrators (object ID, UPN or e-mail address) used to decide who may administer Policy Enforcer. Storage & retention: stored in Azure SQL Database as a snapshot that is refreshed every 30 minutes; retained for the duration of the subscription.

Group change events and violations

Group-management events from the directory audit log for governed spaces only: the changed property (team name, visibility, sensitivity label, owners, members), its old and new value, and the actor who made the change (UPN, or application name for app-made changes). A detected policy violation is stored together with its resolution state, the reviewer who resolved it (object ID) and an optional reviewer comment. Storage & retention: stored in Azure SQL Database for the duration of the subscription.

Known-good baselines

The last compliant value of each monitored property per governed space (for example the approved team name or sensitivity label), used to restore the value after a violation. Storage & retention: stored in Azure SQL Database for the duration of the subscription.

Planner and OneNote names

The titles of Planner plans and the names of OneNote notebooks that belong to governed groups. Plan tasks and notebook pages are not read. Storage & retention: only the changed names are stored, as part of a violation (see above).

Directory profile data (read on demand)

Display name, e-mail address, UPN and profile photo of users, and the owners and members of governed groups — read on demand to show names in the app and in notifications and to determine who must review a violation. Storage & retention: not stored; profile photos are cached in memory for at most one hour.

Microsoft Teams notification data

To send adaptive-card notifications, Policy Enforcer stores the Teams conversation reference of the Policy Enforcer bot for each recipient and a delivery record per card (recipient object ID, Teams message ID, delivery status). Storage & retention: stored in Azure SQL Database for the duration of the subscription.

Tenant and service-account data

Tenant ID and name, tenant settings and, if connected, the object ID of the service account used for delegated operations (see Microsoft Graph). The service account’s refresh token is encrypted at application level with AES-256-GCM, bound to the tenant ID; the encryption key is held in Azure Key Vault. Storage & retention: stored in Azure SQL Database for the duration of the subscription.

Diagnostic telemetry

Requests, dependency calls and errors from the web UI, API and background workers are sent to Azure Application Insights / Log Analytics in the same region. In the API and web UI telemetry, e-mail addresses, object IDs and authorization headers are redacted before they leave the process. Extended diagnostic logging of Microsoft Graph request and response bodies (capped at 16 KB, without authorization headers) is off by default and only enabled per tenant for troubleshooting. Storage & retention: 30 days.

Change detection is forward-only. Policy Enforcer starts evaluating changes from the moment a tenant is onboarded; it does not scan or report historical changes that happened before onboarding.

Microsoft Graph

Policy Enforcer uses one multi-tenant Microsoft Entra app registration. A tenant administrator grants admin consent once during onboarding. Detection and most resolutions run in the background with application permissions. A small number of operations that Microsoft Graph does not support with application permissions (changing a group’s sensitivity label, renaming a Planner plan, reading and renaming OneNote notebooks) run with delegated permissions of a dedicated service account that a tenant administrator connects during setup. Apart from installing its own Teams app for a reviewer who needs to receive a notification, Policy Enforcer only writes to the tenant to restore a governed group to its last known-good state after a policy violation — it never deletes groups, Teams, users, files or content. Scope names are the Microsoft Graph permission names, as shown on the consent screen, and are rendered as code.

ScopeDescriptionJustificationAdmin Consent RequiredType
AuditLog.Read.AllRead all audit log data.Read group-management events from the directory audit log to detect policy violations.YesApplication
Group.ReadWrite.AllRead and write all groups.Read governed groups; restore a group’s name or set its visibility back to private after a violation.YesApplication
GroupMember.ReadWrite.AllRead and write all group memberships.Read owners and members; re-add a required owner or member that was removed.YesApplication
User.Read.AllRead all users’ full profiles.Show user names in the app and in notifications; find the reviewers responsible for a governed space.YesApplication
SensitivityLabels.Read.AllRead sensitivity labels.Show sensitivity-label names instead of IDs in violations and notifications.YesApplication
InformationProtectionPolicy.Read.AllRead all published labels and label policies for an organization.Look up the approved sensitivity label before restoring it.YesApplication
Tasks.Read.AllRead all tasks.Detect renamed Planner plans in governed groups (plan titles only).YesApplication
AppCatalog.Read.AllRead all app catalogs.Find the Policy Enforcer app in the tenant’s Teams app catalog.YesApplication
TeamsAppInstallation.ReadWriteSelfForUser.AllAllow the Teams app to manage itself for all users.Install the Policy Enforcer app for a reviewer so that the bot can deliver a notification. Limited to Policy Enforcer itself.YesApplication
openid, profile, email, offline_access, User.ReadSign in and read the user’s basic profile; maintain access.Sign users in (Teams single sign-on) and keep the service account connected.NoDelegated
Group.ReadWrite.AllRead and write all groups.Restore a group’s sensitivity label (service account; not supported with application permissions).YesDelegated
Tasks.ReadWriteCreate, read, update and delete the user’s tasks and plans.Restore the title of a renamed Planner plan (service account).NoDelegated
Notes.Read.AllRead all OneNote notebooks the user can access.Detect renamed OneNote notebooks in governed groups (notebook names only; service account).NoDelegated
Files.ReadWrite.AllHave full access to all files the user can access.Restore the name of a renamed OneNote notebook, which is stored as a file (service account; rename only, no content access).NoDelegated

Full descriptions of each permission are published in the Microsoft Graph permissions reference.

SharePoint / other workload permissions

Not applicable. Policy Enforcer accesses Microsoft 365 exclusively through Microsoft Graph. It does not use the SharePoint REST API, Exchange Online, the Office 365 Management API or any other workload API, and requests no permissions for them.

Microsoft Teams Apps Security And Compliance

Policy Enforcer is delivered as a Microsoft Teams app with a personal tab (the web UI) and a personal bot that sends adaptive-card notifications. The app manifest requests only the identity and messageTeamMembers device permissions, declares no resource-specific consent (RSC) permissions, no message extensions and no team or group-chat scopes, and lists only the Policy Enforcer host as a valid domain. Users sign in with Teams single sign-on.

The bot sends:

  • Violation notifications — a 1:1 adaptive card to the owners of the affected group and/or the Policy Enforcer administrators, with a button that opens the review dialog. The card is updated in place when the violation is resolved or dismissed.
  • Resolution notices — after selected violations are resolved, a notice to the affected team’s General channel, posted by the bot through the Teams channel, not through a Microsoft Graph write.
  • Replies — a welcome message on installation and short help/status replies when a user writes to the bot.

The bot reads the text of messages sent to it only to recognise these commands; message text is not stored.

Architecture And Flow Diagram

Azure architecture for Policy Enforcer in three columns. Left, the customer's Microsoft 365 tenant: the Microsoft Teams client with the Policy Enforcer personal tab and bot, Microsoft Entra ID (app registration, sign-in, admin consent), Microsoft Graph (directory audit log, groups, owners and members, sensitivity labels, Planner plan titles, OneNote notebook names, conditional reverts) and the Azure Bot Service. Centre, the Solutions2Share Azure environment in Germany West Central: App Service (web UI and API, bot endpoint), Function App (timer and queue workers), Service Bus, Azure SQL Database, Key Vault, Storage account, and Application Insights with Log Analytics. Right, connected services: Teams Manager (read-only), and the Solutions2Share License Management Center. Numbered orange connectors show (1) the Teams client calling App Service, (2) sign-in with Microsoft Entra ID, (3) the read-only Teams Manager sync, (4) the Function App reading from and reverting through Microsoft Graph, and (5) App Service delivering cards through the Azure Bot Service back to Teams.

Data flow: (1) a user opens the Policy Enforcer app in Microsoft Teams, which loads the web UI from App Service and calls its API; (2) the user is signed in with Teams single sign-on and every API request carries a Microsoft Entra token that the API validates (signature, issuer, audience, tenant); (3) every 30 minutes the policy definitions and governed spaces are synchronised read-only from Teams Manager, using a read-only database account whose access is restricted to the Policy Enforcer service’s network addresses; (4) every 10 minutes the Function App reads new group-management events from the directory audit log through Microsoft Graph, evaluates them against the policies over Service Bus queues, stores detected violations in Azure SQL and — where the administrator has chosen automatic resolution — restores the last known-good value through Microsoft Graph, after first checking that the value has not changed again in the meantime; (5) Policy Enforcer sends or updates an adaptive card through the Azure Bot Service, and the reviewer accepts a resolution or dismisses the violation in the review dialog. All compute emits telemetry to Application Insights and Log Analytics.

Policy Enforcer uses three deliberately separated authentication flows on one multi-tenant Microsoft Entra app registration:

  1. Sign-in (delegated). Users sign in with their Microsoft work account through Teams single sign-on. The API accepts only tokens issued for the Policy Enforcer app and derives the tenant from the validated token.
  2. Background processing (application). After admin consent, background workers obtain application tokens for the customer’s tenant. The app credential is stored in Azure Key Vault and is never sent to the browser; the browser never receives a Microsoft Graph token.
  3. Service account (delegated, optional). For the few operations listed under Microsoft Graph, a tenant administrator connects a dedicated service account. Its refresh token is encrypted with AES-256-GCM and bound to the tenant; tokens are requested per operation with the minimum scope needed.

Per-tenant isolation is enforced by the tenant identifier carried in every token: each request is scoped to the tenant of its validated token, every tenant-owned record carries that tenant identifier, and Graph tokens are issued per tenant. Within a tenant, access is role-based: only Teams Manager administrators can configure Policy Enforcer, and group owners can review violations of the spaces they own when this is enabled. All secrets are held in Azure Key Vault and read by the services through their system-assigned managed identities; all endpoints are HTTPS-only and the database connection is encrypted.

Resource Endpoints

Domains that a customer’s network or browser must be able to reach.

NameComments
app-pe-prod.azurewebsites.netThe Policy Enforcer web UI, its API and real-time updates (WebSocket), loaded inside Microsoft Teams.
login.microsoftonline.comMicrosoft Entra ID — sign-in, admin consent and OAuth token issuance (browser and backend).
*.applicationinsights.azure.comAzure Application Insights — diagnostic telemetry from the web UI (browser).

Backend service egress (informational)

Outbound calls made by the Solutions2Share-operated backend. These are not customer-configurable and are listed for transparency.

NameComments
graph.microsoft.comMicrosoft Graph — audit-log reads, group reads and policy reverts.
smba.trafficmanager.netAzure Bot Service (Bot Framework connector for Microsoft Teams) — delivery of Teams notifications.
s2slicensing.azurewebsites.netSolutions2Share License Management Center — product entitlement validation (tenant ID and product name only).
*.database.windows.netAzure SQL Database — Policy Enforcer data store and read-only Teams Manager connection.
*.servicebus.windows.netAzure Service Bus — background work queues.
*.vault.azure.netAzure Key Vault — secrets and keys.
*.blob.core.windows.net, *.queue.core.windows.net, *.table.core.windows.netAzure Storage — background-worker runtime storage.

Dependencies

Third-party libraries used by Policy Enforcer. Versions reflect the current release.

Server

NameVersionUrlLicense
@azure/functions4.16.0npmjs.com/package/@azure/functionsMIT
@azure/identity4.13.1npmjs.com/package/@azure/identityMIT
@azure/keyvault-secrets4.11.2npmjs.com/package/@azure/keyvault-secretsMIT
@azure/monitor-opentelemetry1.18.0npmjs.com/package/@azure/monitor-opentelemetryMIT
@azure/msal-node5.2.2 / 2.16.3npmjs.com/package/@azure/msal-nodeMIT
@azure/service-bus7.9.5npmjs.com/package/@azure/service-busMIT
@azure/storage-blob12.31.0npmjs.com/package/@azure/storage-blobMIT
@microsoft/microsoft-graph-client3.0.7npmjs.com/package/@microsoft/microsoft-graph-clientMIT
@nestjs/axios4.0.1npmjs.com/package/@nestjs/axiosMIT
@nestjs/cache-manager3.1.2npmjs.com/package/@nestjs/cache-managerMIT
@nestjs/common11.1.24npmjs.com/package/@nestjs/commonMIT
@nestjs/config4.0.4npmjs.com/package/@nestjs/configMIT
@nestjs/core11.1.24npmjs.com/package/@nestjs/coreMIT
@nestjs/platform-express11.1.24npmjs.com/package/@nestjs/platform-expressMIT
@nestjs/platform-socket.io11.1.24npmjs.com/package/@nestjs/platform-socket.ioMIT
@nestjs/serve-static5.0.5npmjs.com/package/@nestjs/serve-staticMIT
@nestjs/websockets11.1.24npmjs.com/package/@nestjs/websocketsMIT
@opentelemetry/api1.9.1npmjs.com/package/@opentelemetry/apiApache-2.0
@opentelemetry/api-logs0.208.0npmjs.com/package/@opentelemetry/api-logsApache-2.0
@prisma/adapter-mssql7.8.0npmjs.com/package/@prisma/adapter-mssqlApache-2.0
@prisma/client7.8.0npmjs.com/package/@prisma/clientApache-2.0
@sendgrid/mail8.1.6npmjs.com/package/@sendgrid/mailMIT
async-mutex0.5.0npmjs.com/package/async-mutexMIT
axios1.16.1npmjs.com/package/axiosMIT
botbuilder4.23.3npmjs.com/package/botbuilderMIT
botframework-connector4.23.3npmjs.com/package/botframework-connectorMIT
cache-manager7.2.8npmjs.com/package/cache-managerMIT
class-transformer0.5.1npmjs.com/package/class-transformerMIT
class-validator0.15.1npmjs.com/package/class-validatorMIT
dotenv17.4.2npmjs.com/package/dotenvBSD-2-Clause
durable-functions3.3.1npmjs.com/package/durable-functionsMIT
http-proxy-middleware3.0.5npmjs.com/package/http-proxy-middlewareMIT
jose6.2.3npmjs.com/package/joseMIT
mssql12.5.4npmjs.com/package/mssqlMIT
prisma7.8.0npmjs.com/package/prismaApache-2.0
reflect-metadata0.2.2npmjs.com/package/reflect-metadataApache-2.0
rxjs7.8.2npmjs.com/package/rxjsApache-2.0
socket.io4.8.3npmjs.com/package/socket.ioMIT

Client Packages

NameVersionUrlLicense
@azure/msal-browser5.11.0npmjs.com/package/@azure/msal-browserMIT
@fluentui/react-components9.73.8npmjs.com/package/@fluentui/react-componentsMIT
@fluentui/react-icons2.0.328npmjs.com/package/@fluentui/react-iconsMIT
@microsoft/applicationinsights-web3.4.1npmjs.com/package/@microsoft/applicationinsights-webMIT
@microsoft/teams-js2.53.0npmjs.com/package/@microsoft/teams-jsMIT
@reduxjs/toolkit2.12.0npmjs.com/package/@reduxjs/toolkitMIT
@tanstack/react-query5.100.14npmjs.com/package/@tanstack/react-queryMIT
axios1.16.1npmjs.com/package/axiosMIT
i18next26.2.0npmjs.com/package/i18nextMIT
i18next-browser-languagedetector8.2.1npmjs.com/package/i18next-browser-languagedetectorMIT
react19.2.5npmjs.com/package/reactMIT
react-dom19.2.5npmjs.com/package/react-domMIT
react-i18next17.0.8npmjs.com/package/react-i18nextMIT
react-image-crop11.0.10npmjs.com/package/react-image-cropISC
react-pdf10.4.1npmjs.com/package/react-pdfMIT
react-redux9.3.0npmjs.com/package/react-reduxMIT
react-router-dom7.15.1npmjs.com/package/react-router-domMIT
socket.io-client4.8.3npmjs.com/package/socket.io-clientMIT

Build and test tooling

Used only to build and test the app; not shipped to the browser or deployed to the server.

NameVersionUrlLicense
@rsbuild/core1.7.5npmjs.com/package/@rsbuild/coreMIT
@rsbuild/plugin-react1.4.6npmjs.com/package/@rsbuild/plugin-reactMIT
@nestjs/cli11.0.21npmjs.com/package/@nestjs/cliMIT
@nestjs/testing11.1.24npmjs.com/package/@nestjs/testingMIT
typescript5.9.3npmjs.com/package/typescriptApache-2.0
@typescript/native-preview7.0.0-devnpmjs.com/package/@typescript/native-previewApache-2.0
ts-node10.9.2npmjs.com/package/ts-nodeMIT
tsx4.22.3npmjs.com/package/tsxMIT
tailwindcss4.3.0npmjs.com/package/tailwindcssMIT
@tailwindcss/postcss4.3.0npmjs.com/package/@tailwindcss/postcssMIT
jest30.4.2 / 29.7.0npmjs.com/package/jestMIT
ts-jest29.4.11npmjs.com/package/ts-jestMIT
jest-environment-jsdom30.4.1npmjs.com/package/jest-environment-jsdomMIT
jest-axe10.0.0npmjs.com/package/jest-axeMIT
@testing-library/react16.3.2npmjs.com/package/@testing-library/reactMIT
@testing-library/jest-dom6.9.1npmjs.com/package/@testing-library/jest-domMIT
@testing-library/user-event14.6.1npmjs.com/package/@testing-library/user-eventMIT
msw2.14.6npmjs.com/package/mswMIT
undici6.27.0npmjs.com/package/undiciMIT
supertest7.2.2npmjs.com/package/supertestMIT
@playwright/test1.61.0npmjs.com/package/@playwright/testApache-2.0
@axe-core/playwright4.12.1npmjs.com/package/@axe-core/playwrightMPL-2.0
eslint9.39.4npmjs.com/package/eslintMIT
typescript-eslint8.59.4npmjs.com/package/typescript-eslintMIT
prettier3.8.3npmjs.com/package/prettierMIT

Policy Enforcer uses no third-party analytics or advertising trackers. The Policy Enforcer back end sends customer data only to Microsoft/Azure services and the Solutions2Share License Management Center.

Didn't find your answer?Contact Us