Getting started

1. Five-minute local demo (docker-compose)

The fastest way to see the product. Auth is disabled in compose, so the UI works without an identity provider - you just can't reach real tenants yet. The published images on ghcr.io are public, so no clone or build is needed:

curl -LO https://raw.githubusercontent.com/Spillers-Technology/PartnerCenterBridge/main/docker-compose.ghcr.yml
docker compose -f docker-compose.ghcr.yml up
# SPA:  http://localhost:8082
# API:  http://localhost:5080  (Swagger at /swagger)

Or build from source:

git clone https://github.com/Spillers-Technology/PartnerCenterBridge.git
cd PartnerCenterBridge
docker compose up --build

To point the same stack at real tenants later, create a .env file next to the compose file (see .env.example in the repo) and fill in the PARTNER_* (and optionally EXCHANGE_*) values - compose picks them up automatically.

Or run the pieces directly:

# API (needs a Postgres; connection string in appsettings.json)
dotnet run --project src/PartnerCenterBridge.Api

# SPA (proxies /api to http://localhost:5080)
cd web && npm install && npm run dev

Tests need no tenant at all - orchestration is covered against WireMock:

dotnet test

2. Connect real tenants

To act in customer tenants the bridge needs the standard CSP plumbing you likely already have as an MSP:

RequirementWhy
A multi-tenant Entra app registration in your partner tenant (client id + secret in the Partner config section) This is the Secure Application Model app that acts on your behalf.
GDAP relationship per customer, with roles covering what you use (Intune administration, user management, Exchange recipient management) Scopes what the bridge can touch in each tenant. No GDAP, no access - the tenant shows as NoDelegation.
Per-customer admin consent for the app Standard multi-tenant app consent in each customer tenant.
A one-time SAM bootstrap by an MFA'd admin agent Seeds the encrypted, auto-rotating refresh token the bridge exchanges for per-tenant Graph tokens.
(Exchange workflows only) an app-only certificate for Exchange Online PowerShell (Exchange config section) Mailbox configuration is not fully exposed by Graph; the bridge shells out to the EXO V3 module with certificate auth.

App registration permissions

The Secure Application Model uses delegated (App+User) permissions: the bridge acts as the admin agent whose refresh token you seed at bootstrap. Grant these delegated permissions on the multi-tenant app registration and admin-consent them in your partner tenant. Effective access in each customer tenant is the intersection of this list with the roles on that customer's GDAP relationship.

APIDelegated permissionUsed for
Partner Center (https://api.partnercenter.microsoft.com) user_impersonation Customer list sync; the SAM token exchange itself.
Microsoft Graph DeviceManagementApps.ReadWrite.All Win32 app templates: create, upload and assign Intune apps.
Microsoft Graph User.ReadWrite.All New hire, offboard (block sign-in, revoke sessions), license assignment, user lookups.
Microsoft Graph Group.ReadWrite.All Adding/removing group membership during provisioning and offboarding.
Microsoft Graph UserAuthenticationMethod.ReadWrite.All MFA reset and compromised-account lockdown (enumerating and deleting auth methods).
Microsoft Graph User-PasswordProfile.ReadWrite.All Password reset workflow.
Microsoft Graph Organization.Read.All Reading subscribed SKUs for the license pickers and license repair.
Microsoft Graph Policy.Read.All Config Snapshots: reading Conditional Access Policies and Named Locations.
Microsoft Graph DeviceManagementConfiguration.Read.All Config Snapshots: reading Device Compliance Policies.
Treat this as the minimum. Because tokens are requested with /.default, the bridge can only ever use what is consented on the app - adding a permission later means re-consenting in the partner tenant (customer tenants inherit via GDAP + the multi-tenant consent).

3. First session

  1. Sync tenants: the Tenants tab pulls your customer list from Partner Center.
  2. Create a contract: a named group of tenants sharing a desired state.
  3. Assign tenants to the contract.
  4. Add an app template (upload an .intunewin produced by the Microsoft Win32 Content Prep Tool) or a provisioning template (licenses, groups, UPN domain).
  5. Deploy / provision / run workflows. Everything shows its plan or its diagnosis before it acts, and its steps after.
  6. Take a config snapshot (optional): the Config Snapshots tab backs up Conditional Access, Named Locations, and Device Compliance Policies for a tenant and diffs any two runs. See Config Snapshots.
Operator auth: two real options for production, not just one. Put the SPA and API behind your own OIDC provider (tested with Authentik) via the Auth section (authority, audience) and matching VITE_OIDC_* SPA variables -- or set Auth:Mode=Local for self-registered accounts (passkeys, TOTP, per-tenant sharing) with no external IdP at all. Full detail: Authentication. Auth:Mode=Dev (Auth:Enabled=false) is for local development only -- never on a deployed instance.