@salesforce/afv-skills 1.40.0 → 1.41.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/package.json +1 -1
  2. package/skills/automation-flow-generate/SKILL.md +32 -43
  3. package/skills/experience-portal-create/SKILL.md +497 -0
  4. package/skills/experience-portal-create/assets/report-template.md +30 -0
  5. package/skills/experience-portal-create/references/mcp-invocation.md +288 -0
  6. package/skills/experience-portal-create/references/post-creation-activate-publish.md +165 -0
  7. package/skills/experience-portal-create/references/templates.md +253 -0
  8. package/skills/experience-ui-bundle-features-generate/SKILL.md +5 -1
  9. package/skills/experience-ui-bundle-frontend-generate/SKILL.md +2 -0
  10. package/skills/experience-ui-bundle-frontend-generate/references/page.md +1 -0
  11. package/skills/platform-datamask-run/SKILL.md +345 -0
  12. package/skills/platform-datamask-run/references/api-surface.md +130 -0
  13. package/skills/platform-datamask-run/references/policy-authoring.md +185 -0
  14. package/skills/platform-datamask-run/references/run-and-abort.md +116 -0
  15. package/skills/platform-datamask-run/scripts/poll-job.sh +115 -0
  16. package/skills/platform-dataspace-access-configure/SKILL.md +51 -3
  17. package/skills/platform-dataspace-access-configure/scripts/inspect-dataspace-scopes.sh +56 -0
  18. package/skills/platform-lightning-type-widget-coordinate/references/build-plan-format.md +1 -0
  19. package/skills/platform-sandbox-configure/SKILL.md +17 -2
  20. package/skills/platform-trial-org-create/SKILL.md +175 -0
  21. package/skills/platform-trial-org-create/examples/create_request.json +9 -0
  22. package/skills/platform-trial-org-create/examples/error_response.json +41 -0
  23. package/skills/platform-trial-org-create/examples/success_response.json +27 -0
  24. package/skills/platform-trial-org-create/references/error_codes.md +42 -0
  25. package/skills/platform-trial-org-create/references/signup_request_fields.md +69 -0
  26. package/skills/platform-trial-org-create/scripts/create_signup_request.sh +175 -0
  27. package/skills/platform-trial-org-create/scripts/get_signup_request.sh +155 -0
  28. package/skills/platform-widget-generate/SKILL.md +47 -6
  29. package/skills/platform-widget-generate/examples/conditional.json +3 -3
  30. package/skills/platform-widget-generate/examples/list-with-foreach.json +2 -2
  31. package/skills/platform-widget-generate/examples/single-object.json +2 -2
  32. package/skills/platform-widget-generate/references/widget-bundle-layout.md +1 -1
  33. package/skills/service-agentforce-channel-configure/SKILL.md +271 -0
  34. package/skills/service-agentforce-channel-configure/references/agent-wiring.md +97 -0
  35. package/skills/service-agentforce-channel-configure/references/channel-branch-email.md +145 -0
  36. package/skills/service-agentforce-channel-configure/references/channel-branch-voice.md +69 -0
  37. package/skills/service-agentforce-channel-configure/references/channel-types.md +61 -0
  38. package/skills/service-agentforce-channel-configure/references/live-traffic-gate.md +86 -0
  39. package/skills/service-agentforce-channel-configure/references/queue-resolution.md +135 -0
  40. package/skills/service-agentforce-channel-configure/references/routing-flow.md +384 -0
  41. package/skills/service-catalog-template-deploy/SKILL.md +310 -0
  42. package/skills/service-catalog-template-deploy/references/cli-invocation.md +258 -0
  43. package/skills/service-catalog-template-deploy/scripts/activate-verify.mjs +164 -0
  44. package/skills/service-catalog-template-deploy/scripts/build-deploy-payload.mjs +94 -0
  45. package/skills/service-catalog-template-deploy/scripts/resolve-template.mjs +331 -0
  46. package/skills/service-catalog-template-search/SKILL.md +212 -0
  47. package/skills/service-catalog-template-search/references/cli-invocation.md +128 -0
  48. package/skills/service-catalog-template-search/scripts/classify-catalog.mjs +205 -0
  49. package/skills/service-concierge-portal-generate/SKILL.md +126 -0
  50. package/skills/service-concierge-portal-generate/references/portal-deploy-runbook.md +1428 -0
  51. package/skills/service-digital-engagement-channel-configure/SKILL.md +46 -6
  52. package/skills/service-digital-engagement-channel-configure/assets/messaging_channel_template.xml +2 -1
  53. package/skills/service-digital-engagement-channel-configure/examples/asa_agent_channel.xml +4 -1
  54. package/skills/service-helpagent-coordinate/README.md +8 -2
  55. package/skills/service-helpagent-coordinate/SKILL.md +126 -130
  56. package/skills/service-helpagent-coordinate/assets/help-agent-spec.md +70 -53
  57. package/skills/service-helpagent-coordinate/references/agent-script.md +571 -457
  58. package/skills/service-helpagent-coordinate/references/channel-voice.md +38 -9
  59. package/skills/service-helpagent-coordinate/references/channel-web-chat.md +173 -49
  60. package/skills/service-helpagent-coordinate/references/output-report-format.md +126 -0
  61. package/skills/service-itsm-agentic-setup-agentforce-coordinate/SKILL.md +153 -0
  62. package/skills/service-itsm-agentic-setup-agentforce-coordinate/examples/output-templates.md +79 -0
  63. package/skills/service-itsm-agentic-setup-agentforce-coordinate/scripts/verify-child-verdict.mjs +35 -0
  64. package/skills/service-itsm-agentic-setup-agentforce-studio-configure/SKILL.md +271 -0
  65. package/skills/service-itsm-agentic-setup-agentforce-studio-configure/references/cli-invocation.md +265 -0
  66. package/skills/service-itsm-agentic-setup-agentforce-studio-configure/scripts/classify-enable-plan.mjs +220 -0
  67. package/skills/service-itsm-agentic-setup-agentforce-studio-configure/scripts/classify-final-report.mjs +102 -0
  68. package/skills/service-itsm-agentic-setup-agentforce-studio-configure/scripts/record-enable-result.mjs +73 -0
  69. package/skills/service-itsm-agentic-setup-agentforce-studio-validate/SKILL.md +206 -0
  70. package/skills/service-itsm-agentic-setup-agentforce-studio-validate/references/cli-invocation.md +194 -0
  71. package/skills/service-itsm-agentic-setup-agentforce-studio-validate/scripts/classify-readiness.mjs +223 -0
  72. package/skills/service-itsm-agentic-setup-cmdb-configure/SKILL.md +45 -7
  73. package/skills/service-itsm-agentic-setup-cmdb-configure/references/mcp-invocation.md +45 -5
  74. package/skills/service-itsm-agentic-setup-configure/SKILL.md +116 -0
  75. package/skills/service-itsm-agentic-setup-configure/examples/output-templates.md +64 -0
  76. package/skills/service-itsm-agentic-setup-employee-agent-configure/SKILL.md +158 -0
  77. package/skills/service-itsm-agentic-setup-employee-agent-configure/references/cli-invocation.md +361 -0
  78. package/skills/service-itsm-agentic-setup-employee-agent-configure/references/error-taxonomy.md +44 -0
  79. package/skills/service-itsm-agentic-setup-employee-agent-configure/references/reactivation.md +66 -0
  80. package/skills/service-itsm-agentic-setup-employee-agent-configure/references/report-format.md +66 -0
  81. package/skills/service-itsm-agentic-setup-employee-agent-configure/references/specialized-templates.md +148 -0
  82. package/skills/service-itsm-agentic-setup-employee-agent-configure/references/workflow-detail.md +169 -0
  83. package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/build-create-body.mjs +116 -0
  84. package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/classify-agent-existence.mjs +185 -0
  85. package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/classify-preflight.mjs +168 -0
  86. package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/create-scratch-dir.mjs +58 -0
  87. package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/render-report.mjs +197 -0
  88. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/SKILL.md +186 -0
  89. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/action-availability.md +51 -0
  90. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/cli-invocation.md +345 -0
  91. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/error-taxonomy.md +44 -0
  92. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/reactivation.md +63 -0
  93. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/report-format.md +44 -0
  94. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/workflow-detail.md +149 -0
  95. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/build-create-body.mjs +110 -0
  96. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/classify-action-availability.mjs +201 -0
  97. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/classify-activate-result.mjs +135 -0
  98. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/classify-agent-existence.mjs +194 -0
  99. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/classify-preflight.mjs +158 -0
  100. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/create-scratch-dir.mjs +58 -0
  101. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/render-report.mjs +191 -0
  102. package/skills/service-itsm-agentic-setup-incident-management/SKILL.md +133 -0
  103. package/skills/service-itsm-agentic-setup-incident-management/examples/output-templates.md +71 -0
  104. package/skills/service-itsm-agentic-setup-incident-sla-configure/SKILL.md +308 -0
  105. package/skills/service-itsm-agentic-setup-incident-sla-configure/assets/attach-milestone.json +23 -0
  106. package/skills/service-itsm-agentic-setup-incident-sla-configure/examples/milestone-patterns.md +193 -0
  107. package/skills/service-itsm-agentic-setup-incident-sla-configure/examples/output-templates.md +57 -0
  108. package/skills/service-itsm-agentic-setup-incident-sla-configure/references/mcp-invocation.md +394 -0
  109. package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/SKILL.md +266 -0
  110. package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/references/cli-invocation.md +106 -0
  111. package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/references/helper-contracts.md +142 -0
  112. package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/references/permset-topology.md +82 -0
  113. package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/scripts/classify-action-surface.mjs +137 -0
  114. package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/scripts/classify-assignment-state.mjs +99 -0
  115. package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/scripts/classify-permset-availability.mjs +120 -0
  116. package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/scripts/resolve-target-user.mjs +86 -0
  117. package/skills/service-itsm-agentic-setup-uel-user-create/SKILL.md +284 -0
  118. package/skills/service-itsm-agentic-setup-uel-user-create/references/mcp-invocation.md +302 -0
  119. package/skills/service-itsm-channels-coordinate/SKILL.md +472 -0
  120. package/skills/service-itsm-incident-mgmt-configure/SKILL.md +212 -0
  121. package/skills/service-itsm-incident-mgmt-configure/references/mcp-invocation.md +225 -0
  122. package/skills/service-itsm-incident-priority-configure/SKILL.md +53 -12
  123. package/skills/service-itsm-swarming-configure/SKILL.md +212 -0
  124. package/skills/service-itsm-teams-configure/SKILL.md +395 -0
  125. package/skills/service-itsm-teams-configure/references/azure-credential-population.md +213 -0
  126. package/skills/service-itsm-teams-configure/references/gotchas.md +23 -0
  127. package/skills/service-itsm-teams-coordinate/SKILL.md +175 -0
  128. package/skills/service-itsm-teams-coordinate/examples/output-templates.md +85 -0
  129. package/skills/service-itsm-teams-debug/SKILL.md +144 -0
  130. package/skills/service-itsm-teams-debug/references/configuration-checklists.md +277 -0
  131. package/skills/service-itsm-teams-debug/references/report-generation.md +95 -0
  132. package/skills/service-itsm-teams-employee-agent-configure/SKILL.md +139 -0
  133. package/skills/service-itsm-teams-employee-agent-configure/assets/Teams_AgentForce.EmbeddedServiceConfig-meta.xml +43 -0
  134. package/skills/service-itsm-teams-employee-agent-configure/references/teams-embedded-employee-agent.md +480 -0
  135. package/skills/service-itsm-teams-itdesk-configure/SKILL.md +232 -0
  136. package/skills/service-itsm-teams-itservice-configure/SKILL.md +391 -0
@@ -0,0 +1,395 @@
1
+ ---
2
+ name: service-itsm-teams-configure
3
+ description: "Enable Microsoft Teams for Employee Service (ITSM) in Salesforce — the Salesforce Go feature service-cloud-itsm-teams-integration gating Teams-based IT Desk and IT Service collaboration. Use this for: 'enable Teams for employee service', 'turn on ITSM Teams integration', 'enable Microsoft Teams for IT Service', 'set up Salesforce IT Desk Teams app', 'enable ITSMTeamsEnabled', 'why can't I enable the Teams org preference', or any request to enable/verify this Salesforce Go feature. DO NOT TRIGGER for configuring the TeamsNotifications notification-channel preference or for enabling the Swarming feature itself (service-itsm-swarming-configure)."
4
+ metadata:
5
+ version: "1.0"
6
+ domains: ["Service"]
7
+ minApiVersion: "67.0"
8
+ relatedSkills:
9
+ - "experience-portal-create"
10
+ - "service-itsm-channels-coordinate"
11
+ - "service-itsm-swarming-configure"
12
+ - "service-itsm-teams-employee-agent-configure"
13
+ - "service-itsm-teams-itdesk-configure"
14
+ - "service-itsm-teams-itservice-configure"
15
+ mcpTools:
16
+ headless-360:
17
+ tools: ["describe", "discover", "dispatch", "dispatch_readonly"]
18
+ semver: ">=1.0.0"
19
+ cliTools:
20
+ - tool: ["sf"]
21
+ semver: ">=2.0.0"
22
+ accessCheck:
23
+ - type: "orgPerm"
24
+ value: "MSTeamsSetupAutomationAccess"
25
+ allowed-tools: |
26
+ Read AskUserQuestion Bash
27
+ mcp__headless-360__discover
28
+ mcp__headless-360__describe
29
+ mcp__headless-360__dispatch
30
+ mcp__headless-360__dispatch_readonly
31
+ ---
32
+
33
+ # Enable Microsoft Teams for Employee Service (ITSM)
34
+
35
+ Enable the Salesforce Go feature **"Microsoft Teams for Employee Service"**
36
+ (`service-cloud-itsm-teams-integration`) — the feature that lets IT Desk and IT Service
37
+ agents track tickets, request catalog items, and get Agentforce assistance from inside
38
+ Microsoft Teams. Every operation dispatches through **headless-360**.
39
+
40
+ > **Execute one step at a time.** These steps make real, state-changing API calls. Run a single
41
+ > operation, show its result, confirm it succeeded, then proceed — do not batch multiple setup
42
+ > calls into one parallel block.
43
+
44
+ ## Scope
45
+
46
+ - **In scope**: Enabling the `service-cloud-itsm-teams-integration` Go feature via its
47
+ feature-enablement Connect API; verifying feature and `ITSMTeamsEnabled` preference state
48
+ afterward; explaining why the direct org-preference PATCH route fails and why this route
49
+ works instead; disabling the feature if requested; giving the user step-by-step instructions
50
+ for the Azure/Entra app registration (Step 4a) since no Salesforce API can perform that part;
51
+ once the user provides the resulting Client ID/Tenant ID (in chat) and the Client Secret (via the
52
+ `TEAMS_ENTRA_CLIENT_SECRET` env var / secret file, never in chat), writing them
53
+ directly into the `MSTeamsSetupClientCredentialsEC` Named Credential via API — this
54
+ Salesforce-side write is always automated by this skill, never deferred back to the user;
55
+ registering the Experience Cloud site as the Teams "preferred site" extension via
56
+ `/connect/service-itsm-teams/graph-api/extensions` once that credential exists.
57
+ - **Out of scope**: Notification-channel preferences (`Notifications`, `TeamsNotifications`) —
58
+ a separate concern from this feature. Enabling the `service-cloud-swarming` Go feature itself —
59
+ delegate to `service-itsm-swarming-configure`. The IT Desk/fulfiller checklist group (Turn on
60
+ IT Desk, Install IT Desk app, Manage User Access, Set Teams as Collaboration Tool for
61
+ Swarming) — delegate to `service-itsm-teams-itdesk-configure`. The IT Service/employee
62
+ checklist group (Turn on IT Service, Install IT Service app, Manage User Access, Select a
63
+ Digital Experience Site) — delegate to `service-itsm-teams-itservice-configure`. Portal/site
64
+ creation — use `experience-portal-create`. The actual Azure-side actions (clicking through the
65
+ Azure portal, generating the client secret, granting Microsoft admin consent) must be
66
+ performed by the user in the Microsoft admin center — no Salesforce API reaches Azure/Entra —
67
+ but this skill still provides the exact instructions for those steps (see Gotchas and Step 4a)
68
+ rather than treating them as someone else's problem.
69
+
70
+ ---
71
+
72
+ ## The problem this skill solves
73
+
74
+ `ITSMTeamsEnabled` is the Salesforce Go page toggle preference gating Microsoft Teams ITSM integration. Its
75
+ UDD definition (`ServiceItsmTeams.settings.xml`) declares `orgAccess="always"` but has **no
76
+ `editAccess` attribute** — unlike working preferences such as `Notifications`/`TeamsNotifications`,
77
+ which explicitly set `editAccess="always"`. As a result, the direct Setup preferences Connect
78
+ API route is blocked:
79
+
80
+ ```text
81
+ GET /services/data/vXX.0/setup/org/preferences/ITSMTeamsEnabled
82
+ PATCH /services/data/vXX.0/setup/org/preferences/ITSMTeamsEnabled body: {"desiredState": true}
83
+ ```
84
+
85
+ Both return `401`:
86
+ ```json
87
+ {"error_code":"API_ERROR","status_code":401,"body":"[{\"errorCode\":\"INSUFFICIENT_ACCESS\",\"message\":\"Cannot read data!\"}]"}
88
+ ```
89
+ (`"Cannot update preference value!"` on the PATCH). This is a real, code-level access gate
90
+ (`StandardMetadataChecker` in `setup-connect-impl` relays an Aura `NoAccessException` — "bit(s)
91
+ do not have READ/WRITE access" — for this preference specifically), **not** a version-prefix or
92
+ routing mistake. Do not retry this route with different API versions or bodies.
93
+
94
+ **The verified working path is different: enable the Go *feature*, not the preference
95
+ directly.** The Salesforce Go feature-enablement Connect API sits behind a different access
96
+ check and, on enable, flips `ITSMTeamsEnabled` (and related feature state) as a side effect.
97
+
98
+ ---
99
+
100
+ ## Workflow
101
+
102
+ ### Step 1 — Check current feature status
103
+
104
+ ```text
105
+ mcp__headless-360__dispatch(
106
+ method: "POST",
107
+ url: "/services/data/v67.0/connect/setup/discovery/features/status",
108
+ body: { "featureApiNames": ["service-cloud-itsm-teams-integration"] }
109
+ )
110
+ ```
111
+
112
+ Response shape:
113
+ ```json
114
+ {
115
+ "items": [
116
+ {
117
+ "apiName": "service-cloud-itsm-teams-integration",
118
+ "status": "ENABLED", // or "NOT_ENABLED" / "DISABLED"
119
+ "blockedByApexLock": false,
120
+ "dependencyStatuses": [],
121
+ "enableBlockedReasons": [],
122
+ "disableBlockedReasons": []
123
+ }
124
+ ]
125
+ }
126
+ ```
127
+
128
+ If `status` is already `"ENABLED"`, skip to Step 3 (verification) — do not re-enable.
129
+ If `enableBlockedReasons` is non-empty, surface those reasons to the user (typically a missing
130
+ license/add-on) before attempting Step 2.
131
+
132
+ ### Step 2 — Enable the feature
133
+
134
+ ```text
135
+ mcp__headless-360__dispatch(
136
+ method: "POST",
137
+ url: "/services/data/v67.0/connect/setup/discovery/feature/service-cloud-itsm-teams-integration/enable",
138
+ body: {}
139
+ )
140
+ ```
141
+
142
+ **Known gotcha (verified):** this call can return `500 INTERNAL_ERROR` even when the feature
143
+ successfully ends up `ENABLED`. Do not treat a `500` here as a hard failure — always re-run
144
+ Step 1 (`features/status`) and Step 3 (`ITSMTeamsEnabled` read) afterward to check actual state
145
+ before reporting failure to the user. If status still shows `NOT_ENABLED` after retrying once,
146
+ then report the failure with the raw error.
147
+
148
+ ### Step 3 — Verify `ITSMTeamsEnabled` flipped
149
+
150
+ ```text
151
+ mcp__headless-360__dispatch_readonly(
152
+ method: "GET",
153
+ url: "/services/data/v67.0/setup/org/preferences/ITSMTeamsEnabled"
154
+ )
155
+ ```
156
+
157
+ Expect `200 {"isPreferenceEnabled": true}`. This confirms the underlying preference — otherwise
158
+ inaccessible via direct PATCH — is now enabled as a side effect of the feature enable.
159
+
160
+ ### Step 4 — Report *interim* status (setup is NOT complete yet)
161
+
162
+ Report feature status and whether `ITSMTeamsEnabled` reads `true` — but **frame this as progress,
163
+ not completion.** Enabling the Go feature is only the first half. The integration is **not
164
+ functional** until the Microsoft Entra app is registered, its credentials are written into the
165
+ Named Credential + Auth Provider, and admin consent is granted (Step 4a). Do **not** call this an
166
+ "optional manual tail," do **not** mark Teams "Done"/"configured"/"complete," and do **not** hand
167
+ back to any coordinator as done. State plainly: *"The Salesforce feature is enabled; Teams
168
+ integration is not yet complete — the required Microsoft Entra app registration comes next."* Then
169
+ proceed directly into Step 4a. See the **Completion contract** below for what "complete" requires.
170
+
171
+ ### Step 4a — Follow the Go page's own order: Create Entra app → Configure Named Credentials → Grant consent
172
+
173
+ The Salesforce Go feature page (Setup → Salesforce Go → this feature,
174
+ `.../lightning/setup/page/feature/service-cloud-itsm-teams-integration/home?topic=SalesforceGo`)
175
+ renders a **"Complete the Required Steps" → "Integrate Salesforce with Teams"** checklist with
176
+ exactly three items, in this order — verified from a live screenshot of the page. Follow this
177
+ order; do not skip ahead to Named Credentials before the Entra app exists, and do not treat
178
+ "Grant Azure Administrator Consent" as optional:
179
+
180
+ 1. **Create Microsoft Entra ID App** ("Set Up Microsoft Entra ID App" button — opens
181
+ portal.azure.com). There is no Salesforce API for this sub-step; give the user these exact
182
+ clicks and wait for them to provide the resulting values:
183
+ - **portal.azure.com** → **Microsoft Entra ID** → **App registrations** → **New registration**.
184
+ Name it something identifiable (e.g. `Salesforce ITSM Teams Integration`); single-tenant is
185
+ fine unless the user's org spans multiple tenants; no redirect URI is needed for the
186
+ client-credentials flow used here.
187
+ - From the app's **Overview** page, note the **Application (client) ID** and **Directory
188
+ (tenant) ID**.
189
+ - **Certificates & secrets** → **New client secret** → copy the secret **value** immediately
190
+ (unrecoverable after leaving the page).
191
+ - **API permissions** → **Add a permission** → **Microsoft Graph** → **Application
192
+ permissions** → add the Graph permissions this integration needs (at minimum
193
+ `ChannelMessage.Send`, `Team.ReadBasic.All`, `Channel.ReadBasic.All`,
194
+ `TeamworkAppSettings.ReadWrite.All` — confirm against the org's current Teams for Employee
195
+ Service documentation, since required scopes can change between releases).
196
+ - Provide the credentials **without exposing the secret in chat**: the **Client ID** and
197
+ **Tenant ID** are non-secret identifiers and may be given in the conversation, but the
198
+ **Client Secret is a confidential credential — NEVER ask for it in chat and never accept it
199
+ there.** The user places the secret in the `TEAMS_ENTRA_CLIENT_SECRET` environment variable
200
+ (or a gitignored secret file whose path they give you); you read it from that source at write
201
+ time and never print, echo, or log its value.
202
+ 2. **Configure Setup Named Credentials** ("Go to Setup" button on the Go page — the manual
203
+ equivalent of what this skill automates). **Once you have the Client ID / Tenant ID and the
204
+ secret is available in the env var / file, do not tell the user to enter anything into Setup —
205
+ call the Named Credential APIs directly**, per "Populating `MSTeamsSetupClientCredentialsEC`
206
+ given a user-supplied client ID/secret" under Step 5 below. **This same set of values must ALSO be written into the
207
+ `microsoft_auth_provider` Auth Provider** (the inbound-SSO side, distinct from the outbound-Graph
208
+ Named Credential) — the org provisions this Auth Provider empty. Do this automatically too; see
209
+ "Populating the `microsoft_auth_provider` Auth Provider" under Step 5. Both artifacts share the
210
+ same Client ID / Tenant ID / Client Secret and must be populated together — populating only the
211
+ Named Credential leaves portal SSO login broken.
212
+ 3. **Grant Azure Administrator Consent** ("Grant Consent" button on the Go page). Clicking it
213
+ opens a modal with a one-time consent link to a **fixed Salesforce-owned Entra app**
214
+ (`client_id=cd6bd63f-41ef-47cc-9465-86e986179a29`, tenant segment `organizations` — not the
215
+ user's own tenant ID, and not the app created in step 1) requesting the
216
+ `Organization.ReadWrite.All` delegated scope:
217
+ ```text
218
+ https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize?client_id=cd6bd63f-41ef-47cc-9465-86e986179a29&response_type=code&redirect_uri=https://salesforce.com&response_mode=query&scope=Organization.ReadWrite.All
219
+ ```
220
+ This link is static — it does not need to be fetched per-org or per-user, and headless-360 has
221
+ no operation that generates or dispatches it (it's rendered by an internal Aura controller with
222
+ no public Connect API mirror). **Paste this exact link and tell the user to click it, signed in
223
+ as a Microsoft tenant admin, to grant consent** — this action authenticates as the Microsoft
224
+ admin and cannot be performed by this skill via API.
225
+
226
+ Everything the user does above (steps 1's Azure clicks and step 3's consent click) is their
227
+ manual responsibility because no Salesforce API reaches Azure/Entra. Everything Salesforce-side —
228
+ writing the supplied credential (secret read from the env var / secret file, never from chat) into
229
+ the Named Credential in step 2 — is this skill's job to automate; that division of labor is the
230
+ entire point of this skill.
231
+
232
+ ### Step 4b — Delegate to the IT Desk / IT Service child skills
233
+
234
+ Before touching the "Set Up Salesforce IT Desk" / "Set Up Salesforce IT Service" checklist
235
+ groups, ask the user which they want — these are two independent halves of the feature
236
+ (fulfiller side vs. employee side) and a user may only need one:
237
+
238
+ - **Salesforce IT Desk** — for IT agents/fulfillers to swarm on and resolve tickets from Teams.
239
+ Invoke `service-itsm-teams-itdesk-configure`.
240
+ - **Salesforce IT Service** — for employees to create and manage their own tickets from Teams.
241
+ Invoke `service-itsm-teams-itservice-configure`.
242
+ - **Both** — invoke both child skills.
243
+
244
+ Each child skill handles its own 3-4 item checklist group (Turn on `<app>` → Install `<app>`
245
+ App on Teams → Manage User Access → optional 4th item) end-to-end — do not duplicate that logic
246
+ here.
247
+
248
+ ### Step 4c — Delegate the embedded Agentforce agent (Teams "Ask AI Agent")
249
+
250
+ If the user wants the embedded Agentforce agent to **reply** inside the Teams custom client
251
+ ("Salesforce Employee Assist" → "Ask AI Agent") — i.e. build the `Teams_AgentForce` MIAW
252
+ deployment, its Web channel (**User Verification ON + a `JWKS_URL` Key Set**), the routing flow to the
253
+ IT Service Employee Agent, and the **Agent Access permission set** for the portal user — **invoke
254
+ `service-itsm-teams-employee-agent-configure`.** That is a distinct, large capability with its own
255
+ object model; do not attempt it inline here. It requires the employee portal site
256
+ (`experience-portal-create`) to exist first.
257
+
258
+ ### Step 5 — Register the preferred site (Teams extension), once the Azure credential exists
259
+
260
+ Once the org has an external credential named `MSTeamsSetupClientCredentialsEC` (see Step 4a and
261
+ "Populating..." below), register the Experience Cloud site that should back the Teams integration:
262
+
263
+ ```text
264
+ mcp__headless-360__dispatch(
265
+ method: "POST",
266
+ url: "/services/data/v67.0/connect/service-itsm-teams/graph-api/extensions",
267
+ body: { "siteUrlPathPrefixes": ["<site urlPathPrefix from GET /connect/communities>"] }
268
+ )
269
+ ```
270
+
271
+ Update later with:
272
+ ```text
273
+ mcp__headless-360__dispatch(
274
+ method: "PATCH",
275
+ url: "/services/data/v67.0/connect/service-itsm-teams/graph-api/extensions/{extensionId}",
276
+ body: { "siteUrlPathPrefixes": ["<updated prefix list>"] }
277
+ )
278
+ ```
279
+
280
+ If this returns `400 UNKNOWN_EXCEPTION "...external credential \"MSTeamsSetupClientCredentialsEC\"
281
+ might not exist"`, the Azure/Entra step (Gotchas) has not been completed yet — this is not a bug
282
+ in the call itself.
283
+
284
+ If instead it returns `AccessDenied` (or `400 UNKNOWN_EXCEPTION "Exception while creating Teams
285
+ extension: Unable to fetch tenant ID"`) **even after** the external credential shows
286
+ `authenticationStatus: "Configured"`, the cause is almost always the **Azure app's Graph
287
+ permissions being of type _Delegated_ rather than _Application_** (client-credentials token flow
288
+ cannot use delegated-only permissions). This is a **fixable Azure/Entra misconfiguration, not a
289
+ hard license wall** — verified live this session: the same call went from `AccessDenied` to
290
+ `201 Success` (`com_sf_itsm_teams_config`) after two changes on the Azure side, with no license
291
+ change:
292
+
293
+ 1. In the Azure app registration → **API permissions**, ensure the Microsoft Graph permissions are
294
+ the **Application** type (not Delegated), then click **"Grant admin consent"** for the tenant.
295
+ 2. **Repopulate the credential** (see "Populating..." below) — re-provisioning or any feature
296
+ re-enable can leave the EC/Auth Provider empty; a freshly-populated `MSTeamsSetupClientCredentialsEC`
297
+ showing `authenticationStatus: "Configured"` is required at the moment of the retry.
298
+
299
+ Retry Step 5 after both. Only treat this as a genuine org-license blocker (the `MsTeamsAppApiFamily`
300
+ gotcha below) if the call **still** fails once Application-type Graph permissions + admin consent
301
+ are confirmed and the credential is freshly `Configured`.
302
+
303
+ Once you have the Azure Client ID and Tenant ID (given in chat) and the Client Secret (read from the
304
+ `TEAMS_ENTRA_CLIENT_SECRET` env var / secret file — never requested in chat; Step 4a), do the
305
+ Salesforce-side writes yourself — do not tell the user to enter values in Setup. The full verified
306
+ recipe (populating `MSTeamsSetupClientCredentialsEC`, populating the `microsoft_auth_provider` Auth
307
+ Provider for inbound SSO via the Metadata API, matching the portal user's `Username` to the Microsoft
308
+ UPN so `MsTeamsItsmSSOHandler` resolves them, and granting the portal user `ApiEnabled` for the Teams
309
+ Connect APIs) — with exact API bodies, the AuthProvider MDAPI template, the Web-vs-SPA callback
310
+ constraint, and their gotchas — is in:
311
+
312
+ **→ `references/azure-credential-population.md`**
313
+
314
+ ---
315
+
316
+ ## Completion contract — do NOT report Teams setup "complete" until all of these hold
317
+
318
+ The Go-feature enable (Steps 1–3) is necessary but **not sufficient**. The single most common
319
+ failure mode is declaring Teams "configured/done/complete" after Step 3 while the Microsoft Entra
320
+ app is still unregistered — which leaves in-Teams sign-in and the outbound Graph integration
321
+ **broken**. Treat the Entra app registration as a **blocking prerequisite of completion**, never an
322
+ optional tail. Report **complete only when every item below is verified** (not merely instructed):
323
+
324
+ 1. **Feature enabled** — `service-cloud-itsm-teams-integration` reads `ENABLED` and
325
+ `ITSMTeamsEnabled` reads `true` (Steps 1–3).
326
+ 2. **Microsoft Entra app registered** — the user has completed Step 4a's Azure clicks and provided
327
+ the Client ID and Tenant ID (in chat) with the Client Secret placed in the
328
+ `TEAMS_ENTRA_CLIENT_SECRET` env var / secret file (never pasted in chat). Until they do, **stop
329
+ and wait** — this is a hard gate; you cannot proceed past it, and you must not report completion
330
+ around it.
331
+ 3. **Credentials populated (Salesforce-side, automated by this skill)** — `MSTeamsSetupClientCredentialsEC`
332
+ reads `authenticationStatus: "Configured"` **and** the `microsoft_auth_provider` Auth Provider is
333
+ populated with the same values (see `references/azure-credential-population.md`). Populating only
334
+ one leaves either outbound Graph or inbound SSO broken.
335
+ 4. **Admin consent granted** — the user has clicked the static consent link in Step 4a item 3,
336
+ signed in as a Microsoft tenant admin.
337
+ 5. **Preferred site registered** — the Teams extension call in Step 5 returns success (or the user
338
+ has explicitly deferred the employee-site half).
339
+
340
+ If any of 2–4 is pending, the correct status is **"Blocked on Microsoft-admin action — Teams
341
+ integration incomplete,"** with the exact next step called out. A partial state is **not** a
342
+ success; do not soften it, and do not let a coordinator mark this feature `Done`.
343
+
344
+ ---
345
+
346
+ ## Disabling (if requested)
347
+
348
+ ```text
349
+ mcp__headless-360__dispatch(
350
+ method: "POST",
351
+ url: "/services/data/v67.0/connect/setup/discovery/feature/service-cloud-itsm-teams-integration/disable",
352
+ body: {}
353
+ )
354
+ ```
355
+
356
+ Re-run Step 1/Step 3 afterward to confirm. Disabling `ITSMTeamsEnabled`'s underlying
357
+ provisioning (SSO handler, named/external credentials, PKCE OAuth client) may not be fully
358
+ reversed by this call alone — verify with the user whether they also need those artifacts
359
+ removed and treat that as a separate, manual Setup exercise.
360
+
361
+ ---
362
+
363
+ ## Related, separately-enabled preferences
364
+
365
+ Two sibling org preferences drive the "Fulfiller Hub" and "Employee Hub" halves of this feature
366
+ and, unlike `ITSMTeamsEnabled`, **are** directly writable via the standard Setup preferences
367
+ Connect API — `GET/PATCH /services/data/v67.0/setup/org/preferences/OrgHasITSMFulfillerTeams`
368
+ ("Enable Salesforce IT Desk") and `.../OrgHasEmployeeServiceTeams` ("Enable Salesforce IT
369
+ Service"). Both take `{"desiredState": true}` and return `{"isPreferenceEnabled": true}`. They are
370
+ independent bits — enabling them does **not** unblock `ITSMTeamsEnabled`; enable them alongside,
371
+ not instead of, the Step 2 feature-enable call if the user wants both Hubs.
372
+
373
+ ---
374
+
375
+ ## Gotchas
376
+
377
+ The verified, load-bearing pitfalls (direct-PATCH 401, empty Auth Provider, Azure Web-vs-SPA
378
+ redirect, Username=UPN handler, portal API-Enabled, static consent link, `MsTeamsAppApiFamily`
379
+ 403 hard gate, version-prefix requirement, and more) are catalogued in
380
+ [`references/gotchas.md`](references/gotchas.md). Read it before reporting a step as failed or
381
+ retrying an enablement guess.
382
+
383
+ ---
384
+
385
+ ## Related Skills
386
+
387
+ | Skill | When to use instead |
388
+ |-------|---------------------|
389
+ | `service-itsm-teams-itdesk-configure` | The "Set Up Salesforce IT Desk" checklist group (fulfiller side) — this skill delegates to it (see Step 4b) |
390
+ | `service-itsm-teams-itservice-configure` | The "Set Up Salesforce IT Service" checklist group (employee side) — this skill delegates to it (see Step 4b) |
391
+ | `service-itsm-teams-employee-agent-configure` | Making the embedded Agentforce agent reply in the Teams "Ask AI Agent" custom client (`Teams_AgentForce` MIAW deployment) — this skill delegates to it (see Step 4c) |
392
+ | `service-itsm-swarming-configure` | Enabling the `service-cloud-swarming` Go feature for "Set Teams as Collaboration Tool for Swarming" — invoked by `service-itsm-teams-itdesk-configure`, not by this skill directly |
393
+ | Notification-channel preferences | Enabling the `Notifications`/`TeamsNotifications` preferences is a distinct concern from this feature (no dedicated child skill exists yet) |
394
+ | `experience-portal-create` | Creating the employee-service portal/site itself |
395
+ | `service-itsm-channels-coordinate` | Top-level menu across Teams, Slack, Swarming, Notifications, Portal |
@@ -0,0 +1,213 @@
1
+ # Populating the Azure credentials, inbound SSO, and portal-user access (Step 5 detail)
2
+
3
+ Reference for `service-itsm-teams-configure` Step 5. Once the org has an external credential named
4
+ `MSTeamsSetupClientCredentialsEC` and the user has supplied their Azure **Client ID** and **Tenant
5
+ ID** (non-secret identifiers, given in chat) and placed the **Client Secret** in the
6
+ `TEAMS_ENTRA_CLIENT_SECRET` environment variable or a gitignored secret file (Step 4a — **never ask
7
+ for the secret in chat**), these are the Salesforce-side writes that populate the outbound Graph
8
+ credential, the inbound-SSO Auth Provider, and the portal-user access that make the Teams IT Service
9
+ / IT Desk apps actually work. Read the secret from that env var / file at write time; never print,
10
+ echo, or log its value, and never send the literal `$TEAMS_ENTRA_CLIENT_SECRET` token to an API —
11
+ always resolve it to its actual value first (see the Secret-substitution note in Step 2). Do all of
12
+ these yourself — the user's manual responsibility ends at the Azure admin center.
13
+
14
+ ## Populating `MSTeamsSetupClientCredentialsEC` given a user-supplied client ID/secret
15
+
16
+ **Once the user supplies the Client ID and Tenant ID (in chat) and the Client Secret is available in
17
+ the `TEAMS_ENTRA_CLIENT_SECRET` env var / secret file (Step 4a — never in chat), write them into
18
+ Salesforce yourself via the calls below. Do not respond by telling the user to open Setup and enter
19
+ the values manually — that defeats the purpose of this skill.** The user's manual responsibility
20
+ ends at the Azure admin center (Step 4a); every Salesforce-side write, including this one, is this
21
+ skill's job.
22
+
23
+ 1. Fix the `AuthProviderUrl` parameter (it ships with a literal `{tenant_id}` placeholder):
24
+ ```text
25
+ mcp__headless-360__dispatch(
26
+ method: "PUT",
27
+ url: "/services/data/v67.0/named-credentials/external-credentials/MSTeamsSetupClientCredentialsEC",
28
+ body: { /* GET the record first, then re-PUT its full parameters[]/principals[] with
29
+ AuthProviderUrl set to https://login.microsoftonline.com/<tenant id>/oauth2/v2.0/token */ }
30
+ )
31
+ ```
32
+ This endpoint is full-replace — GET the EC first and mutate, don't send a partial body.
33
+ 2. Set the principal's client ID + secret (both required together in one call; there is no
34
+ partial-update path for just the client ID):
35
+ **Secret substitution — read this first.** `mcp__headless-360__dispatch` is a JSON API call, **not
36
+ a shell**: it does **not** expand `$TEAMS_ENTRA_CLIENT_SECRET`. Passing the literal string
37
+ `"$TEAMS_ENTRA_CLIENT_SECRET"` in the body stores that literal text as the OAuth client secret and
38
+ Graph authentication then fails after an apparently-successful configuration. You must resolve the
39
+ env var to its **actual value** and place that value into `clientSecret.value` at call time. Read it
40
+ with a **non-logging** read (e.g. a single `printenv TEAMS_ENTRA_CLIENT_SECRET` captured into an
41
+ in-memory variable, or read the secret file) — never `echo`/print it, never place the resolved
42
+ secret in any text you emit to the user or into a log, and never write it to disk. The `<secret
43
+ value read from $TEAMS_ENTRA_CLIENT_SECRET>` placeholder below denotes that resolved value, not a
44
+ literal to send:
45
+ ```text
46
+ mcp__headless-360__dispatch(
47
+ method: "POST", // or PUT (update-credential) if credentials already exist for this principal
48
+ url: "/services/data/v67.0/named-credentials/credential",
49
+ body: {
50
+ "externalCredential": "MSTeamsSetupClientCredentialsEC",
51
+ "principalName": "NamedAuthPrincipal",
52
+ "principalType": "NamedPrincipal",
53
+ "authenticationProtocol": "OAuth",
54
+ "authenticationProtocolVariant": "ClientCredentialsClientSecretBasic",
55
+ // clientSecret.value MUST be the resolved secret read from the TEAMS_ENTRA_CLIENT_SECRET env
56
+ // var / secret file — NOT the literal "$TEAMS_ENTRA_CLIENT_SECRET" token (dispatch does not
57
+ // expand shell variables). Resolve in memory via a non-logging read; never echo it.
58
+ "credentials": { "clientId": {"value": "<client id>"}, "clientSecret": {"value": "<secret value read from $TEAMS_ENTRA_CLIENT_SECRET>"} }
59
+ }
60
+ )
61
+ ```
62
+ 3. Verify: `GET /services/data/v67.0/named-credentials/external-credentials/MSTeamsSetupClientCredentialsEC`
63
+ should show `authenticationStatus: "Configured"`.
64
+ 4. If `MSTeamsSetupAutomationAccess` (the EC principal's access-gating permission set) is
65
+ unassigned for the running user, assign it via `POST /services/data/v67.0/sobjects/PermissionSetAssignment`
66
+ (`AssigneeId`, `PermissionSetId`) before retrying Step 5 — it auto-provisions but is not
67
+ auto-assigned.
68
+
69
+ ## Populating the `microsoft_auth_provider` Auth Provider (inbound SSO — do NOT skip)
70
+
71
+ Enabling the Teams feature also provisions a Microsoft-type **Auth Provider** named
72
+ `microsoft_auth_provider` (Setup → Identity → Auth Providers), left **empty** (no Consumer Key,
73
+ Consumer Secret, or endpoint URLs). This is the **inbound SSO** side — it authenticates employees
74
+ logging into the Experience Cloud portal that the Teams IT Service app embeds. It is a *separate
75
+ artifact* from the outbound-Graph `MSTeamsSetupClientCredentialsEC` Named Credential, but takes the
76
+ **same three values** the user supplied (secret from the env var / file, never chat). Populate it automatically in the same pass — a previous run
77
+ of this skill forgot this step, leaving portal SSO login broken even though the Named Credential
78
+ was configured.
79
+
80
+ **Key constraint (verified):** `AuthProvider.ConsumerSecret` is `createable` but **NOT
81
+ `updateable`** on the SObject — so `sf data update` / a Connect PATCH **cannot** set the secret on
82
+ the already-provisioned (empty) record, and headless-360 `discover` exposes **no** Connect route
83
+ that writes an Auth Provider secret. The working path is the **Metadata API**: `AuthProvider` is a
84
+ full MDAPI type whose `<consumerSecret>` round-trips on deploy. Author a source-format file and
85
+ deploy it (this sets every field, including the secret, with no UI):
86
+
87
+ ```xml
88
+ <!-- force-app/main/default/authproviders/microsoft_auth_provider.authprovider-meta.xml -->
89
+ <?xml version="1.0" encoding="UTF-8"?>
90
+ <AuthProvider xmlns="http://soap.sforce.com/2006/04/metadata">
91
+ <authorizeUrl>https://login.microsoftonline.com/<TENANT_ID>/oauth2/v2.0/authorize</authorizeUrl>
92
+ <consumerKey><CLIENT_ID></consumerKey>
93
+ <consumerSecret>${TEAMS_ENTRA_CLIENT_SECRET}</consumerSecret>
94
+ <defaultScopes>openid profile email offline_access https://graph.microsoft.com/.default</defaultScopes>
95
+ <friendlyName>microsoft_auth_provider</friendlyName>
96
+ <includeOrgIdInIdentifier>false</includeOrgIdInIdentifier>
97
+ <providerType>Microsoft</providerType>
98
+ <sendAccessTokenInHeader>true</sendAccessTokenInHeader>
99
+ <sendClientCredentialsInHeader>false</sendClientCredentialsInHeader>
100
+ <tokenUrl>https://login.microsoftonline.com/<TENANT_ID>/oauth2/v2.0/token</tokenUrl>
101
+ </AuthProvider>
102
+ ```
103
+
104
+ ```bash
105
+ sf project deploy start --source-dir force-app --target-org <org-alias>
106
+ ```
107
+
108
+ **Secret handling:** substitute `<TENANT_ID>` / `<CLIENT_ID>` (non-secret) directly, but inject the
109
+ `<consumerSecret>` value from `$TEAMS_ENTRA_CLIENT_SECRET` at build time (e.g. `envsubst` into a
110
+ gitignored temp copy under a scratch dir, deploy that, then delete it). **Never commit the populated
111
+ file** and never echo the secret. The secret comes from the env var / secret file — not from chat.
112
+
113
+ Notes:
114
+ - Use the **tenant-specific** `/…/<TENANT_ID>/oauth2/v2.0/…` endpoints, not `/common/` or
115
+ `/organizations/` — single-tenant Azure apps reject the generic endpoints.
116
+ - `--metadata-dir` (MDAPI format) proved flaky here ("named in package.xml but not found in zipped
117
+ directory"); the **source-format `--source-dir` deploy is the reliable route** — include a minimal
118
+ `sfdx-project.json` with `sourceApiVersion`.
119
+ - `<executionUser>` is optional for a Microsoft SSO Auth Provider (only needed when a registration
120
+ handler runs Apex); it may not bind on deploy and that is fine.
121
+ - **Verify** with `sf data query "SELECT ConsumerKey, AuthorizeUrl, TokenUrl, DefaultScopes FROM
122
+ AuthProvider WHERE DeveloperName = 'microsoft_auth_provider'"`. The **Consumer Secret is
123
+ write-only and will not read back** — a null secret in the query is expected, not a failure;
124
+ confirm the ConsumerKey and URLs populated.
125
+ - **After populating, give the user the Auth Provider's Callback URL to register in Azure.** (The
126
+ callback URL is not a secret.) The redirect URI the Azure app must trust is the OAuth callback endpoint on the org's My
127
+ Domain: `https://<my-domain>/services/authcallback/microsoft_auth_provider` (get `<my-domain>` from
128
+ `sf org display --json` → `instanceUrl`, or read the "OAuth-Only Initialization URL" from the Auth
129
+ Provider's Salesforce Configuration section in Setup). This is a **manual Azure step** — no
130
+ Salesforce API reaches Azure — so paste the exact URL and tell the user: **portal.azure.com → the
131
+ app registration → Authentication → add a platform → *Web* → add this Redirect URI → Save.**
132
+ - **Register the redirect URI under the "Web" platform, NOT "Single-page application" (SPA) — verified.**
133
+ This Auth Provider is a **confidential client**: it does a server-side token exchange using the
134
+ ConsumerSecret. Azure rejects secret-based token requests against a redirect URI registered as SPA,
135
+ so if the callback is added under the SPA platform the login *appears* to start (Salesforce even logs
136
+ a `LoginHistory` "Success" and mints `OauthToken` rows) but the callback round-trip fails at
137
+ `.../services/authcallback/microsoft_auth_provider` with **`OAUTH_APPROVAL_ERROR_GENERIC`**. Moving
138
+ the same redirect URI from the SPA platform to the Web platform in the Azure app fixes it. When you
139
+ emit the callback URL, explicitly tell the user it must go under **Web**, not SPA.
140
+ - Optionally also give the Single Logout URL (`https://<my-domain>/services/auth/rp/oidc/logout`) for
141
+ the app's Front-channel logout URL. Without the redirect URI registered on the Azure side, portal SSO
142
+ login fails with a redirect-mismatch error even though the Auth Provider is fully populated.
143
+
144
+ ## Making a portal user resolvable to the signed-in Microsoft user (Username = MS email — verified)
145
+
146
+ Populating the Auth Provider and its callback is not enough for a person to actually log into the
147
+ embedded Experience Cloud portal from the Teams IT Service (Employee) or IT Desk app. When a user
148
+ signs in through Microsoft, a custom Apex registration handler bound to `microsoft_auth_provider` —
149
+ **`MsTeamsItsmSSOHandler`** (Core module `service-itsm-teams-impl`) — resolves *which* Salesforce user
150
+ they are. Its logic (verified against Core source):
151
+
152
+ ```apex
153
+ global boolean canCreateUser(Auth.UserData data) { return false; } // no JIT
154
+ global User createUser(Id portalId, Auth.UserData data) {
155
+ String loginValue = data.email; // the Microsoft email/UPN claim
156
+ List<User> users = [SELECT Id FROM User WHERE Username = :loginValue LIMIT 2];
157
+ if (users.isEmpty() || users.size() > 1) return null; // 0 or >1 match → no login
158
+ return users[0];
159
+ }
160
+ ```
161
+
162
+ So the **Microsoft `email`/UPN claim must exactly equal a Salesforce `User.Username`** — not
163
+ `User.Email`, not `FederationIdentifier`. Exactly one active user must match; zero matches or a
164
+ duplicate both return `null`, and the app then shows **"you don't have access to the Microsoft account
165
+ in Salesforce."** There is **one handler / one Microsoft Auth Provider for the whole module** — both
166
+ the IT Service (Employee) and IT Desk (Fulfiller) apps use it; the Employee-vs-Fulfiller split lives
167
+ only in notification/adaptive-card routing, never in user resolution.
168
+
169
+ **Do this automatically** (this is a Salesforce-side write — do not defer it to the user): once you
170
+ know the Microsoft UPN the person signs in with, ensure the intended portal user's `Username` equals
171
+ it. First confirm no other user already holds that Username (a duplicate breaks the match too), then
172
+ set it via `PATCH /services/data/v67.0/sobjects/User/<userId>` body `{"Username": "<ms-upn>"}`. In this
173
+ session the empPortal user's Username was renamed to the tenant UPN (e.g. `admin@<tenant>.onmicrosoft.com`)
174
+ and login then resolved. Note UEL "Unified Employee" users are `UserType=Standard` internal users added
175
+ directly as Experience Cloud `NetworkMember`s (ContactId can be null) — they are **not** external
176
+ CspLitePortal users; the Username-match rule is the same regardless.
177
+
178
+ ## Granting the portal user API Enabled for the Teams Connect APIs (verified)
179
+
180
+ Even with SSO resolving correctly, the Teams IT Service (Employee) app calls Connect (Chatter) APIs
181
+ on the embedded portal — e.g.
182
+ `/empPortal/services/data/v66.0/connect/it-service/permissions/EmployeeApp?networkId=<networkId>`.
183
+ If the signed-in user lacks the **API Enabled** user permission, these calls fail with
184
+ **`API_DISABLED_FOR_ORG`** ("...or user type") and the browser Network tab shows **403 Forbidden** —
185
+ the app UI then fails to load its data even though login itself succeeded.
186
+
187
+ The managed permission sets the child skills assign (`TeamsForEmployeeUser`, `EmployeeHubEmployeeUser`)
188
+ do **not** grant `ApiEnabled`, and being managed-package permission sets they **cannot be edited** — a
189
+ Metadata API retrieve reports "cannot be found" and a direct SObject PATCH fails with "invalid record
190
+ id." The working fix is to **create a new *unmanaged* permission set with `ApiEnabled` only, deploy it,
191
+ and assign it** to the portal user. Do this yourself (Salesforce-side write):
192
+
193
+ ```xml
194
+ <!-- force-app/main/default/permissionsets/Teams_Employee_ApiAccess.permissionset-meta.xml -->
195
+ <?xml version="1.0" encoding="UTF-8"?>
196
+ <PermissionSet xmlns="http://soap.sforce.com/2006/04/metadata">
197
+ <label>Teams Employee API Access</label>
198
+ <description>Grants API Enabled to Unified Employee users so the MS Teams IT Service/Employee app can call Connect APIs. Added during ITSM Teams setup.</description>
199
+ <hasActivationRequired>false</hasActivationRequired>
200
+ <userPermissions><enabled>true</enabled><name>ApiEnabled</name></userPermissions>
201
+ </PermissionSet>
202
+ ```
203
+
204
+ ```bash
205
+ sf project deploy start --source-dir force-app --target-org <org-alias>
206
+ ```
207
+
208
+ Then assign it: `POST /services/data/v67.0/sobjects/PermissionSetAssignment` with `AssigneeId` (the
209
+ portal user) and `PermissionSetId` (the new set). **Grant `ApiEnabled` only — do NOT also add
210
+ `ChatterInternalUser`:** the Unified Employee license permits `ApiEnabled` but forbids
211
+ `ChatterInternalUser`, and including it makes the whole assignment fail with "user license doesn't allow
212
+ the permission: ChatterInternalUser." Verify with a query on `PermissionSet` /
213
+ `PermissionSetAssignment` (`PermissionsApiEnabled = true`).
@@ -0,0 +1,23 @@
1
+ # Gotchas — Microsoft Teams for Employee Service (ITSM) feature enablement
2
+
3
+ Verified, load-bearing pitfalls encountered enabling the Teams ITSM feature and wiring the
4
+ Azure/Entra app, Named Credential, Auth Provider, and portal user. Read these before reporting a
5
+ step as failed or retrying an enablement guess.
6
+
7
+ | Issue | Detail |
8
+ |-------|--------|
9
+ | Direct `PATCH /setup/org/preferences/ITSMTeamsEnabled` | Always `401 INSUFFICIENT_ACCESS`. Do not retry this route — use the feature-enable API instead. |
10
+ | `/enable` call returns `500 INTERNAL_ERROR` | Can still succeed. Always re-check `features/status` and the preference read before concluding failure. |
11
+ | `OrgHasITSMFulfillerTeams` / `OrgHasEmployeeServiceTeams` do not gate `ITSMTeamsEnabled` | These are separate Hub-visibility bits; enabling them does not itself unblock the Teams Salesforce Go page toggle preference. |
12
+ | `microsoft_auth_provider` Auth Provider must be populated too (easy to forget) | Enabling the feature provisions an **empty** Microsoft Auth Provider (`microsoft_auth_provider`) for inbound portal SSO — separate from the `MSTeamsSetupClientCredentialsEC` Named Credential but needing the **same** Client ID/Tenant ID/Client Secret. `AuthProvider.ConsumerSecret` is **not `updateable`** (so `sf data update`/Connect PATCH can't set it) and no headless-360 route writes it — populate via **Metadata API source-format deploy** (`sf project deploy start --source-dir`, `<consumerSecret>` round-trips). See "Populating the `microsoft_auth_provider` Auth Provider" under Step 5. Skipping this leaves portal login broken even with the Named Credential configured. |
13
+ | Azure redirect URI must be under the **Web** platform, not SPA | The `microsoft_auth_provider` Auth Provider is a **confidential client** (server-side token exchange using the ConsumerSecret). Azure rejects secret-based token requests against a redirect URI registered as **Single-page application (SPA)**. Symptom: login *appears* to start (Salesforce logs `LoginHistory` "Success" and mints `OauthToken` rows) but the callback fails at `.../services/authcallback/microsoft_auth_provider` with **`OAUTH_APPROVAL_ERROR_GENERIC`**. Fix (verified): register the callback URI under the Azure app's **Web** platform, not SPA. When emitting the callback URL to the user, always say **Web**. See the callback-URL note under "Populating the `microsoft_auth_provider` Auth Provider." |
14
+ | Portal login "you don't have access to the Microsoft account in Salesforce" → Username must equal the MS email/UPN | A custom Apex registration handler **`MsTeamsItsmSSOHandler`** (Core `service-itsm-teams-impl`, bound to `microsoft_auth_provider`) resolves the signed-in Microsoft user by `SELECT Id FROM User WHERE Username = :data.email` — the **Microsoft `email`/UPN claim must exactly equal a Salesforce `User.Username`** (not `User.Email`, not `FederationIdentifier`); `canCreateUser` returns false (no JIT), and 0 or >1 matches both return null → login denied. **One handler serves BOTH the IT Service (Employee) and IT Desk (Fulfiller) apps.** Fix (verified): set the intended portal user's `Username` to the MS UPN (after confirming no duplicate) via `PATCH .../sobjects/User/<id>` `{"Username":"<ms-upn>"}`. See "Making a portal user resolvable..." under Step 5. |
15
+ | Portal Connect API `API_DISABLED_FOR_ORG` / 403 → user needs API Enabled | The Teams IT Service (Employee) app calls Connect APIs on the embedded portal (e.g. `/connect/it-service/permissions/EmployeeApp`); without the **API Enabled** user permission these return `API_DISABLED_FOR_ORG` (403 in the Network tab) and the app fails to load data despite a successful login. The managed permission sets (`TeamsForEmployeeUser`, `EmployeeHubEmployeeUser`) don't grant `ApiEnabled` and **can't be edited** (managed-package: MDAPI retrieve "cannot be found", SObject PATCH "invalid record id"). Fix (verified): create + deploy a new **unmanaged** permission set with `ApiEnabled` only and assign it. **Do not add `ChatterInternalUser`** — the Unified Employee license forbids it (assignment fails "user license doesn't allow the permission: ChatterInternalUser"). See "Granting the portal user API Enabled..." under Step 5. |
16
+ | Azure/Entra app registration + admin consent have no Salesforce API | Salesforce only exposes a consent URL via an internal Aura controller (no public REST contract) — the user must click through the Azure admin center themselves. Give them the exact steps in Step 4a rather than a vague pointer, and once they provide the Client ID/Tenant ID (in chat) with the Client Secret in the `TEAMS_ENTRA_CLIENT_SECRET` env var / secret file (**never request the secret in chat**), take over immediately and write the credential into Salesforce yourself (see "Populating `MSTeamsSetupClientCredentialsEC`..." under Step 5) — do not tell them to enter it manually in Setup. |
17
+ | Go page's real checklist order (verified from a live screenshot) | The "Integrate Salesforce with Teams" group on the feature's Go page has exactly 3 items, in this order: **Create Microsoft Entra ID App** → **Configure Setup Named Credentials** → **Grant Azure Administrator Consent**. This is a *separate* checklist group from "Set Up Salesforce IT Desk" / "Set Up Salesforce IT Service" (delegated to `service-itsm-teams-itdesk-configure` / `service-itsm-teams-itservice-configure`) — do not conflate the groups when reporting progress to the user. |
18
+ | "Grant Azure Administrator Consent" consent link is static, not per-org | Clicking "Grant Consent" on the Go page opens a modal with this exact link: `https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize?client_id=cd6bd63f-41ef-47cc-9465-86e986179a29&response_type=code&redirect_uri=https://salesforce.com&response_mode=query&scope=Organization.ReadWrite.All`. The `client_id` here is Salesforce's own multi-tenant Entra app (**not** the app the user registers in step 1, and **not** related to the Client ID/Secret that go into the Named Credential) — it requests `Organization.ReadWrite.All` from whichever Microsoft tenant the signed-in admin belongs to (`organizations` tenant segment, not a specific tenant ID). headless-360 has no operation that generates this link or reads the Go page's live checklist state (searched `discover` for "grant Azure administrator consent generate consent URL" and "guided setup checklist progress Salesforce Go" — no matching SOR) — paste the link above verbatim and tell the user to click it themselves, signed in as a Microsoft tenant admin. |
19
+ | `preferredSite` / Teams extension registration **is** a public Connect API (verified) — corrects an earlier assumption | `POST /services/data/v67.0/connect/service-itsm-teams/graph-api/extensions` body `{"siteUrlPathPrefixes": ["<site urlPathPrefix>"]}` registers the Experience Cloud site as the Teams extension target; `PATCH .../extensions/{extensionId}` updates it. Verified live: it dispatches and reaches real logic (not a stub) — it fails with `400 UNKNOWN_EXCEPTION "We couldn't access the credential(s)... external credential \"MSTeamsSetupClientCredentialsEC\" might not exist"` until the Azure/Entra app registration is done and that named/external credential is wired up in Setup. Once the credential exists, call this to complete preferred-site selection — do not treat it as Aura-only. |
20
+ | `service-itsm-teams-connect-api` SOR (headless-360 `discover`) | Also exposes `get-teams-get-teams-list`, `get-teams-get-channel-list`, `post-teams-channel-message-send`, `get-teams-get-permissions`, `get-service-itsm-teams-collaboration-app-settings` (valid `targetApplication` values are `TeamsFulfillerApp` / `TeamsEmployeeApp`, not `teams`) — useful for verifying end-to-end Teams connectivity after the manual tail is complete. |
21
+ | `ms-teams-app-connect-api` (`/connect/ms-teams-app/tenant-config`) gates Step 5 and has **no known unlock path** | `GET`/`PUT`/`DELETE` all return `403 FUNCTIONALITY_NOT_ENABLED [MsTeamsAppApiFamily]`, even after `service-cloud-itsm-teams-integration` is enabled and `MSTeamsSetupClientCredentialsEC` is fully configured. **Verified this is the same blocker as Step 5's "Unable to fetch tenant ID" error** — `post-teams-extension`/`patch-teams-extension-update` internally depend on this tenant-config lookup. Checked and ruled out: (a) no Go feature-enablement API name unlocks it — tried `ms-teams-app`, `ms-teams-app-integration`, `microsoft-teams-app-integration`, `teams-app-connect-api`, `msteams-app-api`, `service-cloud-ms-teams-app-api`, `MsTeamsAppApiFamily` itself, all `400 NOT_FOUND "Could not find the requested feature"`; (b) no `PermissionSetLicense` among all 112 in the org grants it — only `TeamsForEmployeePsl`/`TeamsForITSrvcsPsl` relate to Teams, and neither gates this family. This appears to be a hard org/edition-level license gate with no self-service unlock via headless-360 — if a user hits this, Step 5 cannot be completed in this org; do not keep retrying enablement guesses. |
22
+ | A `MSTeamsSetupAutomationAccess` ("Automate Microsoft Teams Setup") permission set also auto-provisions | Was unassigned in this session — assign it to the Setup admin driving this flow if further automation steps need it. (The IT Desk/IT Service checklist permission sets — `TeamsForITSrvcsUser`, `TeamsForEmployeeUser`, `MicrosoftGraphAccess` — are documented in the child skills.) |
23
+ | Version prefix required | headless-360 `dispatch`/`dispatch_readonly` do not resolve API versions — always pass the full `/services/data/vXX.0/...` prefix. |