@wildo-ai/saas-technical-doc 1.1.4 → 1.1.6

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 (205) hide show
  1. package/dist/esm/build/csp-emit.d.ts.map +1 -1
  2. package/dist/esm/build/load-materialized-frontend-providers.d.ts.map +1 -1
  3. package/dist/esm/companion/application-documentation/application-administration-documentation.d.ts.map +1 -1
  4. package/dist/esm/companion/application-documentation/application-administration-documentation.js.map +1 -1
  5. package/dist/esm/companion/application-documentation/application-authentication-documentation.d.ts.map +1 -1
  6. package/dist/esm/companion/application-documentation/application-connection-documentation.d.ts +37 -0
  7. package/dist/esm/companion/application-documentation/application-connection-documentation.d.ts.map +1 -1
  8. package/dist/esm/companion/application-documentation/application-connection-documentation.js +46 -5
  9. package/dist/esm/companion/application-documentation/application-connection-documentation.js.map +1 -1
  10. package/dist/esm/companion/application-documentation/application-documentation-chapters.d.ts +101 -0
  11. package/dist/esm/companion/application-documentation/application-documentation-chapters.d.ts.map +1 -0
  12. package/dist/esm/companion/application-documentation/application-documentation-chapters.js +205 -0
  13. package/dist/esm/companion/application-documentation/application-documentation-chapters.js.map +1 -0
  14. package/dist/esm/companion/application-documentation/application-domain-documentation.d.ts.map +1 -1
  15. package/dist/esm/companion/application-documentation/application-domain-documentation.js.map +1 -1
  16. package/dist/esm/companion/application-documentation/application-integration-documentation.d.ts.map +1 -1
  17. package/dist/esm/companion/application-documentation/application-integration-documentation.js.map +1 -1
  18. package/dist/esm/companion/application-documentation/application-organization-role-documentation.d.ts.map +1 -1
  19. package/dist/esm/companion/application-documentation/application-organization-role-documentation.js.map +1 -1
  20. package/dist/esm/companion/application-documentation/application-organization-unit-resource-documentation.d.ts.map +1 -1
  21. package/dist/esm/companion/application-documentation/application-organization-unit-resource-documentation.js +3 -0
  22. package/dist/esm/companion/application-documentation/application-organization-unit-resource-documentation.js.map +1 -1
  23. package/dist/esm/companion/application-documentation/docs-api-origin-substitution.d.ts +34 -0
  24. package/dist/esm/companion/application-documentation/docs-api-origin-substitution.d.ts.map +1 -0
  25. package/dist/esm/companion/application-documentation/docs-api-origin-substitution.js +45 -0
  26. package/dist/esm/companion/application-documentation/docs-api-origin-substitution.js.map +1 -0
  27. package/dist/esm/companion/application-documentation/technical-documentation-engine-content-bundle.d.ts +24 -10
  28. package/dist/esm/companion/application-documentation/technical-documentation-engine-content-bundle.d.ts.map +1 -1
  29. package/dist/esm/companion/application-documentation/technical-documentation-engine-content-bundle.js +25 -15
  30. package/dist/esm/companion/application-documentation/technical-documentation-engine-content-bundle.js.map +1 -1
  31. package/dist/esm/companion/application-documentation/technical-documentation-operational-evidence.d.ts.map +1 -1
  32. package/dist/esm/companion/application-documentation/technical-documentation-private-derivation.d.ts +11 -3
  33. package/dist/esm/companion/application-documentation/technical-documentation-private-derivation.d.ts.map +1 -1
  34. package/dist/esm/companion/application-documentation/technical-documentation-private-derivation.js +9 -2
  35. package/dist/esm/companion/application-documentation/technical-documentation-private-derivation.js.map +1 -1
  36. package/dist/esm/companion/application-documentation/technical-documentation-publication-policy.d.ts.map +1 -1
  37. package/dist/esm/companion/application-documentation/technical-documentation-publication-policy.js +10 -4
  38. package/dist/esm/companion/application-documentation/technical-documentation-publication-policy.js.map +1 -1
  39. package/dist/esm/companion/content/application-consumer-documentation-content-loader.d.ts.map +1 -1
  40. package/dist/esm/companion/index.d.ts +2 -0
  41. package/dist/esm/companion/index.d.ts.map +1 -1
  42. package/dist/esm/companion/index.js +2 -0
  43. package/dist/esm/companion/index.js.map +1 -1
  44. package/dist/esm/companion/manual-controller-route-projection.d.ts.map +1 -1
  45. package/dist/esm/companion/manual-controller-route-projection.js.map +1 -1
  46. package/dist/esm/companion/openapi-example-derivation.d.ts +53 -0
  47. package/dist/esm/companion/openapi-example-derivation.d.ts.map +1 -0
  48. package/dist/esm/companion/openapi-example-derivation.js +229 -0
  49. package/dist/esm/companion/openapi-example-derivation.js.map +1 -0
  50. package/dist/esm/companion/openapi-generator.d.ts +8 -4
  51. package/dist/esm/companion/openapi-generator.d.ts.map +1 -1
  52. package/dist/esm/companion/openapi-generator.js +323 -33
  53. package/dist/esm/companion/openapi-generator.js.map +1 -1
  54. package/dist/esm/companion/operation-projection.schemas.d.ts +57 -1
  55. package/dist/esm/companion/operation-projection.schemas.d.ts.map +1 -1
  56. package/dist/esm/companion/operation-projection.schemas.js +29 -0
  57. package/dist/esm/companion/operation-projection.schemas.js.map +1 -1
  58. package/dist/esm/companion/publish-result.types.d.ts.map +1 -1
  59. package/dist/esm/companion/publish-result.types.js.map +1 -1
  60. package/dist/esm/companion/rendering/technical-documentation-authorized-bundle-reader.d.ts.map +1 -1
  61. package/dist/esm/companion/rendering/technical-documentation-docusaurus-renderer.d.ts.map +1 -1
  62. package/dist/esm/companion/rendering/technical-documentation-docusaurus-renderer.js +8 -0
  63. package/dist/esm/companion/rendering/technical-documentation-docusaurus-renderer.js.map +1 -1
  64. package/dist/esm/companion/rendering/technical-documentation-managed-tree-validator.d.ts.map +1 -1
  65. package/dist/esm/companion/rendering/technical-documentation-managed-tree-validator.js +20 -0
  66. package/dist/esm/companion/rendering/technical-documentation-managed-tree-validator.js.map +1 -1
  67. package/dist/esm/companion/rendering/technical-documentation-openapi-renderer.d.ts +2 -0
  68. package/dist/esm/companion/rendering/technical-documentation-openapi-renderer.d.ts.map +1 -1
  69. package/dist/esm/companion/rendering/technical-documentation-openapi-renderer.js +48 -31
  70. package/dist/esm/companion/rendering/technical-documentation-openapi-renderer.js.map +1 -1
  71. package/dist/esm/companion/rendering/technical-documentation-render-model.d.ts.map +1 -1
  72. package/dist/esm/companion/rendering/technical-documentation-render-model.js +26 -10
  73. package/dist/esm/companion/rendering/technical-documentation-render-model.js.map +1 -1
  74. package/dist/esm/companion/rendering/technical-documentation-search-index-renderer.d.ts.map +1 -1
  75. package/dist/esm/companion/rendering/technical-documentation-search-index-renderer.js.map +1 -1
  76. package/dist/esm/companion/spec-to-operation-doc.d.ts +52 -10
  77. package/dist/esm/companion/spec-to-operation-doc.d.ts.map +1 -1
  78. package/dist/esm/companion/spec-to-operation-doc.js +125 -7
  79. package/dist/esm/companion/spec-to-operation-doc.js.map +1 -1
  80. package/dist/esm/companion/technical-documentation-asset-path.d.ts.map +1 -1
  81. package/dist/esm/companion/technical-documentation-capture-execution-port.d.ts.map +1 -1
  82. package/dist/esm/companion/technical-documentation-capture-execution-port.js.map +1 -1
  83. package/dist/esm/companion/technical-documentation-diagram-definitions.d.ts.map +1 -1
  84. package/dist/esm/companion/technical-documentation-diagram-definitions.js.map +1 -1
  85. package/dist/esm/companion/technical-documentation-diagram-materializer.d.ts.map +1 -1
  86. package/dist/esm/companion/technical-documentation-diagram-materializer.js.map +1 -1
  87. package/dist/esm/companion/technical-documentation-placeholder-materializer.d.ts.map +1 -1
  88. package/dist/esm/companion/zod-to-openapi.d.ts.map +1 -1
  89. package/dist/esm/companion-exports.d.ts.map +1 -1
  90. package/dist/esm/config/define-tech-doc-config.d.ts.map +1 -1
  91. package/dist/esm/config/index.d.ts.map +1 -1
  92. package/dist/esm/config/wildo-tech-doc-config.schemas.d.ts.map +1 -1
  93. package/dist/esm/config/wildo-tech-doc-config.schemas.js.map +1 -1
  94. package/dist/esm/content/application-consumer-documentation-content-manifest.schemas.d.ts.map +1 -1
  95. package/dist/esm/content/application-consumer-documentation-content.techdoc.d.ts +27 -24
  96. package/dist/esm/content/application-consumer-documentation-content.techdoc.d.ts.map +1 -1
  97. package/dist/esm/content/application-consumer-documentation-content.techdoc.js +205 -82
  98. package/dist/esm/content/application-consumer-documentation-content.techdoc.js.map +1 -1
  99. package/dist/esm/content.exports.d.ts.map +1 -1
  100. package/dist/esm/index.d.ts.map +1 -1
  101. package/dist/esm/openapi/api-reference-link-index.d.ts +3 -0
  102. package/dist/esm/openapi/api-reference-link-index.d.ts.map +1 -1
  103. package/dist/esm/openapi/api-reference-link-index.js +26 -15
  104. package/dist/esm/openapi/api-reference-link-index.js.map +1 -1
  105. package/dist/esm/openapi/api-reference-pages.d.ts +55 -0
  106. package/dist/esm/openapi/api-reference-pages.d.ts.map +1 -0
  107. package/dist/esm/openapi/api-reference-pages.js +229 -0
  108. package/dist/esm/openapi/api-reference-pages.js.map +1 -0
  109. package/dist/esm/openapi/api-reference-search.d.ts +53 -0
  110. package/dist/esm/openapi/api-reference-search.d.ts.map +1 -0
  111. package/dist/esm/openapi/api-reference-search.js +100 -0
  112. package/dist/esm/openapi/api-reference-search.js.map +1 -0
  113. package/dist/esm/openapi/api-reference-targets.d.ts +11 -0
  114. package/dist/esm/openapi/api-reference-targets.d.ts.map +1 -1
  115. package/dist/esm/openapi/api-reference-targets.js +8 -0
  116. package/dist/esm/openapi/api-reference-targets.js.map +1 -1
  117. package/dist/esm/openapi/index.d.ts +2 -0
  118. package/dist/esm/openapi/index.d.ts.map +1 -1
  119. package/dist/esm/openapi/index.js +2 -0
  120. package/dist/esm/openapi/index.js.map +1 -1
  121. package/dist/esm/openapi/openapi-generation-output.schemas.d.ts.map +1 -1
  122. package/dist/esm/openapi-reference-model.exports.d.ts +2 -0
  123. package/dist/esm/openapi-reference-model.exports.d.ts.map +1 -1
  124. package/dist/esm/openapi-reference-model.exports.js +2 -0
  125. package/dist/esm/openapi-reference-model.exports.js.map +1 -1
  126. package/dist/esm/runtime/AuthExchangePage.d.ts +45 -4
  127. package/dist/esm/runtime/AuthExchangePage.d.ts.map +1 -1
  128. package/dist/esm/runtime/AuthExchangePage.js +45 -12
  129. package/dist/esm/runtime/AuthExchangePage.js.map +1 -1
  130. package/dist/esm/runtime/DocsAuthContext.d.ts +2 -2
  131. package/dist/esm/runtime/DocsAuthContext.d.ts.map +1 -1
  132. package/dist/esm/runtime/DocsAuthContext.js +8 -4
  133. package/dist/esm/runtime/DocsAuthContext.js.map +1 -1
  134. package/dist/esm/runtime/DocsFrontendProviders.d.ts +30 -0
  135. package/dist/esm/runtime/DocsFrontendProviders.d.ts.map +1 -0
  136. package/dist/esm/runtime/DocsFrontendProviders.js +39 -0
  137. package/dist/esm/runtime/DocsFrontendProviders.js.map +1 -0
  138. package/dist/esm/runtime/DocsProviderComponent.d.ts +41 -0
  139. package/dist/esm/runtime/DocsProviderComponent.d.ts.map +1 -0
  140. package/dist/esm/runtime/DocsProviderComponent.js +17 -0
  141. package/dist/esm/runtime/DocsProviderComponent.js.map +1 -0
  142. package/dist/esm/runtime/decode-jwt-claims.d.ts.map +1 -1
  143. package/dist/esm/runtime/docs-auth-client.d.ts.map +1 -1
  144. package/dist/esm/runtime/docs-auth-session.schemas.d.ts.map +1 -1
  145. package/dist/esm/runtime/documentation-site-translator.d.ts +53 -0
  146. package/dist/esm/runtime/documentation-site-translator.d.ts.map +1 -0
  147. package/dist/esm/runtime/documentation-site-translator.js +51 -0
  148. package/dist/esm/runtime/documentation-site-translator.js.map +1 -0
  149. package/dist/esm/runtime/frontend-provider-registry.techdoc.d.ts +1 -2
  150. package/dist/esm/runtime/frontend-provider-registry.techdoc.d.ts.map +1 -1
  151. package/dist/esm/runtime/frontend-provider-registry.techdoc.js.map +1 -1
  152. package/dist/esm/runtime/index.d.ts +8 -0
  153. package/dist/esm/runtime/index.d.ts.map +1 -1
  154. package/dist/esm/runtime/index.js +8 -0
  155. package/dist/esm/runtime/index.js.map +1 -1
  156. package/dist/esm/runtime/openapi-reference-conservation.d.ts.map +1 -1
  157. package/dist/esm/runtime/openapi-reference-model.d.ts +30 -0
  158. package/dist/esm/runtime/openapi-reference-model.d.ts.map +1 -1
  159. package/dist/esm/runtime/openapi-reference-model.js +85 -11
  160. package/dist/esm/runtime/openapi-reference-model.js.map +1 -1
  161. package/dist/esm/runtime/openapi-reference-navigation.d.ts +50 -0
  162. package/dist/esm/runtime/openapi-reference-navigation.d.ts.map +1 -0
  163. package/dist/esm/runtime/openapi-reference-navigation.js +46 -0
  164. package/dist/esm/runtime/openapi-reference-navigation.js.map +1 -0
  165. package/dist/esm/runtime/openapi-reference-samples.d.ts +40 -0
  166. package/dist/esm/runtime/openapi-reference-samples.d.ts.map +1 -0
  167. package/dist/esm/runtime/openapi-reference-samples.js +169 -0
  168. package/dist/esm/runtime/openapi-reference-samples.js.map +1 -0
  169. package/dist/esm/runtime/openapi-reference-styles.d.ts +28 -0
  170. package/dist/esm/runtime/openapi-reference-styles.d.ts.map +1 -0
  171. package/dist/esm/runtime/openapi-reference-styles.js +292 -0
  172. package/dist/esm/runtime/openapi-reference-styles.js.map +1 -0
  173. package/dist/esm/runtime/openapi-reference-view.d.ts +40 -5
  174. package/dist/esm/runtime/openapi-reference-view.d.ts.map +1 -1
  175. package/dist/esm/runtime/openapi-reference-view.js +828 -82
  176. package/dist/esm/runtime/openapi-reference-view.js.map +1 -1
  177. package/dist/esm/runtime/openapi-reference-words-context.d.ts +12 -0
  178. package/dist/esm/runtime/openapi-reference-words-context.d.ts.map +1 -0
  179. package/dist/esm/runtime/openapi-reference-words-context.js +30 -0
  180. package/dist/esm/runtime/openapi-reference-words-context.js.map +1 -0
  181. package/dist/esm/runtime/openapi-reference-words.d.ts +205 -0
  182. package/dist/esm/runtime/openapi-reference-words.d.ts.map +1 -0
  183. package/dist/esm/runtime/openapi-reference-words.js +162 -0
  184. package/dist/esm/runtime/openapi-reference-words.js.map +1 -0
  185. package/dist/esm/runtime/provider-component-registry.techdoc.d.ts +31 -0
  186. package/dist/esm/runtime/provider-component-registry.techdoc.d.ts.map +1 -0
  187. package/dist/esm/runtime/provider-component-registry.techdoc.js +35 -0
  188. package/dist/esm/runtime/provider-component-registry.techdoc.js.map +1 -0
  189. package/dist/esm/runtime/use-docs-auth-session.d.ts.map +1 -1
  190. package/dist/esm/runtime/use-docs-frontend-provider-registry.d.ts +1 -0
  191. package/dist/esm/runtime/use-docs-frontend-provider-registry.d.ts.map +1 -1
  192. package/dist/esm/runtime/use-docs-frontend-provider-registry.js +10 -2
  193. package/dist/esm/runtime/use-docs-frontend-provider-registry.js.map +1 -1
  194. package/dist/esm/runtime/use-docs-provider-component.d.ts +29 -0
  195. package/dist/esm/runtime/use-docs-provider-component.d.ts.map +1 -0
  196. package/dist/esm/runtime/use-docs-provider-component.js +42 -0
  197. package/dist/esm/runtime/use-docs-provider-component.js.map +1 -0
  198. package/dist/esm/runtime/use-docs-provider-scripts.d.ts +37 -0
  199. package/dist/esm/runtime/use-docs-provider-scripts.d.ts.map +1 -0
  200. package/dist/esm/runtime/use-docs-provider-scripts.js +47 -0
  201. package/dist/esm/runtime/use-docs-provider-scripts.js.map +1 -0
  202. package/dist/esm/runtime/use-docs-provider-sdks.d.ts.map +1 -1
  203. package/dist/esm/runtime/use-docs-provider-sdks.js.map +1 -1
  204. package/dist/tsconfig.build.tsbuildinfo +1 -1
  205. package/package.json +8 -24
@@ -20,9 +20,12 @@
20
20
  * fact in it is projected from sources the application already accepted — its own resource
21
21
  * registry, its declared API-reference categories, and each specification's purpose and lifecycle.
22
22
  *
23
- * What remains genuinely deferred is a page PER resource. Those need a variable unit set, and the
24
- * renderer's route table is deliberately fixed (see `pathForUnit`), so an application-owned unit
25
- * still fails closed rather than acquiring an implicit route.
23
+ * A page PER resource followed, as a generated tier with its own reserved namespace (see
24
+ * `pathForUnit`). And a cross-resource BUSINESS use case — the journey this module can never write,
25
+ * because it belongs to one application — is authored by that application as a documentation
26
+ * chapter its plan declares (#874, `application-documentation-chapters.ts`), again in a reserved
27
+ * namespace. A unit whose ref an application chose freely still fails closed rather than acquiring
28
+ * an implicit route.
26
29
  */
27
30
  export declare const APPLICATION_CONSUMER_DOCUMENTATION_AUTHORED_CONTENT_V1: readonly [{
28
31
  readonly managedPath: "get-started.md";
@@ -68,12 +71,12 @@ export declare const APPLICATION_CONSUMER_DOCUMENTATION_AUTHORED_CONTENT_V1: rea
68
71
  readonly managedPath: "access-and-identity/sso-configure.md";
69
72
  readonly unitRef: "technical-documentation:unit/sso-configure";
70
73
  readonly sourceRefs: readonly ["saas-technical-doc:engine-content/sso-configure", "source:consumer-fact:access-single-sign-on"];
71
- readonly markdown: "# Configure a single sign-on connection\n\nCreate one connection for one organization and environment. This task is for an\norganization administrator working with the identity administrator who controls\nthe provider tenant.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Have an independent administrator recovery method, provider administration access, the current application's connection values and a controlled test identity | The application and provider identify each other correctly and a test response validates for the intended organization |\n\n~~~mermaid\nflowchart TD\n accTitle: Configure one single sign-on trust boundary\n accDescr: The application and identity-provider owners choose one protocol, exchange environment-specific identities and destinations, configure validation and identity mapping, test while the connection is not default, and enable it only after identity, organization and access checks pass.\n owners[\"Confirm owners and independent recovery\"] --> protocol[\"Choose OpenID Connect or SAML\"]\n protocol --> trust[\"Exchange identities, destinations and verification material\"]\n trust --> mapping[\"Define person, domain and role mapping\"]\n mapping --> controlled[\"Test one controlled identity\"]\n controlled --> access[\"Verify identity, organization, allowed action and refusal\"]\n access --> enable[\"Enable without making default\"]\n~~~\n\nKeep the connection isolated to one organization and environment. Production\nand non-production values may have similar labels but remain different trust\nboundaries.\n\n## Choose the protocol and connection controls\n\n{{CONSUMER_FACT:source:consumer-fact:access-single-sign-on#markdown}}\n\nGive the connection a display name that identifies the organization and\nenvironment. Keep it disabled while exchanging trust configuration when the\nadministration surface permits that sequence. Do not mark it as default yet.\n\n{{CONSUMER_FACT:source:consumer-fact:access-single-sign-on#connectionConfigurationMarkdown}}\n\n> **Current limitation:** keep `bypassAppMFA` off. The configuration field is\n> present, but the current authentication runtime does not use it to decide\n> whether the application requests another factor. Prove the actual sign-in\n> journey with a controlled account; do not use this field as audit evidence.\n\n> **SSO role mapping is an access grant.** Test every mapped value, keep the\n> fallback role non-administrative, and verify an expected refusal. A provider\n> group name should never become broad application authority merely because it\n> was previously used for a different system.\n\n## Exchange the trust configuration\n\nDepending on the selected protocol, the two administrators exchange the\nnon-secret identifiers and destinations needed to identify the application and\nprovider, plus the protected verification or client material required by that\nprotocol. Use only values displayed for the current environment.\n\nCheck these meanings before saving:\n\n- **Provider identity** names the provider tenant this connection trusts.\n- **Application identity or audience** tells the provider which application the\n response is intended for.\n- **Sign-in and return destinations** must belong to the matching environments.\n- **Identity mapping** must use a stable identity value rather than a display\n name that can change or collide.\n- **Verification settings** decide which signed responses the application will\n trust and how timing is evaluated.\n\n~~~mermaid\nflowchart LR\n accTitle: Map provider values to one application connection\n accDescr: The application publishes its callback or assertion-consumer destination and identity. The provider publishes its issuer or entity identity, endpoints and verification material. Both owners configure stable identity claims, and the application alone maps those claims to membership and least-privilege roles.\n app[\"Application environment\"] -->|\"Callback or ACS destination; application identity\"| provider[\"Identity provider tenant\"]\n provider -->|\"Issuer or entity ID; endpoints; signing material\"| app\n provider --> claims[\"Stable identity and optional role/group claims\"]\n claims --> mapping[\"Application claim and access mapping\"]\n mapping --> membership[\"Person + organization membership + roles\"]\n~~~\n\nThe arrows show two separate exchanges. Protocol trust lets the application\naccept a response from the provider. Claim and access mapping decides which\nperson and organization relationship that response may establish. Review both;\na valid signature does not make an unsafe group-to-admin mapping acceptable.\n\n### For an OpenID Connect connection\n\n{{CONSUMER_FACT:source:consumer-fact:access-single-sign-on#oidcConfigurationMarkdown}}\n\nPrefer the provider's maintained discovery information when the administration\nsurface supports it. Confirm the issuer and discovered authorization, token and\nsigning-key locations all belong to the same provider environment. Register the\nexact application return destination at the provider. Protect the client secret\nas write-only credential material, retain its renewal owner, and keep issuer and\naudience validation enabled. Use the strong proof method offered for the\nauthorization-code journey rather than weakening it to accommodate an old\nclient.\n\nChoose one endpoint mode deliberately:\n\n1. **Discovery** — supply the provider issuer or discovery URL. The sign-in\n runtime retrieves the current metadata and uses its issuer, authorization,\n token, user-info, signing-key and logout locations when published.\n2. **Provider template** — choose a maintained provider contract and supply its\n required tenant substitutions. Verify every resolved URL before enabling.\n3. **Manual** — supply the authorization and token endpoints, plus issuer,\n user-info and signing-key locations where required. Use this only when the\n provider cannot publish usable metadata.\n\n> The administrative **Discover endpoints** and **Test connection** operations\n> currently return `supported: false` for OIDC and perform no provider\n> handshake. This does not disable discovery-mode sign-in; it means the admin\n> diagnostic action cannot prove that connection. Use a controlled end-to-end\n> sign-in and provider logs as the positive test.\n\n### For a SAML connection\n\n{{CONSUMER_FACT:source:consumer-fact:access-single-sign-on#samlConfigurationMarkdown}}\n\nConfirm the provider entity identifier, application audience, sign-in\ndestination and assertion return destination as a single environment-specific\nset. Load the current provider signing certificate through the protected\nadministration surface and plan renewal before it expires. Keep signed-assertion\nvalidation enabled. Choose a stable subject/NameID and explicit attribute\nmapping; do not use a mutable display name as the person's identity.\n\nThe administrative **Discover endpoints** operation can retrieve SAML metadata\nand return the provider entity ID, sign-in/logout URLs, certificates and NameID\nformat for review. It does **not** save those values. After saving the\nconnection, **Test connection** checks the configured entity ID, endpoint\nreachability, certificate validity and generated service-provider metadata. A\npass is useful preflight evidence, but only a real application-started sign-in\nproves the browser, provider policy, response validation and identity mapping.\n\n{{CONSUMER_FACT:source:consumer-fact:access-single-sign-on#diagnosticsMarkdown}}\n\n## Configure a common identity provider\n\nThe provider changes the names and screens, not the application trust model.\nAlways copy the application values from the **same environment** you are\nconfiguring; the examples below deliberately contain no reusable callback URL,\nentity ID, client ID or secret.\n\n| Application meaning | Microsoft Entra ID | Okta | Google Workspace / Cloud Identity |\n| --- | --- | --- | --- |\n| OIDC application identity | App registration **Application (client) ID** | OIDC app **Client ID** | OAuth client **Client ID** |\n| OIDC return destination | App registration **Redirect URI** | **Sign-in redirect URI** | OAuth client **Authorized redirect URI** |\n| OIDC provider identity | Tenant-specific issuer/discovery document | Okta authorization-server issuer | Google issuer/discovery document |\n| SAML application identity | **Identifier (Entity ID)** | **Audience URI (SP Entity ID)** | **Entity ID** |\n| SAML return destination | **Reply URL (ACS URL)** | **Single sign-on URL** | **ACS URL** |\n| SAML provider identity | Microsoft Entra Identifier | Identity Provider Issuer | Google Entity ID |\n| SAML verification material | SAML signing certificate / federation metadata | Signing certificate / IdP metadata | Certificate / IdP metadata |\n\n### Microsoft Entra ID\n\nFor OIDC, create or select the application registration, register the exact web\nredirect URI supplied by this application environment, use the tenant-specific\nissuer, and create a client credential with a named owner and expiry. Keep the\nprovider assignment limited to the pilot population. Microsoft distinguishes\nthe app registration (the application definition) from its enterprise\napplication/service-principal instance; record both identities during support.\n\nFor SAML, create or select the enterprise application, configure its Identifier\nand Reply URL from this environment, then load the Microsoft Entra Identifier,\nlogin URL and current signing certificate into the SAML connection. Review the\nprovider's claims before authoring role or group mappings.\n\n- [Microsoft Entra OIDC application setup](https://learn.microsoft.com/en-us/entra/identity/enterprise-apps/add-application-portal-setup-oidc-sso)\n- [Microsoft Entra SAML application setup](https://learn.microsoft.com/en-us/entra/identity/enterprise-apps/add-application-portal-setup-sso)\n- [Microsoft Entra redirect URI rules](https://learn.microsoft.com/en-us/entra/identity-platform/how-to-add-redirect-uri)\n\n### Okta\n\nCreate a private OIDC or SAML app integration and initially assign only the\npilot people or groups. For OIDC, choose a **Web Application**, register the\nexact sign-in redirect URI, retain authorization code, and keep PKCE S256. Copy\nthe client ID, client secret and exact issuer used by that authorization server.\nDo not enable a wildcard redirect merely to avoid maintaining environment URLs.\n\nFor SAML, enter this environment's ACS URL and service-provider entity ID, then\nload Okta's Identity Provider issuer, sign-on URL and signing certificate into\nthe application connection. Map claims and groups explicitly; an Okta\nassignment decides who may reach the provider integration, while the\napplication membership and roles still decide application access.\n\n- [Okta OIDC app integration](https://help.okta.com/en-us/content/topics/apps/apps_app_integration_wizard_oidc.htm)\n- [Okta SAML app integration](https://help.okta.com/en-us/content/topics/apps/apps_app_integration_wizard_saml.htm)\n- [Okta SAML field reference](https://help.okta.com/en-us/content/topics/apps/aiw-saml-reference.htm)\n\n### Google Workspace or Cloud Identity\n\nFor OIDC, configure a web OAuth client with the exact authorized redirect URI\nand use Google's published issuer/discovery information. The provider can\nauthenticate Google accounts beyond one Workspace domain, so the application\nconnection's explicit allowed-domain list and the organization's membership\npolicy remain important boundaries.\n\nFor SAML, add a custom SAML app, copy Google's IdP entity ID, SSO URL and\ncertificate into this connection, then enter the application's ACS URL and\nentity ID in Google. Start with the service disabled or assigned to a pilot\norganizational unit/group, depending on the provider controls available to the\norganization.\n\n- [Google OpenID Connect guide](https://developers.google.com/identity/openid-connect/openid-connect)\n- [Google custom SAML application setup](https://support.google.com/a/answer/6087519)\n\n> **Do not paste credentials, private keys or complete certificates into a\n> ticket or screenshot.** Use the protected administration surfaces to exchange\n> sensitive material and share only non-secret identifiers for diagnosis.\n\n## Verify before enabling broadly\n\nEnable the connection for a controlled test, but do not make it default. Start\nfrom the application's sign-in journey and verify:\n\n1. the intended provider and environment receive the request;\n2. the provider accepts the controlled person under its expected policy;\n3. the application accepts the returned issuer/entity, audience, destination,\n signature and time checks;\n4. the stable subject maps to the intended application person;\n5. the person enters the intended organization with the expected role;\n6. one expected action succeeds and one action outside that authority is\n refused; and\n7. the independent recovery administrator still signs in.\n\nRecord non-secret identifiers, time, outcome and correlation evidence. Continue with\n[Roll out SSO and keep a recovery path](/access-and-identity/sso-rollout-and-recovery)\nbefore making it the default. Never include a password, client secret, private\nkey, complete assertion, authorization code or session cookie in the evidence.";
74
+ readonly markdown: "# Configure a single sign-on connection\n\nCreate one connection for one organization and environment. This task is for an\norganization administrator working with the identity administrator who controls\nthe provider tenant.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Have an independent administrator recovery method, provider administration access, the current application's connection values and a controlled test identity | The application and provider identify each other correctly and a test response validates for the intended organization |\n\n~~~mermaid\nflowchart TD\n accTitle: Configure one single sign-on trust boundary\n accDescr: The application and identity-provider owners choose one protocol, exchange environment-specific identities and destinations, configure validation and identity mapping, test while the connection is not default, and enable it only after identity, organization and access checks pass.\n owners[\"Confirm owners and independent recovery\"] --> protocol[\"Choose OpenID Connect or SAML\"]\n protocol --> trust[\"Exchange identities, destinations and verification material\"]\n trust --> mapping[\"Define person, domain and role mapping\"]\n mapping --> controlled[\"Test one controlled identity\"]\n controlled --> access[\"Verify identity, organization, allowed action and refusal\"]\n access --> enable[\"Enable without making default\"]\n~~~\n\nKeep the connection isolated to one organization and environment. Production\nand non-production values may have similar labels but remain different trust\nboundaries.\n\n## Choose the protocol and connection controls\n\n{{CONSUMER_FACT:source:consumer-fact:access-single-sign-on#markdown}}\n\nGive the connection a display name that identifies the organization and\nenvironment. Keep it disabled while exchanging trust configuration when the\nadministration surface permits that sequence. Do not mark it as default yet.\n\n{{CONSUMER_FACT:source:consumer-fact:access-single-sign-on#connectionConfigurationMarkdown}}\n\n> **SSO role mapping is an access grant.** Test every mapped value, keep the\n> fallback role non-administrative, and verify an expected refusal. A provider\n> group name should never become broad application authority merely because it\n> was previously used for a different system.\n\n## Exchange the trust configuration\n\nDepending on the selected protocol, the two administrators exchange the\nnon-secret identifiers and destinations needed to identify the application and\nprovider, plus the protected verification or client material required by that\nprotocol. Use only values displayed for the current environment.\n\nCheck these meanings before saving:\n\n- **Provider identity** names the provider tenant this connection trusts.\n- **Application identity or audience** tells the provider which application the\n response is intended for.\n- **Sign-in and return destinations** must belong to the matching environments.\n- **Identity mapping** must use a stable identity value rather than a display\n name that can change or collide.\n- **Verification settings** decide which signed responses the application will\n trust and how timing is evaluated.\n\n~~~mermaid\nflowchart LR\n accTitle: Map provider values to one application connection\n accDescr: The application publishes its callback or assertion-consumer destination and identity. The provider publishes its issuer or entity identity, endpoints and verification material. Both owners configure stable identity claims, and the application alone maps those claims to membership and least-privilege roles.\n app[\"Application environment\"] -->|\"Callback or ACS destination; application identity\"| provider[\"Identity provider tenant\"]\n provider -->|\"Issuer or entity ID; endpoints; signing material\"| app\n provider --> claims[\"Stable identity and optional role/group claims\"]\n claims --> mapping[\"Application claim and access mapping\"]\n mapping --> membership[\"Person + organization membership + roles\"]\n~~~\n\nThe arrows show two separate exchanges. Protocol trust lets the application\naccept a response from the provider. Claim and access mapping decides which\nperson and organization relationship that response may establish. Review both;\na valid signature does not make an unsafe group-to-admin mapping acceptable.\n\n### For an OpenID Connect connection\n\n{{CONSUMER_FACT:source:consumer-fact:access-single-sign-on#oidcConfigurationMarkdown}}\n\nPrefer the provider's maintained discovery information when the administration\nsurface supports it. Confirm the issuer and discovered authorization, token and\nsigning-key locations all belong to the same provider environment. Register the\nexact application return destination at the provider. Protect the client secret\nas write-only credential material, retain its renewal owner, and keep issuer and\naudience validation enabled. Use the strong proof method offered for the\nauthorization-code journey rather than weakening it to accommodate an old\nclient.\n\nChoose one endpoint mode deliberately:\n\n1. **Discovery** — supply the provider issuer or discovery URL. The sign-in\n runtime retrieves the current metadata and uses its issuer, authorization,\n token, user-info, signing-key and logout locations when published.\n2. **Provider template** — choose a maintained provider contract and supply its\n required tenant substitutions. Verify every resolved URL before enabling.\n3. **Manual** — supply the authorization and token endpoints, plus issuer,\n user-info and signing-key locations where required. Use this only when the\n provider cannot publish usable metadata.\n\n> The administrative **Discover endpoints** and **Test connection** operations\n> currently return `supported: false` for OIDC and perform no provider\n> handshake. This does not disable discovery-mode sign-in; it means the admin\n> diagnostic action cannot prove that connection. Use a controlled end-to-end\n> sign-in and provider logs as the positive test.\n\n### For a SAML connection\n\n{{CONSUMER_FACT:source:consumer-fact:access-single-sign-on#samlConfigurationMarkdown}}\n\nConfirm the provider entity identifier, application audience, sign-in\ndestination and assertion return destination as a single environment-specific\nset. Load the current provider signing certificate through the protected\nadministration surface and plan renewal before it expires. Keep signed-assertion\nvalidation enabled. Choose a stable subject/NameID and explicit attribute\nmapping; do not use a mutable display name as the person's identity.\n\nThe administrative **Discover endpoints** operation can retrieve SAML metadata\nand return the provider entity ID, sign-in/logout URLs, certificates and NameID\nformat for review. It does **not** save those values. After saving the\nconnection, **Test connection** checks the configured entity ID, endpoint\nreachability, certificate validity and generated service-provider metadata. A\npass is useful preflight evidence, but only a real application-started sign-in\nproves the browser, provider policy, response validation and identity mapping.\n\n{{CONSUMER_FACT:source:consumer-fact:access-single-sign-on#diagnosticsMarkdown}}\n\n## Configure a common identity provider\n\nThe provider changes the names and screens, not the application trust model.\nAlways copy the application values from the **same environment** you are\nconfiguring; the examples below deliberately contain no reusable callback URL,\nentity ID, client ID or secret.\n\n| Application meaning | Microsoft Entra ID | Okta | Google Workspace / Cloud Identity |\n| --- | --- | --- | --- |\n| OIDC application identity | App registration **Application (client) ID** | OIDC app **Client ID** | OAuth client **Client ID** |\n| OIDC return destination | App registration **Redirect URI** | **Sign-in redirect URI** | OAuth client **Authorized redirect URI** |\n| OIDC provider identity | Tenant-specific issuer/discovery document | Okta authorization-server issuer | Google issuer/discovery document |\n| SAML application identity | **Identifier (Entity ID)** | **Audience URI (SP Entity ID)** | **Entity ID** |\n| SAML return destination | **Reply URL (ACS URL)** | **Single sign-on URL** | **ACS URL** |\n| SAML provider identity | Microsoft Entra Identifier | Identity Provider Issuer | Google Entity ID |\n| SAML verification material | SAML signing certificate / federation metadata | Signing certificate / IdP metadata | Certificate / IdP metadata |\n\n### Microsoft Entra ID\n\nFor OIDC, create or select the application registration, register the exact web\nredirect URI supplied by this application environment, use the tenant-specific\nissuer, and create a client credential with a named owner and expiry. Keep the\nprovider assignment limited to the pilot population. Microsoft distinguishes\nthe app registration (the application definition) from its enterprise\napplication/service-principal instance; record both identities during support.\n\nFor SAML, create or select the enterprise application, configure its Identifier\nand Reply URL from this environment, then load the Microsoft Entra Identifier,\nlogin URL and current signing certificate into the SAML connection. Review the\nprovider's claims before authoring role or group mappings.\n\n- [Microsoft Entra OIDC application setup](https://learn.microsoft.com/en-us/entra/identity/enterprise-apps/add-application-portal-setup-oidc-sso)\n- [Microsoft Entra SAML application setup](https://learn.microsoft.com/en-us/entra/identity/enterprise-apps/add-application-portal-setup-sso)\n- [Microsoft Entra redirect URI rules](https://learn.microsoft.com/en-us/entra/identity-platform/how-to-add-redirect-uri)\n\n### Okta\n\nCreate a private OIDC or SAML app integration and initially assign only the\npilot people or groups. For OIDC, choose a **Web Application**, register the\nexact sign-in redirect URI, retain authorization code, and keep PKCE S256. Copy\nthe client ID, client secret and exact issuer used by that authorization server.\nDo not enable a wildcard redirect merely to avoid maintaining environment URLs.\n\nFor SAML, enter this environment's ACS URL and service-provider entity ID, then\nload Okta's Identity Provider issuer, sign-on URL and signing certificate into\nthe application connection. Map claims and groups explicitly; an Okta\nassignment decides who may reach the provider integration, while the\napplication membership and roles still decide application access.\n\n- [Okta OIDC app integration](https://help.okta.com/en-us/content/topics/apps/apps_app_integration_wizard_oidc.htm)\n- [Okta SAML app integration](https://help.okta.com/en-us/content/topics/apps/apps_app_integration_wizard_saml.htm)\n- [Okta SAML field reference](https://help.okta.com/en-us/content/topics/apps/aiw-saml-reference.htm)\n\n### Google Workspace or Cloud Identity\n\nFor OIDC, configure a web OAuth client with the exact authorized redirect URI\nand use Google's published issuer/discovery information. The provider can\nauthenticate Google accounts beyond one Workspace domain, so the application\nconnection's explicit allowed-domain list and the organization's membership\npolicy remain important boundaries.\n\nFor SAML, add a custom SAML app, copy Google's IdP entity ID, SSO URL and\ncertificate into this connection, then enter the application's ACS URL and\nentity ID in Google. Start with the service disabled or assigned to a pilot\norganizational unit/group, depending on the provider controls available to the\norganization.\n\n- [Google OpenID Connect guide](https://developers.google.com/identity/openid-connect/openid-connect)\n- [Google custom SAML application setup](https://support.google.com/a/answer/6087519)\n\n> **Do not paste credentials, private keys or complete certificates into a\n> ticket or screenshot.** Use the protected administration surfaces to exchange\n> sensitive material and share only non-secret identifiers for diagnosis.\n\n## Verify before enabling broadly\n\nEnable the connection for a controlled test, but do not make it default. Start\nfrom the application's sign-in journey and verify:\n\n1. the intended provider and environment receive the request;\n2. the provider accepts the controlled person under its expected policy;\n3. the application accepts the returned issuer/entity, audience, destination,\n signature and time checks;\n4. the stable subject maps to the intended application person;\n5. the person enters the intended organization with the expected role;\n6. one expected action succeeds and one action outside that authority is\n refused; and\n7. the independent recovery administrator still signs in.\n\nRecord non-secret identifiers, time, outcome and correlation evidence. Continue with\n[Roll out SSO and keep a recovery path](/access-and-identity/sso-rollout-and-recovery)\nbefore making it the default. Never include a password, client secret, private\nkey, complete assertion, authorization code or session cookie in the evidence.";
72
75
  }, {
73
76
  readonly managedPath: "access-and-identity/sso-rollout-and-recovery.md";
74
77
  readonly unitRef: "technical-documentation:unit/sso-rollout-and-recovery";
75
78
  readonly sourceRefs: readonly ["saas-technical-doc:engine-content/sso-rollout-and-recovery", "source:consumer-fact:access-single-sign-on"];
76
- readonly markdown: "# Roll out SSO and keep a recovery path\n\nIntroduce a configured connection in stages so a mapping mistake or provider\noutage cannot lock every administrator out at once.\n\n| Before you begin | Successful result |\n| --- | --- |\n| The connection passes a controlled test, the application and identity-provider owners are available, and an independent administrator can enter without this connection | Representative people sign in to the right organization with expected access, the connection becomes default only after proof, and a tested recovery path remains available |\n\nThe application can offer more than one configured connection and distinguish\nenabled from default behavior:\n\n{{CONSUMER_FACT:source:consumer-fact:access-single-sign-on#markdown}}\n\n~~~mermaid\nflowchart LR\n accTitle: Roll out single sign-on in controlled stages\n accDescr: Keep an independent recovery administrator, test one controlled identity, expand to a representative pilot, make the connection default only after verification, and retain the recovery path.\n recovery[\"Verify independent administrator recovery\"] --> controlled[\"Test one controlled identity\"]\n controlled --> pilot[\"Expand to a representative pilot\"]\n pilot --> default[\"Make default after verification\"]\n default --> monitor[\"Monitor and retain recovery\"]\n controlled -.-> stop[\"Stop on unexplained difference\"]\n pilot -.-> stop\n~~~\n\nThe recovery identity must not depend on the connection being tested. Confirm it\nbefore changing the default connection, and verify it again after a material\nprovider or trust change.\n\n## Build a representative pilot\n\nDo not test only an administrator. Include the identity and access differences\nthat can reveal a mapping defect:\n\n| Pilot case | What it proves |\n| --- | --- |\n| Existing ordinary member | Stable subject mapping does not create a duplicate person |\n| Newly eligible person, when first-sign-in creation is enabled | The intended user and membership lifecycle occurs with the fallback role |\n| Person with a mapped provider role or group | The exact external value maps to the intended application role |\n| Person outside an allowed domain or mapping | The connection refuses the identity without revealing another account |\n| Person with application MFA requirements | The actual post-provider journey is observed; do not infer it from the currently non-operative `bypassAppMFA` field |\n| Independent recovery administrator | Provider outage or mapping failure does not remove all administrative access |\n\nUse controlled test identities and non-sensitive application actions. Do not\nalter a real person's provider attributes merely to make the pilot pass.\n\n## Run the staged rollout\n\n1. Test one controlled identity whose provider attributes and organization\n membership are already known.\n2. Confirm the person returns to the correct environment and organization.\n3. Verify expected application access and an expected refusal; a successful\n provider login alone is insufficient.\n4. Expand to a pilot representing the identity patterns and roles used by the\n organization.\n5. Stop on an unexplained mapping, membership or access difference.\n6. Confirm how leavers and role changes are handled manually or through SCIM;\n SSO alone does not close the application membership.\n7. Make the connection default only when the pilot and recovery path both pass.\n\n## Make the default change observable\n\nChoose a support window, communicate which people and organization are affected,\nand record the previous default connection. After the change, repeat a normal\napplication-started sign-in rather than reusing a provider URL. Verify the\nresolved person, organization, expected action and expected refusal. Monitor\nauthentication failures separately from membership/role refusals so an access\nproblem is not mistaken for a provider outage.\n\n~~~mermaid\nstateDiagram-v2\n accTitle: Keep the connection in a known operational state\n accDescr: A connection begins configured but not default, advances through controlled and representative proof, becomes default only after recovery proof, returns to validation after any trust or mapping change, and is disabled when safe verification cannot be restored.\n [*] --> ConfiguredNotDefault\n ConfiguredNotDefault --> ControlledProof: one known identity passes\n ControlledProof --> Pilot: representative identities pass\n Pilot --> Default: recovery path also passes\n Default --> ConfiguredNotDefault: trust, credential, certificate, mapping or provider change\n ConfiguredNotDefault --> Disabled: validation cannot be completed safely\n Default --> Disabled: active incident requires containment\n Disabled --> ConfiguredNotDefault: corrected configuration is ready to retest\n~~~\n\nThe loop back to validation is intentional. A renewed secret, signing\ncertificate, issuer, endpoint, claim mapping or default role changes the trust\nor access proof even when the connection keeps the same display name.\n\n## Renew credentials and signing certificates without an outage\n\n### Rotate an OIDC client secret\n\n1. Confirm whether the provider supports two simultaneously valid secrets.\n2. Create the replacement in the provider and record its owner and expiry.\n3. Update the protected, write-only client-secret field in the matching\n application environment. Never paste the secret into a change ticket.\n4. Run a fresh controlled sign-in and inspect both provider and application\n evidence.\n5. Revoke the previous secret only after the replacement succeeds and the\n rollback window has been approved.\n\nIf the provider permits only one active secret, schedule a support window,\nretain the independent administrator path, update both sides as one controlled\nchange, and test immediately.\n\n### Rotate a SAML signing certificate\n\n1. Obtain the provider's new public signing certificate and verify its\n fingerprint through an approved independent channel.\n2. When the provider and application support overlapping certificates, load the\n new certificate before the provider starts signing with it.\n3. Run **Test connection**, then complete a real sign-in.\n4. Switch the provider to the new signing key and repeat the controlled proof.\n5. Remove the old certificate only after all provider nodes use the new key and\n the overlap window has ended.\n\nThe application schema accepts more than one SAML signing certificate so a\nplanned overlap is possible. Do not replace a certificate merely because a\nticket contains a PEM block; verify the provider source and fingerprint.\n\n## Monitor both sides of the boundary\n\nCorrelate by time, person, application/connection and the provider's request or\ncorrelation identifier where available. Provider success plus application\nfailure points to response validation, mapping or membership. Provider failure\nmeans the application may never receive a response.\n\n- Microsoft Entra: [sign-in logs](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-sign-ins)\n and [sign-in diagnostics](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-use-sign-in-diagnostics).\n- Okta: [System Log](https://help.okta.com/en-us/content/topics/reports/reports_syslog.htm).\n- Google Workspace: use the provider's authentication and SAML application\n audit/investigation views available for the organization's edition, together\n with the application audit trail.\n\n## Prepare for provider or configuration failure\n\nRecord who owns the provider and application sides of the connection, how to\nreach the independent recovery method, and which last-known-good values can be\ncompared without exposing secrets. After changing issuer, entity, audience,\nredirect, certificate, client or mapping settings, repeat the controlled test\nbefore expanding again.\n\nIf the provider is unavailable, use the independent recovery method, confirm\nthe scope of the outage and avoid changing trust values speculatively. Restore\nor correct one boundary, retest with a controlled identity, then return the\nconnection to default use. Keep the recovery method narrow and monitored; it is\nnot a shared bypass account.\n\nRetain the connection name, organization, environment, pilot cases, test times,\nnon-secret trust identifiers, mapping decisions, allowed/refused results,\ndefault-change approval and recovery proof. Exclude passwords, one-time codes,\nclient secrets, private keys, complete assertions and session cookies.";
79
+ readonly markdown: "# Roll out SSO and keep a recovery path\n\nIntroduce a configured connection in stages so a mapping mistake or provider\noutage cannot lock every administrator out at once.\n\n| Before you begin | Successful result |\n| --- | --- |\n| The connection passes a controlled test, the application and identity-provider owners are available, and an independent administrator can enter without this connection | Representative people sign in to the right organization with expected access, the connection becomes default only after proof, and a tested recovery path remains available |\n\nThe application can offer more than one configured connection and distinguish\nenabled from default behavior:\n\n{{CONSUMER_FACT:source:consumer-fact:access-single-sign-on#markdown}}\n\n~~~mermaid\nflowchart LR\n accTitle: Roll out single sign-on in controlled stages\n accDescr: Keep an independent recovery administrator, test one controlled identity, expand to a representative pilot, make the connection default only after verification, and retain the recovery path.\n recovery[\"Verify independent administrator recovery\"] --> controlled[\"Test one controlled identity\"]\n controlled --> pilot[\"Expand to a representative pilot\"]\n pilot --> default[\"Make default after verification\"]\n default --> monitor[\"Monitor and retain recovery\"]\n controlled -.-> stop[\"Stop on unexplained difference\"]\n pilot -.-> stop\n~~~\n\nThe recovery identity must not depend on the connection being tested. Confirm it\nbefore changing the default connection, and verify it again after a material\nprovider or trust change.\n\n## Build a representative pilot\n\nDo not test only an administrator. Include the identity and access differences\nthat can reveal a mapping defect:\n\n| Pilot case | What it proves |\n| --- | --- |\n| Existing ordinary member | Stable subject mapping does not create a duplicate person |\n| Newly eligible person, when first-sign-in creation is enabled | The intended user and membership lifecycle occurs with the fallback role |\n| Person with a mapped provider role or group | The exact external value maps to the intended application role |\n| Person outside an allowed domain or mapping | The connection refuses the identity without revealing another account |\n| Person with application MFA requirements | The actual post-provider journey is observed. A connection cannot exempt anyone from the application's requirement: the declared policy is enforced on the federated lane too, and an organization may only tighten it |\n| Independent recovery administrator | Provider outage or mapping failure does not remove all administrative access |\n\nUse controlled test identities and non-sensitive application actions. Do not\nalter a real person's provider attributes merely to make the pilot pass.\n\n## Run the staged rollout\n\n1. Test one controlled identity whose provider attributes and organization\n membership are already known.\n2. Confirm the person returns to the correct environment and organization.\n3. Verify expected application access and an expected refusal; a successful\n provider login alone is insufficient.\n4. Expand to a pilot representing the identity patterns and roles used by the\n organization.\n5. Stop on an unexplained mapping, membership or access difference.\n6. Confirm how leavers and role changes are handled manually or through SCIM;\n SSO alone does not close the application membership.\n7. Make the connection default only when the pilot and recovery path both pass.\n\n## Make the default change observable\n\nChoose a support window, communicate which people and organization are affected,\nand record the previous default connection. After the change, repeat a normal\napplication-started sign-in rather than reusing a provider URL. Verify the\nresolved person, organization, expected action and expected refusal. Monitor\nauthentication failures separately from membership/role refusals so an access\nproblem is not mistaken for a provider outage.\n\n~~~mermaid\nstateDiagram-v2\n accTitle: Keep the connection in a known operational state\n accDescr: A connection begins configured but not default, advances through controlled and representative proof, becomes default only after recovery proof, returns to validation after any trust or mapping change, and is disabled when safe verification cannot be restored.\n [*] --> ConfiguredNotDefault\n ConfiguredNotDefault --> ControlledProof: one known identity passes\n ControlledProof --> Pilot: representative identities pass\n Pilot --> Default: recovery path also passes\n Default --> ConfiguredNotDefault: trust, credential, certificate, mapping or provider change\n ConfiguredNotDefault --> Disabled: validation cannot be completed safely\n Default --> Disabled: active incident requires containment\n Disabled --> ConfiguredNotDefault: corrected configuration is ready to retest\n~~~\n\nThe loop back to validation is intentional. A renewed secret, signing\ncertificate, issuer, endpoint, claim mapping or default role changes the trust\nor access proof even when the connection keeps the same display name.\n\n## Renew credentials and signing certificates without an outage\n\n### Rotate an OIDC client secret\n\n1. Confirm whether the provider supports two simultaneously valid secrets.\n2. Create the replacement in the provider and record its owner and expiry.\n3. Update the protected, write-only client-secret field in the matching\n application environment. Never paste the secret into a change ticket.\n4. Run a fresh controlled sign-in and inspect both provider and application\n evidence.\n5. Revoke the previous secret only after the replacement succeeds and the\n rollback window has been approved.\n\nIf the provider permits only one active secret, schedule a support window,\nretain the independent administrator path, update both sides as one controlled\nchange, and test immediately.\n\n### Rotate a SAML signing certificate\n\n1. Obtain the provider's new public signing certificate and verify its\n fingerprint through an approved independent channel.\n2. When the provider and application support overlapping certificates, load the\n new certificate before the provider starts signing with it.\n3. Run **Test connection**, then complete a real sign-in.\n4. Switch the provider to the new signing key and repeat the controlled proof.\n5. Remove the old certificate only after all provider nodes use the new key and\n the overlap window has ended.\n\nThe application schema accepts more than one SAML signing certificate so a\nplanned overlap is possible. Do not replace a certificate merely because a\nticket contains a PEM block; verify the provider source and fingerprint.\n\n## Monitor both sides of the boundary\n\nCorrelate by time, person, application/connection and the provider's request or\ncorrelation identifier where available. Provider success plus application\nfailure points to response validation, mapping or membership. Provider failure\nmeans the application may never receive a response.\n\n- Microsoft Entra: [sign-in logs](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-sign-ins)\n and [sign-in diagnostics](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-use-sign-in-diagnostics).\n- Okta: [System Log](https://help.okta.com/en-us/content/topics/reports/reports_syslog.htm).\n- Google Workspace: use the provider's authentication and SAML application\n audit/investigation views available for the organization's edition, together\n with the application audit trail.\n\n## Prepare for provider or configuration failure\n\nRecord who owns the provider and application sides of the connection, how to\nreach the independent recovery method, and which last-known-good values can be\ncompared without exposing secrets. After changing issuer, entity, audience,\nredirect, certificate, client or mapping settings, repeat the controlled test\nbefore expanding again.\n\nIf the provider is unavailable, use the independent recovery method, confirm\nthe scope of the outage and avoid changing trust values speculatively. Restore\nor correct one boundary, retest with a controlled identity, then return the\nconnection to default use. Keep the recovery method narrow and monitored; it is\nnot a shared bypass account.\n\nRetain the connection name, organization, environment, pilot cases, test times,\nnon-secret trust identifiers, mapping decisions, allowed/refused results,\ndefault-change approval and recovery proof. Exclude passwords, one-time codes,\nclient secrets, private keys, complete assertions and session cookies.";
77
80
  }, {
78
81
  readonly managedPath: "access-and-identity/sso-troubleshoot.md";
79
82
  readonly unitRef: "technical-documentation:unit/sso-troubleshoot";
@@ -93,12 +96,12 @@ export declare const APPLICATION_CONSUMER_DOCUMENTATION_AUTHORED_CONTENT_V1: rea
93
96
  readonly managedPath: "access-and-identity/api-keys-lifecycle.md";
94
97
  readonly unitRef: "technical-documentation:unit/api-keys-lifecycle";
95
98
  readonly sourceRefs: readonly ["saas-technical-doc:engine-content/api-keys-lifecycle", "source:consumer-fact:access-api-keys"];
96
- readonly markdown: "# Rotate, expire or deactivate an API key\n\nReplace a machine credential without losing control of which secret works. Use\nrotation for a planned, bounded handover; use immediate rotation or deactivation\nfor suspected exposure; and use expiry when access has a known end date.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Identify the key by its non-secret prefix, owner, workload, scope, roles and deployed instances; have an approved secrets-manager destination | Every intended instance uses the replacement, the previous secret stops at the chosen time, expected access still works and unrelated access remains refused |\n\nThe key presentation identifies its scope, not its authority:\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#markdown}}\n\nConfirm that you are changing the intended organization or application key\nbefore reissuing any secret. A prefix is safe to use for identification, but it\nis not enough on its own: compare the owner, workload and environment too.\n\n## Choose the lifecycle action\n\n| Situation | Action | Important consequence |\n| --- | --- | --- |\n| Planned replacement with a short deployment window | **Rotate** with an explicit future invalidation time | Current and previous secrets can overlap only until that chosen time |\n| Suspected disclosure and the workload can switch now | **Rotate immediately** | Immediate rotation is the default when no future invalidation time is chosen; the previous secret stops working at cutover |\n| Suspected disclosure and workload ownership is uncertain | **Deactivate** | Neither the current nor retained previous secret can authenticate while the key is inactive |\n| Workload is permanently retired | **Deactivate** and remove its deployed secret | The key remains identifiable for review but cannot authenticate |\n| Temporary credential has a known end | Set an **expiry** at creation; extend it only after a documented review | Once expired, the key cannot be reactivated; replace it if access is approved again |\n| An intentional open-ended overlap is truly required | **Regenerate**, with a separately controlled follow-up rotation | The previous secret remains valid until a later reissue; regeneration does not contain a leaked credential |\n\n## Know the maintained lifecycle operations\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#statusMarkdown}}\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#lifecycleMarkdown}}\n\n~~~mermaid\nflowchart TD\n accTitle: Choose the safe API-key lifecycle action\n accDescr: A planned handover uses rotation and verification. Suspected compromise requires prompt old-secret invalidation or deactivation. Finished access is deactivated, while a time-bounded credential is allowed to expire.\n reason{\"Why must access change?\"}\n reason -->|\"Planned replacement\"| rotate[\"Rotate with explicit handover\"]\n reason -->|\"Suspected exposure\"| contain[\"Invalidate old secret promptly or deactivate\"]\n reason -->|\"Workload retired\"| deactivate[\"Deactivate key\"]\n reason -->|\"Known end time\"| expiry[\"Set or extend explicit expiry\"]\n~~~\n\n## Run a planned rotation\n\nRotation keeps the same credential record, owner, scope and roles while issuing\na new complete secret. The outgoing secret moves into a single previous-secret\nslot and remains usable only until the selected invalidation time. If no future\ntime is selected, the operation defaults to **now**, which is an immediate\ncutover.\n\n1. Inventory every production instance, scheduled job and deployment that reads\n this key. Do not rotate while ownership is unknown.\n2. Choose the shortest practical invalidation time. Record the reason, owner\n and planned end of overlap.\n3. Perform the rotation and move the one-time replacement directly into the\n approved secrets-manager entry. Never paste it into the change record.\n4. Roll out the new secret to every known instance and verify a safe operation\n in the intended environment and scope.\n5. Before the deadline, confirm every instance reports the replacement version\n and no deployment still depends on the outgoing secret.\n6. After invalidation, verify that the replacement still succeeds and that the\n previous secret is refused. Record only prefixes, times, outcomes and\n correlation evidence.\n\nIf an instance cannot move before the chosen time, stop and make a conscious\navailability-versus-exposure decision. Do not silently extend an overlap whose\nowner or purpose is unclear.\n\n## Understand regeneration before using it\n\n> **Regeneration is not incident containment.** An open-ended regenerate\n> operation leaves the previous secret valid until a later reissue replaces the\n> overlap state. If the key may be compromised, deactivate it or rotate with\n> prompt invalidation.\n\nRegeneration can support a deliberately staged migration when the old secret\ncannot yet have a bounded end time, but it creates two live secrets. Before\nusing it, document why a normal bounded rotation is impossible, who owns the\nfollow-up cutover and when the later rotation will occur. Verify both the new\ndeployment and the eventual rejection of the previous secret; issuing a new\nsecret is not completion.\n\n## Contain suspected exposure\n\nWhen a complete secret may have reached source control, a browser bundle, a\nticket, an ordinary log or an unauthorized person:\n\n1. Preserve non-secret time, environment, prefix and workload evidence.\n2. Deactivate the key when deployment ownership is uncertain, or rotate with\n immediate invalidation when the approved workload can switch safely.\n3. Remove the exposed value from every deployment and storage location. Treat\n source-history or log cleanup as a separate containment task; rotation alone\n does not remove copied material.\n4. Review the application audit trail and workload/provider logs for the\n affected period, using the key identifier, prefix, operation and correlation\n evidence—not the complete secret. Do not infer inactivity from the current\n per-key usage-statistics response.\n5. Restore only the minimum intended roles and operations with a protected\n replacement. Verify an expected refusal as well as a successful request.\n\n## Handle status and expiry\n\nAn inactive key cannot authenticate, including through a retained previous\nsecret. Reactivation is permitted only for an **Inactive** key; an **Expired**\nkey is terminal and cannot be reactivated. If access is approved again after\nexpiry, create a new least-privilege credential with a new review decision.\n\nExpiry is enforced when the key authenticates. Treat the key as unusable after\nthat time even if a list view has not yet changed its stored status label.\nExtend an existing expiry only when the same owner, workload, scope, roles and\nbusiness need have been reviewed. Extension changes the time boundary; it does\nnot rotate secret material or repair an ownerless key.\n\n## Close the change with evidence\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#usageStatisticsLimitationMarkdown}}\n\nUntil per-key tracking exists, prove deployment and retirement from controlled\nrequests, application audit evidence and the workload's own secret-access and\nexecution logs. A page of zero counters is not a safe deletion decision.\n\nRetain a non-secret lifecycle record containing:\n\n- key identifier or visible prefix, scope, owner and workload;\n- action taken, reason, approver and environment;\n- replacement deployment time and every affected instance;\n- chosen previous-secret invalidation time;\n- successful expected operation and expected refusal;\n- confirmation that the previous secret no longer authenticates; and\n- incident or change correlation identifier and next review date.\n\nNever attach the current or previous complete secret, Authorization header or\nsecrets-manager value to lifecycle evidence.";
99
+ readonly markdown: "# Rotate, expire or deactivate an API key\n\nReplace a machine credential without losing control of which secret works. Use\nrotation for a planned, bounded handover; use immediate rotation or deactivation\nfor suspected exposure; and use expiry when access has a known end date.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Identify the key by its non-secret prefix, owner, workload, scope, roles and deployed instances; have an approved secrets-manager destination | Every intended instance uses the replacement, the previous secret stops at the chosen time, expected access still works and unrelated access remains refused |\n\nThe key presentation identifies its scope, not its authority:\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#markdown}}\n\nConfirm that you are changing the intended organization or application key\nbefore reissuing any secret. A prefix is safe to use for identification, but it\nis not enough on its own: compare the owner, workload and environment too.\n\n## Choose the lifecycle action\n\n| Situation | Action | Important consequence |\n| --- | --- | --- |\n| Planned replacement with a short deployment window | **Rotate** with an explicit future invalidation time | Current and previous secrets can overlap only until that chosen time |\n| Suspected disclosure and the workload can switch now | **Rotate immediately** | Immediate rotation is the default when no future invalidation time is chosen; the previous secret stops working at cutover |\n| Suspected disclosure and workload ownership is uncertain | **Deactivate** | Neither the current nor retained previous secret can authenticate while the key is inactive |\n| Workload is permanently retired | **Deactivate** and remove its deployed secret | The key remains identifiable for review but cannot authenticate |\n| Temporary credential has a known end | Set an **expiry** at creation; extend it only after a documented review | Once expired, the key cannot be reactivated; replace it if access is approved again |\n| An intentional open-ended overlap is truly required | **Regenerate**, with a separately controlled follow-up rotation | The previous secret remains valid until a later reissue; regeneration does not contain a leaked credential |\n\n## Know the maintained lifecycle operations\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#statusMarkdown}}\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#lifecycleMarkdown}}\n\n~~~mermaid\nflowchart TD\n accTitle: Choose the safe API-key lifecycle action\n accDescr: A planned handover uses rotation and verification. Suspected compromise requires prompt old-secret invalidation or deactivation. Finished access is deactivated, while a time-bounded credential is allowed to expire.\n reason{\"Why must access change?\"}\n reason -->|\"Planned replacement\"| rotate[\"Rotate with explicit handover\"]\n reason -->|\"Suspected exposure\"| contain[\"Invalidate old secret promptly or deactivate\"]\n reason -->|\"Workload retired\"| deactivate[\"Deactivate key\"]\n reason -->|\"Known end time\"| expiry[\"Set or extend explicit expiry\"]\n~~~\n\n## Run a planned rotation\n\nRotation keeps the same credential record, owner, scope and roles while issuing\na new complete secret. The outgoing secret moves into a single previous-secret\nslot and remains usable only until the selected invalidation time. If no future\ntime is selected, the operation defaults to **now**, which is an immediate\ncutover.\n\n1. Inventory every production instance, scheduled job and deployment that reads\n this key. Do not rotate while ownership is unknown.\n2. Choose the shortest practical invalidation time. Record the reason, owner\n and planned end of overlap.\n3. Perform the rotation and move the one-time replacement directly into the\n approved secrets-manager entry. Never paste it into the change record.\n4. Roll out the new secret to every known instance and verify a safe operation\n in the intended environment and scope.\n5. Before the deadline, confirm every instance reports the replacement version\n and no deployment still depends on the outgoing secret.\n6. After invalidation, verify that the replacement still succeeds and that the\n previous secret is refused. Record only prefixes, times, outcomes and\n correlation evidence.\n\nIf an instance cannot move before the chosen time, stop and make a conscious\navailability-versus-exposure decision. Do not silently extend an overlap whose\nowner or purpose is unclear.\n\n## Understand regeneration before using it\n\n> **Regeneration is not incident containment.** An open-ended regenerate\n> operation leaves the previous secret valid until a later reissue replaces the\n> overlap state. If the key may be compromised, deactivate it or rotate with\n> prompt invalidation.\n\nRegeneration can support a deliberately staged migration when the old secret\ncannot yet have a bounded end time, but it creates two live secrets. Before\nusing it, document why a normal bounded rotation is impossible, who owns the\nfollow-up cutover and when the later rotation will occur. Verify both the new\ndeployment and the eventual rejection of the previous secret; issuing a new\nsecret is not completion.\n\n## Contain suspected exposure\n\nWhen a complete secret may have reached source control, a browser bundle, a\nticket, an ordinary log or an unauthorized person:\n\n1. Preserve non-secret time, environment, prefix and workload evidence.\n2. Deactivate the key when deployment ownership is uncertain, or rotate with\n immediate invalidation when the approved workload can switch safely.\n3. Remove the exposed value from every deployment and storage location. Treat\n source-history or log cleanup as a separate containment task; rotation alone\n does not remove copied material.\n4. Review the application audit trail and workload/provider logs for the\n affected period, using the key identifier, prefix, operation and correlation\n evidence—not the complete secret. Do not infer inactivity from the current\n per-key usage-statistics response.\n5. Restore only the minimum intended roles and operations with a protected\n replacement. Verify an expected refusal as well as a successful request.\n\n## Handle status and expiry\n\nAn inactive key cannot authenticate, including through a retained previous\nsecret. Reactivation is permitted only for an **Inactive** key; an **Expired**\nkey is terminal and cannot be reactivated. If access is approved again after\nexpiry, create a new least-privilege credential with a new review decision.\n\nExpiry is enforced when the key authenticates. Treat the key as unusable after\nthat time even if a list view has not yet changed its stored status label.\nExtend an existing expiry only when the same owner, workload, scope, roles and\nbusiness need have been reviewed. Extension changes the time boundary; it does\nnot rotate secret material or repair an ownerless key.\n\n## Close the change with evidence\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#usageStatisticsMarkdown}}\n\nAfter a rotation, the new key should show accepted requests and a recent\nlast-accepted time, and the key it replaced should stop being accepted. The\ncounters cover a rolling week, so a key a workload uses less often than weekly\ncan show none: read its last-accepted time before calling it unused, and confirm\nwith the owning workload before deleting a key that time does not settle.\n\nRetain a non-secret lifecycle record containing:\n\n- key identifier or visible prefix, scope, owner and workload;\n- action taken, reason, approver and environment;\n- replacement deployment time and every affected instance;\n- chosen previous-secret invalidation time;\n- successful expected operation and expected refusal;\n- confirmation that the previous secret no longer authenticates; and\n- incident or change correlation identifier and next review date.\n\nNever attach the current or previous complete secret, Authorization header or\nsecrets-manager value to lifecycle evidence.";
97
100
  }, {
98
101
  readonly managedPath: "access-and-identity/api-keys-troubleshoot.md";
99
102
  readonly unitRef: "technical-documentation:unit/api-keys-troubleshoot";
100
103
  readonly sourceRefs: readonly ["saas-technical-doc:engine-content/api-keys-troubleshoot", "source:consumer-fact:access-api-keys"];
101
- readonly markdown: "# Troubleshoot an API key\n\nDiagnose the failed decision in order: transport, credential lifecycle, scope,\nrole and operation policy. Do not rotate or broaden a credential before you\nknow which decision failed.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Preserve the environment, operation, approximate time, correlation details and non-secret key prefix | One narrow correction makes a safe request succeed, and the workload still cannot exceed its intended scope |\n\n~~~mermaid\nflowchart TD\n accTitle: Diagnose an API key from transport to operation access\n accDescr: The integration owner confirms the environment and authorization header, matches the non-secret prefix to an active unexpired key, verifies organization or application scope and assigned roles, and finally checks whether the exact operation accepts API-key authentication.\n symptom[\"Request is refused or resource is missing\"] --> environment[\"Confirm environment and operation\"]\n environment --> transport{\"Header contains current opaque key?\"}\n transport -->|No| correct[\"Correct secret delivery without logging it\"]\n transport -->|Yes| lifecycle{\"Key active and unexpired?\"}\n lifecycle -->|No| replace[\"Use approved rotation or replacement\"]\n lifecycle -->|Yes| scope{\"Scope and roles match the task?\"}\n scope -->|No| assignment[\"Correct the narrow assignment\"]\n scope -->|Yes| contract[\"Check exact operation authentication contract\"]\n contract --> proof[\"Repeat one safe request and verify result\"]\n~~~\n\nThe non-secret prefix helps identify the credential record; it cannot prove\nthat the workload received the current complete secret.\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#usageStatisticsLimitationMarkdown}}\n\nDo not diagnose an apparently unused key from those counters. Correlate the\nworkload's execution logs, secret-access logs, application audit trail and one\ncontrolled request instead.\n\nThe request must carry the complete opaque value in this maintained header\nshape:\n\n~~~text\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#requestHeader}}\n~~~\n\n| Result | Check first | Safe response |\n| --- | --- | --- |\n| **401 Unauthorized** | Header spelling, complete secret, absence of `Bearer`, key status, expiry and environment | Correct transport or replace an inactive, expired or revoked key |\n| **403 Forbidden** | Key roles, scope, feature entitlement and whether the operation accepts API keys | Correct the narrow assignment or integration design |\n| **404 Not Found** | Resource identifier and organization visibility | Confirm scope without assuming a hidden resource exists |\n| Requests alternate between success and 401 | Secret version on every workload replica or job runner | Finish deployment of the current secret, then retire the previous one deliberately |\n\n## Isolate the failing decision\n\n1. Confirm the workload targets the expected environment.\n2. Confirm the standard authorization header contains the current complete\n opaque key and no scheme.\n3. Compare the non-secret prefix with the intended credential record.\n4. Check whether rotation recently created a new secret and whether every\n workload instance received it.\n5. Check active status and expiry. An expired or inactive key must not\n authenticate even if its record remains visible.\n6. Check organization or application scope and assigned roles.\n7. Check the exact operation's generated authentication contract. Some\n operations intentionally refuse API-key access.\n8. Repeat one read-only or otherwise safe request and verify the business result\n in the intended scope.\n\n## Choose the repair that matches the failure\n\n- **Transport failure:** correct the secrets-manager reference or header\n construction. Never print the value to compare it.\n- **Old secret after rotation:** deploy the new value everywhere and verify it\n before the previous value reaches its invalidation time.\n- **Inactive, expired or compromised key:** use the approved lifecycle action;\n do not reactivate a key whose owner or exposure is uncertain.\n- **Wrong scope or role:** change only the assignment needed by the documented\n workload. Re-run an expected refusal as well as the success proof.\n- **Operation rejects API keys:** use the supported human or delegated-client\n journey. A broader API key does not change the operation's authentication\n policy.\n\nNever replace a narrow key with a broadly privileged key merely to silence an\nauthorization error. That turns a diagnosable assignment problem into a larger\nsecurity exposure.\n\n## Escalate without exposing the credential\n\nProvide the environment, operation, HTTP result, approximate time, correlation\nidentifier, non-secret key prefix, lifecycle state and whether rotation was in\nprogress. Never include the complete key, authorization header, secret-manager\nvalue or a screenshot containing them.";
104
+ readonly markdown: "# Troubleshoot an API key\n\nDiagnose the failed decision in order: transport, credential lifecycle, scope,\nrole and operation policy. Do not rotate or broaden a credential before you\nknow which decision failed.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Preserve the environment, operation, approximate time, correlation details and non-secret key prefix | One narrow correction makes a safe request succeed, and the workload still cannot exceed its intended scope |\n\n~~~mermaid\nflowchart TD\n accTitle: Diagnose an API key from transport to operation access\n accDescr: The integration owner confirms the environment and authorization header, matches the non-secret prefix to an active unexpired key, verifies organization or application scope and assigned roles, and finally checks whether the exact operation accepts API-key authentication.\n symptom[\"Request is refused or resource is missing\"] --> environment[\"Confirm environment and operation\"]\n environment --> transport{\"Header contains current opaque key?\"}\n transport -->|No| correct[\"Correct secret delivery without logging it\"]\n transport -->|Yes| lifecycle{\"Key active and unexpired?\"}\n lifecycle -->|No| replace[\"Use approved rotation or replacement\"]\n lifecycle -->|Yes| scope{\"Scope and roles match the task?\"}\n scope -->|No| assignment[\"Correct the narrow assignment\"]\n scope -->|Yes| contract[\"Check exact operation authentication contract\"]\n contract --> proof[\"Repeat one safe request and verify result\"]\n~~~\n\nThe non-secret prefix helps identify the credential record; it cannot prove\nthat the workload received the current complete secret.\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#usageStatisticsMarkdown}}\n\nOnly requests the application ACCEPTED the key for are counted. A key sent with\nthe wrong secret, past its expiry or after deactivation is refused and leaves no\ncount, and neither does a request stopped before it reaches the application. So\na key with no recent use points at the workload not sending it; failures on a\nkey with recent use point at the request itself (its scope, roles or payload).\nConfirm either reading with one controlled request.\n\nThe request must carry the complete opaque value in this maintained header\nshape:\n\n~~~text\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#requestHeader}}\n~~~\n\n| Result | Check first | Safe response |\n| --- | --- | --- |\n| **401 Unauthorized** | Header spelling, complete secret, absence of `Bearer`, key status, expiry and environment | Correct transport or replace an inactive, expired or revoked key |\n| **403 Forbidden** | Key roles, scope, feature entitlement and whether the operation accepts API keys | Correct the narrow assignment or integration design |\n| **404 Not Found** | Resource identifier and organization visibility | Confirm scope without assuming a hidden resource exists |\n| Requests alternate between success and 401 | Secret version on every workload replica or job runner | Finish deployment of the current secret, then retire the previous one deliberately |\n\n## Isolate the failing decision\n\n1. Confirm the workload targets the expected environment.\n2. Confirm the standard authorization header contains the current complete\n opaque key and no scheme.\n3. Compare the non-secret prefix with the intended credential record.\n4. Check whether rotation recently created a new secret and whether every\n workload instance received it.\n5. Check active status and expiry. An expired or inactive key must not\n authenticate even if its record remains visible.\n6. Check organization or application scope and assigned roles.\n7. Check the exact operation's generated authentication contract. Some\n operations intentionally refuse API-key access.\n8. Repeat one read-only or otherwise safe request and verify the business result\n in the intended scope.\n\n## Choose the repair that matches the failure\n\n- **Transport failure:** correct the secrets-manager reference or header\n construction. Never print the value to compare it.\n- **Old secret after rotation:** deploy the new value everywhere and verify it\n before the previous value reaches its invalidation time.\n- **Inactive, expired or compromised key:** use the approved lifecycle action;\n do not reactivate a key whose owner or exposure is uncertain.\n- **Wrong scope or role:** change only the assignment needed by the documented\n workload. Re-run an expected refusal as well as the success proof.\n- **Operation rejects API keys:** use the supported human or delegated-client\n journey. A broader API key does not change the operation's authentication\n policy.\n\nNever replace a narrow key with a broadly privileged key merely to silence an\nauthorization error. That turns a diagnosable assignment problem into a larger\nsecurity exposure.\n\n## Escalate without exposing the credential\n\nProvide the environment, operation, HTTP result, approximate time, correlation\nidentifier, non-secret key prefix, lifecycle state and whether rotation was in\nprogress. Never include the complete key, authorization header, secret-manager\nvalue or a screenshot containing them.";
102
105
  }, {
103
106
  readonly managedPath: "access-and-identity/oauth-provider.md";
104
107
  readonly unitRef: "technical-documentation:unit/oauth-provider";
@@ -118,7 +121,7 @@ export declare const APPLICATION_CONSUMER_DOCUMENTATION_AUTHORED_CONTENT_V1: rea
118
121
  readonly managedPath: "access-and-identity/oauth-operate-and-revoke.md";
119
122
  readonly unitRef: "technical-documentation:unit/oauth-operate-and-revoke";
120
123
  readonly sourceRefs: readonly ["saas-technical-doc:engine-content/oauth-operate-and-revoke", "source:consumer-fact:access-oauth-clients"];
121
- readonly markdown: "# Operate and revoke OAuth clients\n\nReview active clients as independent machine identities. Keep each client,\ncredential and delegated token associated with its owner, environment, subject\nand organization.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Identify the client, owner, environment, grant, deployed workloads, delegated users and non-secret secret prefix; know whether the change concerns client configuration, client credential or issued tokens | The intended client or token access changes, expected operation and refusal are re-proven, and unrelated integrations continue without broader authority |\n\n{{CONSUMER_FACT:source:consumer-fact:access-oauth-clients#markdown}}\n\nThe maintained registered-client lifecycle is:\n\n{{CONSUMER_FACT:source:consumer-fact:access-oauth-clients#statusMarkdown}}\n\n{{CONSUMER_FACT:source:consumer-fact:access-oauth-clients#lifecycleMarkdown}}\n\n{{CONSUMER_FACT:source:consumer-fact:access-oauth-clients#currentUsageEvidenceMarkdown}}\n\n## Change the correct lifecycle layer\n\n~~~mermaid\nflowchart TD\n accTitle: Choose the OAuth lifecycle layer that needs to change\n accDescr: The operator distinguishes the registered client contract, its confidential secret, issued delegated tokens and the person's application membership, then changes and verifies only the affected layer.\n reason{\"What must change?\"}\n reason -->|\"Grant, roles, scopes, redirects or class\"| registration[\"Review or replace client registration\"]\n reason -->|\"Confidential secret\"| credential[\"Rotate with bounded invalidation\"]\n reason -->|\"One delegated authorization\"| token[\"Use published token revocation or reauthorization\"]\n reason -->|\"Person leaves organization\"| membership[\"Suspend/remove membership or use SCIM\"]\n registration --> verify[\"Repeat complete flow and authority proof\"]\n credential --> verify\n token --> verify\n membership --> verify\n~~~\n\nThese layers are related but not interchangeable. Rotating a client secret does\nnot by itself prove that an already issued delegated token is revoked. Removing\na person's organization access is a user-administration decision, not a reason\nto silently grant the client a machine role.\n\n## Review and change a client safely\n\nAt every review, answer these questions:\n\n- Is the owner and business purpose still current?\n- Does the grant still match who authorizes the work?\n- Are application roles limited to the exact operations still used?\n- Are identity scopes limited to claims the delegated client still needs?\n- Does every redirect and post-sign-out destination still belong to this client\n and environment?\n- Does the public/confidential classification match where the client now runs?\n- Is explicit consent still appropriate for the client's trust posture?\n- Do expiry, audit evidence, resource-server activity and active deployments\n support keeping it?\n\nA changed redirect, role, grant, identity scope, consent posture or token method\nchanges the security contract. Where the management surface does not safely\nsupport that transition in place, register a replacement client and migrate\ndeliberately instead of repurposing an established identity.\n\n## Rotate a confidential client secret\n\nRotate a confidential client secret through the administration operation\nprovided for that client. Deploy and verify the new secret before the previous\none becomes invalid when a handover is intended. For suspected compromise,\ninvalidate the previous secret promptly or remove the client; do not rely on\nan open-ended regenerate operation to contain exposure.\n\nRotation reissues the secret on the same client. A future invalidation time\ncreates a bounded overlap; the default is immediate invalidation. Regeneration\ncreates an open-ended overlap until a later reissue, so it is not incident\ncontainment.\n\n1. Inventory every workload instance using the confidential client.\n2. Choose the shortest practical invalidation time and record the owner.\n3. Store the one-time replacement directly in the approved secrets manager.\n4. Deploy it everywhere and complete a safe token plus operation proof.\n5. After invalidation, confirm the replacement succeeds and the previous secret\n is refused.\n\nIf disclosure is suspected and ownership is uncertain, remove the compromised\nclient through the supported administration lifecycle and register a protected\nreplacement. Do not leave an open-ended overlap while searching for consumers.\n\n## Revoke delegated access or retire a client\n\nUse the application's published token-revocation behavior when one delegated\nauthorization should end, and require a fresh authorization journey if the\nperson later restores it. Retire an entire integration by removing its client\nregistration and every deployed secret, then confirm new token issuance fails.\nSeparately suspend or remove the person's organization membership when their\napplication access must end; SSO or OAuth revocation alone is not the membership\nlifecycle.\n\nFor a suspected incident, treat client credential exposure and issued-token\nexposure as separate questions. Contain both applicable paths and review\nactivity for the affected client, person, organization and period.\n\nToken revocation follows [RFC 7009](https://www.rfc-editor.org/rfc/rfc7009): an\nunknown or already revoked token still receives a successful response so the\nendpoint does not become a token-validity oracle. Therefore **HTTP success is\nnot the final proof**. Retry one safe protected operation with the revoked token\nand verify that it is refused, then confirm a different unaffected client still\nworks. Confidential clients must authenticate to the revocation endpoint using\ntheir registered method; a bad client secret is refused before revocation.\n\n## Diagnose OAuth failures\n\n| Symptom | Check first | Safe response |\n| --- | --- | --- |\n| Discovery or registration is unavailable | Whether the capability is advertised here | Use an enabled onboarding path; do not probe undocumented endpoints |\n| Authorization request is rejected | Client, allowed grant, exact redirect and required proof | Correct the registered client or request |\n| Consent is denied or required | Client identity, claims and intended roles | Preserve the decision and explain or correct the request |\n| Code exchange fails | Issuer, redirect, proof, client class and token method | Restart the published flow; never reuse a code |\n| Token is valid but an operation is refused | Organization, client roles and person's authority | Diagnose authorization; do not request broader identity scopes |\n| Token is invalid or revoked | Client and token lifecycle | Refresh or reauthorize only through advertised behavior |\n\n## Close the change with non-secret evidence\n\nRetain the client identifier, non-secret secret prefixes, owner, environment,\ngrant, roles, identity scopes, redirect inventory, action and approval, old-\nsecret invalidation time, affected delegated authorization, successful expected\noperation, expected refusal and correlation evidence. Never attach a client\nsecret, authorization code, access/refresh token, Authorization header or\ncomplete authorization response.";
124
+ readonly markdown: "# Operate and revoke OAuth clients\n\nReview active clients as independent machine identities. Keep each client,\ncredential and delegated token associated with its owner, environment, subject\nand organization.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Identify the client, owner, environment, grant, deployed workloads, delegated users and non-secret secret prefix; know whether the change concerns client configuration, client credential or issued tokens | The intended client or token access changes, expected operation and refusal are re-proven, and unrelated integrations continue without broader authority |\n\n{{CONSUMER_FACT:source:consumer-fact:access-oauth-clients#markdown}}\n\nThe maintained registered-client lifecycle is:\n\n{{CONSUMER_FACT:source:consumer-fact:access-oauth-clients#statusMarkdown}}\n\n{{CONSUMER_FACT:source:consumer-fact:access-oauth-clients#lifecycleMarkdown}}\n\n{{CONSUMER_FACT:source:consumer-fact:access-oauth-clients#usageEvidenceMarkdown}}\n\n## Change the correct lifecycle layer\n\n~~~mermaid\nflowchart TD\n accTitle: Choose the OAuth lifecycle layer that needs to change\n accDescr: The operator distinguishes the registered client contract, its confidential secret, issued delegated tokens and the person's application membership, then changes and verifies only the affected layer.\n reason{\"What must change?\"}\n reason -->|\"Grant, roles, scopes, redirects or class\"| registration[\"Review or replace client registration\"]\n reason -->|\"Confidential secret\"| credential[\"Rotate with bounded invalidation\"]\n reason -->|\"One delegated authorization\"| token[\"Use published token revocation or reauthorization\"]\n reason -->|\"Person leaves organization\"| membership[\"Suspend/remove membership or use SCIM\"]\n registration --> verify[\"Repeat complete flow and authority proof\"]\n credential --> verify\n token --> verify\n membership --> verify\n~~~\n\nThese layers are related but not interchangeable. Rotating a client secret does\nnot by itself prove that an already issued delegated token is revoked. Removing\na person's organization access is a user-administration decision, not a reason\nto silently grant the client a machine role.\n\n## Review and change a client safely\n\nAt every review, answer these questions:\n\n- Is the owner and business purpose still current?\n- Does the grant still match who authorizes the work?\n- Are application roles limited to the exact operations still used?\n- Are identity scopes limited to claims the delegated client still needs?\n- Does every redirect and post-sign-out destination still belong to this client\n and environment?\n- Does the public/confidential classification match where the client now runs?\n- Is explicit consent still appropriate for the client's trust posture?\n- Do expiry, audit evidence, resource-server activity and active deployments\n support keeping it?\n\nA changed redirect, role, grant, identity scope, consent posture or token method\nchanges the security contract. Where the management surface does not safely\nsupport that transition in place, register a replacement client and migrate\ndeliberately instead of repurposing an established identity.\n\n## Rotate a confidential client secret\n\nRotate a confidential client secret through the administration operation\nprovided for that client. Deploy and verify the new secret before the previous\none becomes invalid when a handover is intended. For suspected compromise,\ninvalidate the previous secret promptly or remove the client; do not rely on\nan open-ended regenerate operation to contain exposure.\n\nRotation reissues the secret on the same client. A future invalidation time\ncreates a bounded overlap; the default is immediate invalidation. Regeneration\ncreates an open-ended overlap until a later reissue, so it is not incident\ncontainment.\n\n1. Inventory every workload instance using the confidential client.\n2. Choose the shortest practical invalidation time and record the owner.\n3. Store the one-time replacement directly in the approved secrets manager.\n4. Deploy it everywhere and complete a safe token plus operation proof.\n5. After invalidation, confirm the replacement succeeds and the previous secret\n is refused.\n\nIf disclosure is suspected and ownership is uncertain, remove the compromised\nclient through the supported administration lifecycle and register a protected\nreplacement. Do not leave an open-ended overlap while searching for consumers.\n\n## Revoke delegated access or retire a client\n\nUse the application's published token-revocation behavior when one delegated\nauthorization should end, and require a fresh authorization journey if the\nperson later restores it. Retire an entire integration by removing its client\nregistration and every deployed secret, then confirm new token issuance fails.\nSeparately suspend or remove the person's organization membership when their\napplication access must end; SSO or OAuth revocation alone is not the membership\nlifecycle.\n\nFor a suspected incident, treat client credential exposure and issued-token\nexposure as separate questions. Contain both applicable paths and review\nactivity for the affected client, person, organization and period.\n\nToken revocation follows [RFC 7009](https://www.rfc-editor.org/rfc/rfc7009): an\nunknown or already revoked token still receives a successful response so the\nendpoint does not become a token-validity oracle. Therefore **HTTP success is\nnot the final proof**. Retry one safe protected operation with the revoked token\nand verify that it is refused, then confirm a different unaffected client still\nworks. Confidential clients must authenticate to the revocation endpoint using\ntheir registered method; a bad client secret is refused before revocation.\n\n## Diagnose OAuth failures\n\n| Symptom | Check first | Safe response |\n| --- | --- | --- |\n| Discovery or registration is unavailable | Whether the capability is advertised here | Use an enabled onboarding path; do not probe undocumented endpoints |\n| Authorization request is rejected | Client, allowed grant, exact redirect and required proof | Correct the registered client or request |\n| Consent is denied or required | Client identity, claims and intended roles | Preserve the decision and explain or correct the request |\n| Code exchange fails | Issuer, redirect, proof, client class and token method | Restart the published flow; never reuse a code |\n| Token is valid but an operation is refused | Organization, client roles and person's authority | Diagnose authorization; do not request broader identity scopes |\n| Token is invalid or revoked | Client and token lifecycle | Refresh or reauthorize only through advertised behavior |\n\n## Close the change with non-secret evidence\n\nRetain the client identifier, non-secret secret prefixes, owner, environment,\ngrant, roles, identity scopes, redirect inventory, action and approval, old-\nsecret invalidation time, affected delegated authorization, successful expected\noperation, expected refusal and correlation evidence. Never attach a client\nsecret, authorization code, access/refresh token, Authorization header or\ncomplete authorization response.";
122
125
  }, {
123
126
  readonly managedPath: "user-administration.md";
124
127
  readonly unitRef: "technical-documentation:unit/user-administration";
@@ -183,47 +186,47 @@ export declare const APPLICATION_CONSUMER_DOCUMENTATION_AUTHORED_CONTENT_V1: rea
183
186
  readonly managedPath: "user-administration/scim-provisioning.md";
184
187
  readonly unitRef: "technical-documentation:unit/scim";
185
188
  readonly sourceRefs: readonly ["saas-technical-doc:engine-content/scim", "source:consumer-fact:organization-scim-provisioning"];
186
- readonly markdown: "# Provision users with SCIM\n\nSCIM lets an identity directory maintain a defined population of users and\norganization memberships. Choose it when your directory should own repeatable\njoiner, mover and leaver changes. The application supports **SCIM Users**, not\nSCIM Groups; a directory `department` can be mapped to one existing\norganization unit.\n\n> **SCIM provisions access; it does not sign people in.** Configure and prove\n> single sign-on separately. A directory-managed person needs both a correctly\n> provisioned membership and a working enterprise sign-in path.\n\n~~~mermaid\nflowchart LR\n accTitle: Adopt SCIM in four controlled stages\n accDescr: Configure the connection, map profile and unit data, validate with a small population, then operate and troubleshoot the live integration.\n configure[\"Configure lifecycle and credential\"] --> map[\"Map profile and unit data\"]\n map --> validate[\"Validate and roll out\"]\n validate --> operate[\"Operate and troubleshoot\"]\n~~~\n\n## How a directory change becomes application access\n\nProvisioning is not a single switch. A directory assignment passes through\nseveral independent decisions before a person can use the application:\n\n~~~mermaid\nsequenceDiagram\n accTitle: From directory assignment to usable application access\n accDescr: A directory administrator assigns a person, the identity provider sends a SCIM User request, the application validates the organization token and profile, maintains the identity and membership, optionally reconciles a mapped organization unit on supported operations, and responds. The person later signs in through a separate authentication journey and current membership and role determine access.\n actor Admin as Directory administrator\n participant Directory as Identity directory\n participant SCIM as Application SCIM service\n participant Access as Identity and membership\n participant Units as Organization units\n actor Person as Person\n Admin->>Directory: Assign person to the application\n Directory->>SCIM: Send SCIM User operation\n SCIM->>SCIM: Authenticate token and validate payload\n SCIM->>Access: Create or update identity and membership\n opt Department mapping on a supported operation\n SCIM->>Units: Reconcile mapped unit assignment\n end\n SCIM-->>Directory: Return SCIM result\n Person->>Access: Sign in through the configured method\n Access-->>Person: Evaluate current membership and role\n~~~\n\nThis journey separates six decisions that are often confused during a rollout:\n\n| Decision | Question the owners must answer |\n| --- | --- |\n| Provisioned population | Which directory assignment or group decides who is sent to the application? |\n| Identity matching | Which stable directory value identifies the same person after an email or name change? |\n| Initial access | Which non-administrative organization role should a newly provisioned person receive? |\n| Leaver behavior | What should happen to the application user and membership when the directory sends `active:false`? |\n| Unit authority | Should `department` merely describe the person, or authoritatively add and remove organization-unit access? |\n| Authentication | Which sign-in or SSO method will the person use after provisioning succeeds? |\n\n> **A successful SCIM response proves provisioning, not usable access.** Verify\n> the resulting membership, role and unit assignments, then ask the pilot person\n> to complete the separate sign-in journey.\n\n## Choose the stage you are working on\n\n| Your goal | Continue with |\n| --- | --- |\n| Understand the supported SCIM profile, payloads and operation behavior | [SCIM protocol and payload reference](/user-administration/scim-protocol-and-payloads) |\n| Decide lifecycle defaults and connect the directory | [Configure SCIM provisioning](/user-administration/scim-configure) |\n| Connect Microsoft Entra ID or a synchronized Active Directory population | [Connect Microsoft Entra ID](/user-administration/scim-microsoft-entra) |\n| Connect an Okta organization | [Connect Okta](/user-administration/scim-okta) |\n| Start from Active Directory Domain Services or another LDAP directory | [Connect an LDAP or Active Directory source](/user-administration/scim-ldap-and-active-directory) |\n| Map names, email and department-owned unit access | [Map SCIM profiles and organization units](/user-administration/scim-map-profile-and-units) |\n| Prove behavior with controlled users before broad enablement | [Validate and roll out SCIM](/user-administration/scim-validate-and-roll-out) |\n| Rotate credentials, investigate errors or recover a person | [Operate and troubleshoot SCIM](/user-administration/scim-operate-and-troubleshoot) |\n\n{{CONSUMER_FACT:source:consumer-fact:organization-scim-provisioning#markdown}}\n\n## Decide whether SCIM fits\n\nUse SCIM only when the directory will be the source of truth for the population,\nenterprise sign-in already works, and named owners can respond to provisioning\nfailures and credential changes. Keep people deliberately outside the directory\non the manual path. Do not let SCIM and an administrator compete to manage the\nsame membership or unit assignment.";
189
+ readonly markdown: "# Provision users with SCIM\n\nSCIM lets an identity directory maintain a defined population of users and\norganization memberships. Choose it when your directory should own repeatable\njoiner, mover and leaver changes. The application supports **SCIM Users** and\n**SCIM Groups**. A directory `department` can be mapped to one existing\norganization unit, and a directory group can become an organization unit of its\nown — see *Provision organization units from your directory*.\n\n> **SCIM provisions access; it does not sign people in.** Configure and prove\n> single sign-on separately. A directory-managed person needs both a correctly\n> provisioned membership and a working enterprise sign-in path.\n\n~~~mermaid\nflowchart LR\n accTitle: Adopt SCIM in four controlled stages\n accDescr: Configure the connection, map profile and unit data, validate with a small population, then operate and troubleshoot the live integration.\n configure[\"Configure lifecycle and credential\"] --> map[\"Map profile and unit data\"]\n map --> validate[\"Validate and roll out\"]\n validate --> operate[\"Operate and troubleshoot\"]\n~~~\n\n## How a directory change becomes application access\n\nProvisioning is not a single switch. A directory assignment passes through\nseveral independent decisions before a person can use the application:\n\n~~~mermaid\nsequenceDiagram\n accTitle: From directory assignment to usable application access\n accDescr: A directory administrator assigns a person, the identity provider sends a SCIM User request, the application validates the organization token and profile, maintains the identity and membership, optionally reconciles a mapped organization unit on supported operations, and responds. The person later signs in through a separate authentication journey and current membership and role determine access.\n actor Admin as Directory administrator\n participant Directory as Identity directory\n participant SCIM as Application SCIM service\n participant Access as Identity and membership\n participant Units as Organization units\n actor Person as Person\n Admin->>Directory: Assign person to the application\n Directory->>SCIM: Send SCIM User operation\n SCIM->>SCIM: Authenticate token and validate payload\n SCIM->>Access: Create or update identity and membership\n opt Department mapping on a supported operation\n SCIM->>Units: Reconcile mapped unit assignment\n end\n SCIM-->>Directory: Return SCIM result\n Person->>Access: Sign in through the configured method\n Access-->>Person: Evaluate current membership and role\n~~~\n\nThis journey separates six decisions that are often confused during a rollout:\n\n| Decision | Question the owners must answer |\n| --- | --- |\n| Provisioned population | Which directory assignment or group decides who is sent to the application? |\n| Identity matching | Which stable directory value identifies the same person after an email or name change? |\n| Initial access | Which non-administrative organization role should a newly provisioned person receive? |\n| Leaver behavior | What should happen to the application user and membership when the directory sends `active:false`? |\n| Unit authority | Should `department` merely describe the person, or authoritatively add and remove organization-unit access? |\n| Authentication | Which sign-in or SSO method will the person use after provisioning succeeds? |\n\n> **A successful SCIM response proves provisioning, not usable access.** Verify\n> the resulting membership, role and unit assignments, then ask the pilot person\n> to complete the separate sign-in journey.\n\n## Choose the stage you are working on\n\n| Your goal | Continue with |\n| --- | --- |\n| Understand the supported SCIM profile, payloads and operation behavior | [SCIM protocol and payload reference](/user-administration/scim-protocol-and-payloads) |\n| Decide lifecycle defaults and connect the directory | [Configure SCIM provisioning](/user-administration/scim-configure) |\n| Connect Microsoft Entra ID or a synchronized Active Directory population | [Connect Microsoft Entra ID](/user-administration/scim-microsoft-entra) |\n| Connect an Okta organization | [Connect Okta](/user-administration/scim-okta) |\n| Start from Active Directory Domain Services or another LDAP directory | [Connect an LDAP or Active Directory source](/user-administration/scim-ldap-and-active-directory) |\n| Map names, email and department-owned unit access | [Map SCIM profiles and organization units](/user-administration/scim-map-profile-and-units) |\n| Prove behavior with controlled users before broad enablement | [Validate and roll out SCIM](/user-administration/scim-validate-and-roll-out) |\n| Rotate credentials, investigate errors or recover a person | [Operate and troubleshoot SCIM](/user-administration/scim-operate-and-troubleshoot) |\n\n{{CONSUMER_FACT:source:consumer-fact:organization-scim-provisioning#markdown}}\n\n## Decide whether SCIM fits\n\nUse SCIM only when the directory will be the source of truth for the population,\nenterprise sign-in already works, and named owners can respond to provisioning\nfailures and credential changes. Keep people deliberately outside the directory\non the manual path. Do not let SCIM and an administrator compete to manage the\nsame membership or unit assignment.";
187
190
  }, {
188
191
  readonly managedPath: "user-administration/scim-protocol-and-payloads.md";
189
192
  readonly unitRef: "technical-documentation:unit/scim-protocol-and-payloads";
190
193
  readonly sourceRefs: readonly ["saas-technical-doc:engine-content/scim-protocol-and-payloads", "source:companion-projection:application-connection", "source:consumer-fact:organization-scim-provisioning"];
191
- readonly markdown: "# SCIM protocol and payload reference\n\nUse this page to decide whether a directory or provisioning bridge is compatible\nwith this application **before** configuring production users. The application\nimplements a focused SCIM 2.0 User service. It is not a generic LDAP endpoint and\nit does not implement SCIM Groups.\n\n## Supported profile at a glance\n\n| Contract | This application supports | Important boundary |\n| --- | --- | --- |\n| Protocol | SCIM 2.0 over HTTPS with `application/scim+json` | SCIM 1.1 and direct LDAP binds are not accepted |\n| Authentication | A dedicated organization SCIM bearer token | The token selects one organization; it is not a user session or ordinary API key |\n| Resources | `Users` plus SCIM discovery documents | `Groups` is not implemented; group assignment can scope which users the provider sends but must not call `/Groups` |\n| User operations | Create, list, read, full replace, partial update and deactivate; Bulk accepts up to 100 operations | Organization-unit reconciliation differs by operation, as shown below |\n| Filtering | User lookup filters with a published maximum result size of 200 | Test the provider’s exact matching query before broad rollout |\n| Password changes | Not supported | Use the configured human sign-in or SSO journey; do not synchronize directory passwords |\n| Sorting and ETags | Not supported | A provider must not require sorting or conditional ETag writes |\n| Request budget | 300 requests per minute for each SCIM token | A 429 response includes retry information; reduce concurrency rather than rotating addresses |\n\nThe public discovery documents are available beneath the SCIM base URL:\n\n~~~text\nGET /ServiceProviderConfig\nGET /Schemas\nGET /ResourceTypes\n~~~\n\nRead `ServiceProviderConfig` during compatibility testing instead of assuming\nthat every feature mentioned by the SCIM standards is implemented.\n\n## Follow one SCIM request through the application\n\n~~~mermaid\nsequenceDiagram\n accTitle: How the application processes one SCIM User request\n accDescr: The provider sends an authenticated User operation. The SCIM service uses the bearer token to select an organization, validates the operation and profile, matches or creates the identity, maintains the organization membership, performs organization-unit reconciliation only when configured and supported for that operation, and returns a SCIM response.\n participant Provider as Provisioning provider\n participant Endpoint as SCIM endpoint\n participant Scope as Organization boundary\n participant Identity as User and membership\n participant Unit as Organization-unit mapping\n Provider->>Endpoint: User request plus bearer token\n Endpoint->>Scope: Resolve token to one organization\n Scope-->>Endpoint: Authorized organization context\n Endpoint->>Endpoint: Validate operation and SCIM profile\n Endpoint->>Identity: Match, create or update\n opt Mapping enabled and operation supported\n Endpoint->>Unit: Reconcile exact department mapping\n end\n Endpoint-->>Provider: SCIM resource, list or error response\n~~~\n\nThe token establishes the organization boundary **before** the profile is\napplied. The service then validates the request, resolves the person, maintains\nthe organization membership and, for the operations shown below, may reconcile\norganization-unit assignments. The response does not create a browser session\nand does not prove that the person can complete SSO.\n\n### Compatibility questions to answer before configuration\n\n| Provider requirement | Compatible expectation |\n| --- | --- |\n| Discovery | The provider can read `ServiceProviderConfig`, `Schemas` and `ResourceTypes` and respect the advertised feature set |\n| Resource types | User provisioning works without calling `/Groups` |\n| Update behavior | The provider can operate with the documented PUT/PATCH consequences, especially when department controls unit access |\n| Authentication | The provider can send the dedicated bearer token in the HTTPS `Authorization` header |\n| Matching and pagination | Its exact user filter and result-window behavior work within the published limit |\n| Unsupported features | It does not require password synchronization, sorting or conditional ETag writes |\n| Request volume | It respects rate-limit responses and does not depend on Bulk for organization-unit reconciliation |\n\n## Understand the base URL\n\nThis is the complete base URL a provider needs. Everything below hangs off it:\n\n~~~text\n{{APPLICATION_CONNECTION_VALUE:scimBaseUrl}}\n~~~\n\nThe organization is not encoded in that URL. The bearer token identifies the\norganization and must therefore be unique to one provider connection and one\nenvironment.\n\n## Example User document\n\nThe following payload shows the fields used by the maintained profile mapping\nand optional organization-unit mapping. Replace every value with a controlled\ntest identity; never copy a real person into documentation or a support ticket.\n\n~~~json\n{\n \"schemas\": [\n \"urn:ietf:params:scim:schemas:core:2.0:User\",\n \"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User\"\n ],\n \"externalId\": \"directory-user-001\",\n \"userName\": \"alex.morgan@example.com\",\n \"active\": true,\n \"name\": {\n \"givenName\": \"Alex\",\n \"familyName\": \"Morgan\"\n },\n \"displayName\": \"Alex Morgan\",\n \"emails\": [{\n \"value\": \"alex.morgan@example.com\",\n \"type\": \"work\",\n \"primary\": true\n }],\n \"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User\": {\n \"department\": \"Engineering\"\n }\n}\n~~~\n\nThe email mapping may use `userName`, the primary email or another configured\nemail path. Department is read from the standard Enterprise User extension; a\ntop-level `department` is accepted as a compatibility fallback. Its value is\nmatched exactly, after trimming, against the organization-unit mapping.\n\n{{CONSUMER_FACT:source:consumer-fact:organization-scim-provisioning#attributeMappingMarkdown}}\n\n## Choose operations with their consequences visible\n\n| Provider operation | User/profile effect | Organization-unit effect |\n| --- | --- | --- |\n| `POST /Users` | Creates or links the person according to the lifecycle configuration | Reconciles an exact mapped department when unit mapping and a default unit role are configured |\n| `PUT /Users/{id}` | Replaces the maintained profile and active state | Performs authoritative unit reconciliation from the full department value |\n| `PATCH /Users/{id}` | Applies supported partial profile or active-state changes | **Does not currently reconcile organization units** |\n| `DELETE /Users/{id}` | Runs the configured deactivation behavior; it does not physically erase the person | Does not perform a department-to-unit reconciliation |\n| `POST /Bulk` | Executes supported user operations individually | **Does not currently reconcile organization units**, including Bulk PUT operations |\n\nThis difference matters with providers that normally send PATCH. Do not enable\nauthoritative department-to-unit mapping merely because user creation worked.\nCapture the operation used for a department move and confirm that the former\nunit assignment is actually removed.\n\n## Recognize a valid list and error response\n\nA successful lookup with no match is a 200 response containing an empty SCIM\nlist—not a 404:\n\n~~~json\n{\n \"schemas\": [\"urn:ietf:params:scim:api:messages:2.0:ListResponse\"],\n \"totalResults\": 0,\n \"startIndex\": 1,\n \"itemsPerPage\": 0,\n \"Resources\": []\n}\n~~~\n\nErrors use the SCIM error media type and may include a `scimType` of\n`invalidSyntax`, `invalidValue`, `uniqueness` or `tooMany`. Preserve the HTTP status, SCIM type, redacted detail, operation,\nprovider job identifier and time. Never preserve the bearer token.\n\n## Standards used by this profile\n\n- [RFC 7643 §4.1](https://www.rfc-editor.org/rfc/rfc7643.html#section-4.1)\n defines the SCIM User resource; [§4.3](https://www.rfc-editor.org/rfc/rfc7643.html#section-4.3)\n defines the Enterprise User extension used for `department`.\n- [RFC 7644 §3.4.2](https://www.rfc-editor.org/rfc/rfc7644.html#section-3.4.2)\n defines filtering; [§3.5.1](https://www.rfc-editor.org/rfc/rfc7644.html#section-3.5.1)\n and [§3.5.2](https://www.rfc-editor.org/rfc/rfc7644.html#section-3.5.2)\n distinguish full replacement from PATCH; [§3.7](https://www.rfc-editor.org/rfc/rfc7644.html#section-3.7)\n defines Bulk; and [§3.12](https://www.rfc-editor.org/rfc/rfc7644.html#section-3.12)\n defines SCIM error responses.\n- [RFC 6750 §2.1](https://www.rfc-editor.org/rfc/rfc6750.html#section-2.1)\n defines bearer-token transport in the `Authorization` header. The\n application’s SCIM token lifecycle and authorization policy remain\n application behavior, not a promise made by that RFC.\n\nUse these standards to understand the wire contract. Use this page and the\napplication’s discovery response to understand the implemented profile.";
194
+ readonly markdown: "# SCIM protocol and payload reference\n\nUse this page to decide whether a directory or provisioning bridge is compatible\nwith this application **before** configuring production users. The application\nimplements a focused SCIM 2.0 User and Group service. It is not a generic LDAP\nendpoint, and its Group resource maps to organization units rather than to roles.\n\n## Supported profile at a glance\n\n| Contract | This application supports | Important boundary |\n| --- | --- | --- |\n| Protocol | SCIM 2.0 over HTTPS with `application/scim+json` | SCIM 1.1 and direct LDAP binds are not accepted |\n| Authentication | A dedicated organization SCIM bearer token | The token selects one organization; it is not a user session or ordinary API key |\n| Resources | `Users`, `Groups` and SCIM discovery documents | A `Group` is an organization unit, not a role. It is available only once an administrator sets the unit role on the SCIM provisioning configuration; until then every `/Groups` request answers 403 |\n| User operations | Create, list, read, full replace, partial update and deactivate; Bulk accepts up to 100 User or Group operations | Organization-unit reconciliation differs by operation, as shown below |\n| Filtering | User lookup filters with a published maximum result size of 200 | Test the provider’s exact matching query before broad rollout |\n| Password changes | Not supported | Use the configured human sign-in or SSO journey; do not synchronize directory passwords |\n| Sorting and ETags | Not supported | A provider must not require sorting or conditional ETag writes |\n| Request budget | 6,000 requests per minute for each SCIM token, sized for the request bursts Microsoft Entra ID and Okta send (neither uses Bulk) | A 429 response carries an integer `Retry-After`; follow it rather than rotating addresses |\n\nThe public discovery documents are available beneath the SCIM base URL:\n\n~~~text\nGET /ServiceProviderConfig\nGET /Schemas\nGET /ResourceTypes\n~~~\n\nRead `ServiceProviderConfig` during compatibility testing instead of assuming\nthat every feature mentioned by the SCIM standards is implemented.\n\n## Follow one SCIM request through the application\n\n~~~mermaid\nsequenceDiagram\n accTitle: How the application processes one SCIM User request\n accDescr: The provider sends an authenticated User operation. The SCIM service uses the bearer token to select an organization, validates the operation and profile, matches or creates the identity, maintains the organization membership, performs organization-unit reconciliation only when configured and supported for that operation, and returns a SCIM response.\n participant Provider as Provisioning provider\n participant Endpoint as SCIM endpoint\n participant Scope as Organization boundary\n participant Identity as User and membership\n participant Unit as Organization-unit mapping\n Provider->>Endpoint: User request plus bearer token\n Endpoint->>Scope: Resolve token to one organization\n Scope-->>Endpoint: Authorized organization context\n Endpoint->>Endpoint: Validate operation and SCIM profile\n Endpoint->>Identity: Match, create or update\n opt Mapping enabled and operation supported\n Endpoint->>Unit: Reconcile exact department mapping\n end\n Endpoint-->>Provider: SCIM resource, list or error response\n~~~\n\nThe token establishes the organization boundary **before** the profile is\napplied. The service then validates the request, resolves the person, maintains\nthe organization membership and, for the operations shown below, may reconcile\norganization-unit assignments. The response does not create a browser session\nand does not prove that the person can complete SSO.\n\n### Compatibility questions to answer before configuration\n\n| Provider requirement | Compatible expectation |\n| --- | --- |\n| Discovery | The provider can read `ServiceProviderConfig`, `Schemas` and `ResourceTypes` and respect the advertised feature set |\n| Resource types | `/ResourceTypes` lists both `User` and `Group`. User provisioning works whether or not the provider calls `/Groups` |\n| Update behavior | The provider can operate with the documented PUT/PATCH consequences, especially when department controls unit access |\n| Authentication | The provider can send the dedicated bearer token in the HTTPS `Authorization` header |\n| Matching and pagination | Its exact user filter and result-window behavior work within the published limit |\n| Unsupported features | It does not require password synchronization, sorting or conditional ETag writes |\n| Request volume | It respects rate-limit responses and does not depend on Bulk for organization-unit reconciliation |\n\n## Understand the base URL\n\nThis is the complete base URL a provider needs. Everything below hangs off it:\n\n~~~text\n{{APPLICATION_CONNECTION_VALUE:scimBaseUrl}}\n~~~\n\nThe organization is not encoded in that URL. The bearer token identifies the\norganization and must therefore be unique to one provider connection and one\nenvironment.\n\n## Example User document\n\nThe following payload shows the fields used by the maintained profile mapping\nand optional organization-unit mapping. Replace every value with a controlled\ntest identity; never copy a real person into documentation or a support ticket.\n\n~~~json\n{\n \"schemas\": [\n \"urn:ietf:params:scim:schemas:core:2.0:User\",\n \"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User\"\n ],\n \"externalId\": \"directory-user-001\",\n \"userName\": \"alex.morgan@example.com\",\n \"active\": true,\n \"name\": {\n \"givenName\": \"Alex\",\n \"familyName\": \"Morgan\"\n },\n \"displayName\": \"Alex Morgan\",\n \"emails\": [{\n \"value\": \"alex.morgan@example.com\",\n \"type\": \"work\",\n \"primary\": true\n }],\n \"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User\": {\n \"department\": \"Engineering\"\n }\n}\n~~~\n\nThe email mapping may use `userName`, the primary email or another configured\nemail path. Department is read from the standard Enterprise User extension; a\ntop-level `department` is accepted as a compatibility fallback. Its value is\nmatched exactly, after trimming, against the organization-unit mapping.\n\n{{CONSUMER_FACT:source:consumer-fact:organization-scim-provisioning#attributeMappingMarkdown}}\n\n## Choose operations with their consequences visible\n\n| Provider operation | User/profile effect | Organization-unit effect |\n| --- | --- | --- |\n| `POST /Users` | Creates or links the person according to the lifecycle configuration | Reconciles an exact mapped department when unit mapping and a default unit role are configured |\n| `PUT /Users/{id}` | Replaces the maintained profile and active state | Performs authoritative unit reconciliation from the full department value |\n| `PATCH /Users/{id}` | Applies supported partial profile or active-state changes | Reconciles units only when the PATCH sets or removes the department; a PATCH that does not touch the department leaves unit assignments unchanged |\n| `DELETE /Users/{id}` | Runs the configured deactivation behavior; it does not physically erase the person | Does not perform a department-to-unit reconciliation |\n| `POST /Bulk` | Executes each User or Group operation individually, exactly as the same request would on its own | The same effect as the individual operation: a Bulk PUT reconciles like `PUT`, a Bulk PATCH like `PATCH`. A `bulkId:` reference to a resource created earlier in the same request is replaced by its id, so one request can create a user and add them to a new group |\n\nThis difference matters with providers that normally send PATCH. Do not enable\nauthoritative department-to-unit mapping merely because user creation worked.\nCapture the operation used for a department move and confirm that the former\nunit assignment is actually removed.\n\n## Recognize a valid list and error response\n\nA successful lookup with no match is a 200 response containing an empty SCIM\nlist—not a 404:\n\n~~~json\n{\n \"schemas\": [\"urn:ietf:params:scim:api:messages:2.0:ListResponse\"],\n \"totalResults\": 0,\n \"startIndex\": 1,\n \"itemsPerPage\": 0,\n \"Resources\": []\n}\n~~~\n\nErrors use the SCIM error media type and may include a `scimType` of\n`invalidSyntax`, `invalidValue`, `uniqueness` or `tooMany`. Preserve the HTTP status, SCIM type, redacted detail, operation,\nprovider job identifier and time. Never preserve the bearer token.\n\n## Standards used by this profile\n\n- [RFC 7643 §4.1](https://www.rfc-editor.org/rfc/rfc7643.html#section-4.1)\n defines the SCIM User resource; [§4.3](https://www.rfc-editor.org/rfc/rfc7643.html#section-4.3)\n defines the Enterprise User extension used for `department`.\n- [RFC 7644 §3.4.2](https://www.rfc-editor.org/rfc/rfc7644.html#section-3.4.2)\n defines filtering; [§3.5.1](https://www.rfc-editor.org/rfc/rfc7644.html#section-3.5.1)\n and [§3.5.2](https://www.rfc-editor.org/rfc/rfc7644.html#section-3.5.2)\n distinguish full replacement from PATCH; [§3.7](https://www.rfc-editor.org/rfc/rfc7644.html#section-3.7)\n defines Bulk; and [§3.12](https://www.rfc-editor.org/rfc/rfc7644.html#section-3.12)\n defines SCIM error responses.\n- [RFC 6750 §2.1](https://www.rfc-editor.org/rfc/rfc6750.html#section-2.1)\n defines bearer-token transport in the `Authorization` header. The\n application’s SCIM token lifecycle and authorization policy remain\n application behavior, not a promise made by that RFC.\n\nUse these standards to understand the wire contract. Use this page and the\napplication’s discovery response to understand the implemented profile.";
192
195
  }, {
193
196
  readonly managedPath: "user-administration/scim-configure.md";
194
197
  readonly unitRef: "technical-documentation:unit/scim-configure";
195
198
  readonly sourceRefs: readonly ["saas-technical-doc:engine-content/scim-configure", "source:companion-projection:application-connection", "source:consumer-fact:organization-scim-provisioning"];
196
- readonly markdown: "# Configure SCIM provisioning\n\nConfigure the lifecycle rules and a dedicated credential before you send any\nproduction user. This page is for an organization administrator working with\nthe identity team that owns the directory connection.\n\n## What you need and what success looks like\n\n| | |\n| --- | --- |\n| **Who performs this task** | An organization owner or administrator together with the identity-directory owner |\n| **Where the configuration applies** | One selected organization and one directory environment |\n| **Before you begin** | Prove enterprise sign-in, choose lifecycle defaults, create any mapped units and prepare a protected secret store |\n| **Successful result** | The provisioning configuration and a dedicated active token exist, and a controlled SCIM user operation produces the expected application state |\n\n## Open SCIM administration\n\n1. Select the organization the directory will manage.\n2. Open **Settings**, then the organization’s **User provisioning** area.\n3. Use **Provisioning** for lifecycle defaults, attribute mappings and unit\n mappings.\n4. Use **Tokens** to create and manage the directory credential.\n\nIf **User provisioning** is absent, do not infer that SCIM is enabled. Confirm\nthe organization entitlement and application capability with the application\nowner. For automation, use the SCIM configuration and token API references\nlinked from this section.\n\n## Confirm the prerequisites\n\n- The organization type allows SCIM. The provisioning record has no separate\n `scimEnabled` switch.\n- Enterprise sign-in works for a representative directory-managed person.\n- You have selected a least-privileged default organization role.\n- Any organization units referenced by the directory already exist.\n- You know whether trusted directory assertions verify email and whether\n directory deactivation should change application access.\n\n## Configure the lifecycle decisions\n\nThe configuration below is projected from the maintained SCIM resource\nspecification and schema. The API reference remains authoritative for its exact\nrequest shape; this table explains what each value changes operationally.\n\n{{CONSUMER_FACT:source:consumer-fact:organization-scim-provisioning#configurationMarkdown}}\n\nThe standard **Organization owner** and **Organization administrator** roles\ncannot be SCIM defaults. Review every custom role’s effective inheritance before\nusing it for automatic provisioning.\n\n### Example: cautious first configuration\n\n~~~json\n{\n \"autoCreateUsers\": true,\n \"autoVerifyEmail\": true,\n \"autoDeactivateUsers\": false,\n \"defaultRole\": \"ORG_MEMBER\",\n \"attributeMapping\": {\n \"email\": \"emails[primary eq true].value\",\n \"firstName\": \"name.givenName\",\n \"lastName\": \"name.familyName\",\n \"displayName\": \"displayName\"\n }\n}\n~~~\n\nThis example deliberately leaves automatic deactivation off for the first\ncontrolled tests. It is not a recommended permanent policy: before production,\ndecide who owns leaver access and prove the multi-organization consequence\ndescribed below. Replace the example role with one from this application’s\n[Roles and permissions](/user-administration/roles-and-permissions) page.\n\n## Create the directory credential\n\nUse the application’s public API origin with the SCIM base path:\n\n~~~text\n/api/v1/scim/v2\n~~~\n\nSend a dedicated bearer token:\n\n~~~http\nAuthorization: Bearer SCIM_TOKEN\n~~~\n\nCreate a separate token for each directory connection and environment. The\nplaintext secret is returned once; store it immediately in the identity\nprovider’s secret store. Keep it out of source control, screenshots, logs,\ntickets and reusable examples.\n\nThe current request budget is **300 requests per minute per token**. When the\nservice returns a rate limit, follow its retry information and reduce\nconcurrency instead of starting parallel retries.\n\n## Treat deactivation as a high-impact choice\n\nThe current deactivation path marks both the global user and the addressed\norganization membership inactive. For a person who belongs to several\norganizations, this can affect more than the directory-owned membership. Test\nthat case before production rollout. A later `active:true` does not prove that\nthe organization membership was restored; verify both layers before announcing\nrecovery.";
199
+ readonly markdown: "# Configure SCIM provisioning\n\nConfigure the lifecycle rules and a dedicated credential before you send any\nproduction user. This page is for an organization administrator working with\nthe identity team that owns the directory connection.\n\n## What you need and what success looks like\n\n| | |\n| --- | --- |\n| **Who performs this task** | An organization owner or administrator together with the identity-directory owner |\n| **Where the configuration applies** | One selected organization and one directory environment |\n| **Before you begin** | Prove enterprise sign-in, choose lifecycle defaults, create any mapped units and prepare a protected secret store |\n| **Successful result** | The provisioning configuration and a dedicated active token exist, and a controlled SCIM user operation produces the expected application state |\n\n## Open SCIM administration\n\n1. Select the organization the directory will manage.\n2. Open **Settings**, then the organization’s **User provisioning** area.\n3. Use **Provisioning** for lifecycle defaults, attribute mappings and unit\n mappings.\n4. Use **Tokens** to create and manage the directory credential.\n\nIf **User provisioning** is absent, do not infer that SCIM is enabled. Confirm\nthe organization entitlement and application capability with the application\nowner. For automation, use the SCIM configuration and token API references\nlinked from this section.\n\n## Confirm the prerequisites\n\n- The organization type allows SCIM. The provisioning record has no separate\n `scimEnabled` switch.\n- Enterprise sign-in works for a representative directory-managed person.\n- You have selected a least-privileged default organization role.\n- Any organization units referenced by the directory already exist.\n- You know whether trusted directory assertions verify email and whether\n directory deactivation should change application access.\n\n## Configure the lifecycle decisions\n\nThe configuration below is projected from the maintained SCIM resource\nspecification and schema. The API reference remains authoritative for its exact\nrequest shape; this table explains what each value changes operationally.\n\n{{CONSUMER_FACT:source:consumer-fact:organization-scim-provisioning#configurationMarkdown}}\n\nThe standard **Organization owner** and **Organization administrator** roles\ncannot be SCIM defaults. Review every custom role’s effective inheritance before\nusing it for automatic provisioning.\n\n### Example: cautious first configuration\n\n~~~json\n{\n \"autoCreateUsers\": true,\n \"autoVerifyEmail\": true,\n \"autoDeactivateUsers\": false,\n \"defaultRole\": \"ORG_MEMBER\",\n \"attributeMapping\": {\n \"email\": \"emails[primary eq true].value\",\n \"firstName\": \"name.givenName\",\n \"lastName\": \"name.familyName\",\n \"displayName\": \"displayName\"\n }\n}\n~~~\n\nThis example deliberately leaves automatic deactivation off for the first\ncontrolled tests. It is not a recommended permanent policy: before production,\ndecide who owns leaver access and prove the multi-organization consequence\ndescribed below. Replace the example role with one from this application’s\n[Roles and permissions](/user-administration/roles-and-permissions) page.\n\n## Create the directory credential\n\nUse the application’s public API origin with the SCIM base path:\n\n~~~text\n/api/v1/scim/v2\n~~~\n\nSend a dedicated bearer token:\n\n~~~http\nAuthorization: Bearer SCIM_TOKEN\n~~~\n\nCreate a separate token for each directory connection and environment. The\nplaintext secret is returned once; store it immediately in the identity\nprovider’s secret store. Keep it out of source control, screenshots, logs,\ntickets and reusable examples.\n\nThe current request budget is **6,000 requests per minute per token**. It is\nsized for how identity providers really push: neither Microsoft Entra ID nor\nOkta uses SCIM Bulk, so a first sync arrives as a burst of individual requests.\nWhen the service returns a rate limit, it states an integer `Retry-After` in\nseconds; follow it instead of starting parallel retries.\n\n## Treat deactivation as a high-impact choice\n\nDeactivation withdraws the person's membership in **this organization only**,\ntogether with the access that membership conferred. Their account and their\nmemberships in other organizations are not touched: one organization's\ndirectory cannot lock a person out of another.\n\nA later `active:true` restores the membership with the organization's\n**current default role**, not the roles the person held before. Re-grant any\nadditional role deliberately. A person whose account was disabled by the\napplication operator is not re-enabled by the directory; restoring them is the\noperator's decision.";
197
200
  }, {
198
201
  readonly managedPath: "user-administration/scim-microsoft-entra.md";
199
202
  readonly unitRef: "technical-documentation:unit/scim-microsoft-entra";
200
203
  readonly sourceRefs: readonly ["saas-technical-doc:engine-content/scim-microsoft-entra"];
201
- readonly markdown: "# Provision users from Microsoft Entra ID\n\nConnect one Microsoft Entra enterprise application to one application\norganization. Entra decides which assigned people should exist; SCIM creates or\nupdates their application identities and organization memberships. **This\nconnection provisions access—it does not configure how those people sign in.**\nConfigure and test single sign-on separately.\n\n~~~mermaid\nflowchart LR\n directory[\"Active Directory or another HR source\"] --> entra[\"Microsoft Entra ID\"]\n entra -->|\"SCIM 2.0 over HTTPS\"| endpoint[\"Application SCIM endpoint\"]\n endpoint --> identity[\"User profile\"]\n endpoint --> membership[\"Organization membership and role\"]\n endpoint -. \"department on supported operations\" .-> unit[\"Organization-unit assignments\"]\n~~~\n\nIf your source is on-premises Active Directory Domain Services, synchronize it\nto Entra first. The application does not accept LDAP traffic at its SCIM\nendpoint.\n\n## Before you configure Entra\n\n- Create a non-production organization or select a small pilot organization.\n- Verify that the pilot person can sign in by the organization’s intended\n authentication method.\n- Create the application’s SCIM provisioning configuration and a **dedicated\n token for this Entra connection**.\n- Choose a non-administrative default role. Do not provision broad access merely\n to make the first test pass.\n- Decide whether Entra’s `department` value should control organization-unit\n access. Leave unit mapping off until the operation behavior below is proven.\n\n## Create the enterprise application\n\n1. In the Microsoft Entra admin center, open **Enterprise applications** and\n create or select the application used for provisioning.\n2. Open **Provisioning**, choose an automatic provisioning mode, and start a new\n configuration.\n3. Set **Tenant URL** to the application’s public API origin followed by:\n\n ~~~text\n /api/v1/scim/v2\n ~~~\n\n4. Set **Secret Token** to the plaintext SCIM token returned by the application.\n It is a bearer credential; store it in Entra and your approved secret-recovery\n process, not in a ticket or documentation screenshot.\n5. Run **Test Connection**.\n\nEntra’s connection test queries a randomly generated, non-existent user. A\ncorrect empty result is HTTP 200 with a SCIM `ListResponse` and zero resources.\nThat proves URL, TLS, token and basic query compatibility. **It does not prove\nrole assignment, deactivation, department changes or sign-in.**\n\n## Configure the user mappings\n\nKeep the first mapping small and observable:\n\n| Entra source | SCIM target | Decision to verify |\n| --- | --- | --- |\n| `userPrincipalName` or a verified mail attribute | `userName` | Must be stable and unique for the person |\n| `mail` | `emails[type eq \"work\"].value` | Must resolve to an admitted organization domain when domain restrictions exist |\n| `givenName` | `name.givenName` | Check accents and empty values |\n| `surname` | `name.familyName` | Check the real payload, not the portal preview alone |\n| `displayName` | `displayName` | Decide which system owns later changes |\n| Account-enabled expression | `active` | Test disable and re-enable as separate access events |\n| `department` | Enterprise User `department` | Enable only if department is an access-control authority |\n\nThis application currently exposes **Users**, not SCIM **Groups**. Disable group\nobject provisioning and Push Groups-style expectations. Entra groups may still\nbe useful on the Entra side to decide who is assigned to the enterprise\napplication, but they are not imported as application groups.\n\n## Treat department-to-unit mapping as a controlled rollout\n\nThe application reconciles organization units on direct `POST /Users` and full\n`PUT /Users/{id}` operations. It does **not** currently reconcile units on\n`PATCH` or `Bulk`. Entra can use PATCH for attribute changes, so a successful\nprofile update does not prove that moving a person between departments removed\ntheir former unit access.\n\nBefore making department authoritative:\n\n1. Map one test department to one existing organization unit.\n2. Use **Provision on demand** for a pilot person and record the SCIM operation\n visible in the application/provider evidence.\n3. Change the person’s department.\n4. Confirm both the new assignment and removal of the old assignment in the\n application—not only a successful Entra job.\n5. If Entra sends PATCH, leave automatic unit reconciliation disabled until the\n application supports that operation or your integration deliberately sends a\n tested full replacement.\n\n## Roll out and operate\n\n- Start with **Sync only assigned users and groups** and assign a small pilot\n population. This scopes Entra’s source population; it does not add SCIM Group\n support to the application.\n- Verify in the application: user profile, membership status, organization role,\n unit assignments and sign-in.\n- Review Entra provisioning logs for the request and response associated with\n each pilot person. Preserve provider job identifiers, not bearer tokens.\n- Configure provisioning-failure notifications and review Microsoft’s\n accidental-deletion prevention before broad assignment.\n- Rotate a token as an immediate credential cutover: update Entra promptly and\n run the connection test again.\n\n## Microsoft documentation to keep with the runbook\n\n- Use Microsoft’s [provision users and groups with SCIM](https://learn.microsoft.com/en-us/entra/identity/app-provisioning/use-scim-to-provision-users-and-groups)\n guide for current Entra portal controls, attribute mappings, test connection\n and provisioning behavior. The application-specific limits on this page\n still take precedence over generic provider capabilities.\n- Use [how Microsoft Entra provisioning works](https://learn.microsoft.com/en-us/entra/identity/app-provisioning/how-provisioning-works)\n to understand the provider’s synchronization cycle and the path from a\n connected source such as Active Directory to an enterprise application.\n\nRecord the reviewed provider-documentation date in the production runbook;\nportal labels and provider behavior can change independently of the application.";
204
+ readonly markdown: "# Provision users from Microsoft Entra ID\n\nConnect one Microsoft Entra enterprise application to one application\norganization. Entra decides which assigned people should exist; SCIM creates or\nupdates their application identities and organization memberships. **This\nconnection provisions access—it does not configure how those people sign in.**\nConfigure and test single sign-on separately.\n\n~~~mermaid\nflowchart LR\n directory[\"Active Directory or another HR source\"] --> entra[\"Microsoft Entra ID\"]\n entra -->|\"SCIM 2.0 over HTTPS\"| endpoint[\"Application SCIM endpoint\"]\n endpoint --> identity[\"User profile\"]\n endpoint --> membership[\"Organization membership and role\"]\n endpoint -. \"department on supported operations\" .-> unit[\"Organization-unit assignments\"]\n~~~\n\nIf your source is on-premises Active Directory Domain Services, synchronize it\nto Entra first. The application does not accept LDAP traffic at its SCIM\nendpoint.\n\n## Before you configure Entra\n\n- Create a non-production organization or select a small pilot organization.\n- Verify that the pilot person can sign in by the organization’s intended\n authentication method.\n- Create the application’s SCIM provisioning configuration and a **dedicated\n token for this Entra connection**.\n- Choose a non-administrative default role. Do not provision broad access merely\n to make the first test pass.\n- Decide whether Entra’s `department` value should control organization-unit\n access. Leave unit mapping off until the operation behavior below is proven.\n\n## Create the enterprise application\n\n1. In the Microsoft Entra admin center, open **Enterprise applications** and\n create or select the application used for provisioning.\n2. Open **Provisioning**, choose an automatic provisioning mode, and start a new\n configuration.\n3. Set **Tenant URL** to the application’s public API origin followed by:\n\n ~~~text\n /api/v1/scim/v2\n ~~~\n\n4. Set **Secret Token** to the plaintext SCIM token returned by the application.\n It is a bearer credential; store it in Entra and your approved secret-recovery\n process, not in a ticket or documentation screenshot.\n5. Run **Test Connection**.\n\nEntra’s connection test queries a randomly generated, non-existent user. A\ncorrect empty result is HTTP 200 with a SCIM `ListResponse` and zero resources.\nThat proves URL, TLS, token and basic query compatibility. **It does not prove\nrole assignment, deactivation, department changes or sign-in.**\n\n## Configure the user mappings\n\nKeep the first mapping small and observable:\n\n| Entra source | SCIM target | Decision to verify |\n| --- | --- | --- |\n| `userPrincipalName` or a verified mail attribute | `userName` | Must be stable and unique for the person |\n| `mail` | `emails[type eq \"work\"].value` | Must resolve to an admitted organization domain when domain restrictions exist |\n| `givenName` | `name.givenName` | Check accents and empty values |\n| `surname` | `name.familyName` | Check the real payload, not the portal preview alone |\n| `displayName` | `displayName` | Decide which system owns later changes |\n| Account-enabled expression | `active` | Test disable and re-enable as separate access events |\n| `department` | Enterprise User `department` | Enable only if department is an access-control authority |\n\nThis application exposes **Users** and **Groups**. A pushed Entra group becomes\nan organization UNIT, and its members become assignments in that unit carrying\nthe unit role configured on the SCIM provisioning configuration — it does not\nbecome a role or a permission set. Enable group provisioning only if you intend\nyour directory's groups to define unit access; leave it off and Entra groups\nremain purely an Entra-side way to decide who is assigned to the enterprise\napplication.\n\nTwo consequences to plan for. A group this application did not create is never\nadopted, so an Entra group whose name matches a unit an administrator authored\ncreates a second unit rather than taking over the first. And a group Entra\ndeletes takes its unit, and every assignment in it, with it.\n\nWhile the directory is connected, a unit it created is **managed by the\ndirectory**: its name and its members are refused if changed in this\napplication, because the next push would put them back. The organization-units\nscreen marks such a unit with its source (SCIM) and the directory's own group\nidentifier. Rename the group, or change who is in it, in Entra. An assignment's\nunit role, and the unit's code, type, status and position, are not\ndirectory-managed and stay editable here. If the directory is disconnected —\nevery SCIM token revoked — the unit becomes editable like any other.\n\n## Treat department-to-unit mapping as a controlled rollout\n\nThe application reconciles organization units on `POST /Users`, on full\n`PUT /Users/{id}`, and on a `PATCH` that sets or removes the department — and\non the same operations inside `Bulk`. A PATCH that does not touch the department\nleaves unit assignments unchanged. Entra sends PATCH for attribute changes, so\nconfirm that a department move actually reaches the application as a department\nchange before relying on it to remove former unit access.\n\nBefore making department authoritative:\n\n1. Map one test department to one existing organization unit.\n2. Use **Provision on demand** for a pilot person and record the SCIM operation\n visible in the application/provider evidence.\n3. Change the person’s department.\n4. Confirm both the new assignment and removal of the old assignment in the\n application—not only a successful Entra job.\n5. If Entra sends PATCH, leave automatic unit reconciliation disabled until the\n application supports that operation or your integration deliberately sends a\n tested full replacement.\n\n## Roll out and operate\n\n- Start with **Sync only assigned users and groups** and assign a small pilot\n population. This scopes Entra’s source population; it does not add SCIM Group\n support to the application.\n- Verify in the application: user profile, membership status, organization role,\n unit assignments and sign-in.\n- Review Entra provisioning logs for the request and response associated with\n each pilot person. Preserve provider job identifiers, not bearer tokens.\n- Configure provisioning-failure notifications and review Microsoft’s\n accidental-deletion prevention before broad assignment.\n- Rotate a token as an immediate credential cutover: update Entra promptly and\n run the connection test again.\n\n## Microsoft documentation to keep with the runbook\n\n- Use Microsoft’s [provision users and groups with SCIM](https://learn.microsoft.com/en-us/entra/identity/app-provisioning/use-scim-to-provision-users-and-groups)\n guide for current Entra portal controls, attribute mappings, test connection\n and provisioning behavior. The application-specific limits on this page\n still take precedence over generic provider capabilities.\n- Use [how Microsoft Entra provisioning works](https://learn.microsoft.com/en-us/entra/identity/app-provisioning/how-provisioning-works)\n to understand the provider’s synchronization cycle and the path from a\n connected source such as Active Directory to an enterprise application.\n\nRecord the reviewed provider-documentation date in the production runbook;\nportal labels and provider behavior can change independently of the application.";
202
205
  }, {
203
206
  readonly managedPath: "user-administration/scim-okta.md";
204
207
  readonly unitRef: "technical-documentation:unit/scim-okta";
205
208
  readonly sourceRefs: readonly ["saas-technical-doc:engine-content/scim-okta"];
206
- readonly markdown: "# Provision users from Okta\n\nUse an Okta SCIM 2.0 application to create, update and deactivate people in one\napplication organization. The Okta assignment determines who is provisioned;\nthe application’s SCIM configuration determines the role and lifecycle effects.\nSign-on configuration remains a separate SSO decision.\n\n~~~mermaid\nflowchart LR\n accTitle: Keep Okta assignment, provisioning and application access distinct\n accDescr: An Okta administrator assigns a person or population to the Okta application. Okta sends SCIM User operations to the application. The application maintains the user profile and organization membership, applies the configured default role, and optionally reconciles a mapped department on supported operations. The person signs in through a separately configured method.\n source[\"Okta user and assignment\"] --> provision[\"Okta provisioning connector\"]\n provision -->|\"SCIM User operations\"| endpoint[\"Application SCIM endpoint\"]\n endpoint --> profile[\"User profile\"]\n endpoint --> membership[\"Organization membership and default role\"]\n endpoint -. \"mapped department on supported operations\" .-> units[\"Organization-unit access\"]\n signin[\"Separate sign-in or SSO journey\"] --> membership\n~~~\n\nThe Okta assignment defines the population. It does not choose the\napplication role, import an Okta group as an application group, or prove that\nthe person can sign in. Verify those outcomes separately during the pilot.\n\n## Choose the correct Okta integration shape\n\nFor a private connection, create or use a **SCIM 2.0 Test App (Header Auth)** or\nanother Okta application whose provisioning connector lets you supply a SCIM\nbase URL and bearer token. If the application later has a reviewed Okta\nIntegration Network entry, follow that entry instead of duplicating it.\n\nThe application accepts SCIM **User** resources. It does not currently expose a\nSCIM Group resource, so do not enable Push Groups or depend on group-object\nimports. An Okta group can still control which users are assigned to the Okta\napplication.\n\n## Connect Okta\n\n1. In the Okta Admin Console, open the application’s **Provisioning** settings.\n2. Enable API integration and choose bearer/header authentication.\n3. Set the SCIM connector base URL to the application’s public API origin plus\n `/api/v1/scim/v2`.\n4. Paste a dedicated application-issued SCIM token into the API token field.\n5. Run **Test API Credentials**.\n\nThe credential test is a transport and authorization test. Complete a pilot\ncreate, update and deactivate before treating the connection as ready.\n\n## Configure provisioning actions\n\nEnable only the actions you are prepared to verify:\n\n| Okta **To App** action | Application effect to test |\n| --- | --- |\n| Create Users | Creates or links the user, then creates the organization membership with the configured default role |\n| Update User Attributes | Updates maintained profile values; inspect whether Okta used PUT or PATCH |\n| Deactivate Users | Normally sends `active:false`; verify the application user and organization membership consequences |\n| Sync Password | **Keep disabled.** The SCIM service does not accept password changes |\n\nUse a stable, unique Okta attribute for `userName`. Map the work email, given\nname, family name and display name explicitly. When verified-domain restrictions\nexist, ensure the resolved work email is admitted before the pilot.\n\n### Department and organization units\n\nMap Okta’s department to the SCIM Enterprise User extension only when it is\nauthoritative enough to change access. Then map exact department values to\nexisting application organization units.\n\n> **Operation limitation:** organization-unit reconciliation currently runs for\n> direct user creation and full replacement. It does not run for PATCH or Bulk.\n> Capture the operation Okta sends for a department change and prove that the\n> old unit assignment is removed before production rollout.\n\n## Prove one complete lifecycle\n\n1. Assign one pilot user to the Okta application.\n2. Confirm the person appears in the intended application organization with the\n approved role—not an administrator role.\n3. Change one mapped profile value and confirm it in the application.\n4. If unit mapping is enabled, move the pilot between two mapped departments and\n confirm both addition and removal.\n5. Unassign or deactivate the pilot. Confirm the user and membership state in\n the application and verify the effect on any other organization membership.\n6. Reassign the pilot. Confirm that the organization membership is usable again;\n a globally active user alone is not sufficient proof.\n\nUse Okta’s **System Log** and provisioning task details to correlate failures.\nRecord time, Okta user/application identifiers, SCIM operation, HTTP status,\nredacted SCIM error and resulting application state. Never record the API token.\n\n## Okta documentation to keep with the runbook\n\n- Use Okta’s [connect a private SCIM integration](https://developer.okta.com/docs/guides/scim-provisioning-integration-connect/main/)\n guide for current Admin Console fields and connector setup.\n- Use the [Okta SCIM protocol reference](https://developer.okta.com/docs/api/openapi/okta-scim/guides)\n when diagnosing the operation, filter, payload or response Okta expects.\n- Use [Understanding SCIM](https://developer.okta.com/docs/concepts/scim/)\n to align directory and application owners on assignment, provisioning and\n deprovisioning responsibilities.\n\nKeep the application profile on this page beside those provider references:\nOkta’s support for a feature does not mean this application exposes it.";
209
+ readonly markdown: "# Provision users from Okta\n\nUse an Okta SCIM 2.0 application to create, update and deactivate people in one\napplication organization. The Okta assignment determines who is provisioned;\nthe application’s SCIM configuration determines the role and lifecycle effects.\nSign-on configuration remains a separate SSO decision.\n\n~~~mermaid\nflowchart LR\n accTitle: Keep Okta assignment, provisioning and application access distinct\n accDescr: An Okta administrator assigns a person or population to the Okta application. Okta sends SCIM User operations to the application. The application maintains the user profile and organization membership, applies the configured default role, and optionally reconciles a mapped department on supported operations. The person signs in through a separately configured method.\n source[\"Okta user and assignment\"] --> provision[\"Okta provisioning connector\"]\n provision -->|\"SCIM User operations\"| endpoint[\"Application SCIM endpoint\"]\n endpoint --> profile[\"User profile\"]\n endpoint --> membership[\"Organization membership and default role\"]\n endpoint -. \"mapped department on supported operations\" .-> units[\"Organization-unit access\"]\n signin[\"Separate sign-in or SSO journey\"] --> membership\n~~~\n\nThe Okta assignment defines the population. It does not choose the\napplication role, import an Okta group as an application group, or prove that\nthe person can sign in. Verify those outcomes separately during the pilot.\n\n## Choose the correct Okta integration shape\n\nFor a private connection, create or use a **SCIM 2.0 Test App (Header Auth)** or\nanother Okta application whose provisioning connector lets you supply a SCIM\nbase URL and bearer token. If the application later has a reviewed Okta\nIntegration Network entry, follow that entry instead of duplicating it.\n\nThe application accepts SCIM **User** and **Group** resources. A pushed group\nbecomes an organization UNIT rather than a role: its members receive the unit\nrole configured on the SCIM provisioning configuration, which confines which\nrecords they reach and never widens their permissions. Enable Push Groups only\nif that is what you intend; otherwise an Okta group can still control which users\nare assigned to the Okta application without being pushed.\n\nNote that Okta creates a group without an `externalId`, which this application\nhandles: the group is identified by the id returned when it was created.\n\nA pushed group's name and members are managed by Okta while it stays connected:\nchanging either in this application is refused, because the next push would\nrestore it. Make those changes in Okta; unit roles and the unit's other settings\nstay editable here.\n\n## Connect Okta\n\n1. In the Okta Admin Console, open the application’s **Provisioning** settings.\n2. Enable API integration and choose bearer/header authentication.\n3. Set the SCIM connector base URL to the application’s public API origin plus\n `/api/v1/scim/v2`.\n4. Paste a dedicated application-issued SCIM token into the API token field.\n5. Run **Test API Credentials**.\n\nThe credential test is a transport and authorization test. Complete a pilot\ncreate, update and deactivate before treating the connection as ready.\n\n## Configure provisioning actions\n\nEnable only the actions you are prepared to verify:\n\n| Okta **To App** action | Application effect to test |\n| --- | --- |\n| Create Users | Creates or links the user, then creates the organization membership with the configured default role |\n| Update User Attributes | Updates maintained profile values; inspect whether Okta used PUT or PATCH |\n| Deactivate Users | Normally sends `active:false`; verify the application user and organization membership consequences |\n| Sync Password | **Keep disabled.** The SCIM service does not accept password changes |\n\nUse a stable, unique Okta attribute for `userName`. Map the work email, given\nname, family name and display name explicitly. When verified-domain restrictions\nexist, ensure the resolved work email is admitted before the pilot.\n\n### Department and organization units\n\nMap Okta’s department to the SCIM Enterprise User extension only when it is\nauthoritative enough to change access. Then map exact department values to\nexisting application organization units.\n\n> **Operation boundary:** organization-unit reconciliation runs on user creation,\n> full replacement, and a PATCH that sets or removes the department, including the\n> same operations inside Bulk. A PATCH that does not touch the department leaves\n> unit assignments unchanged. Capture the operation Okta sends for a department\n> change and prove that the old unit assignment is removed before production rollout.\n\n## Prove one complete lifecycle\n\n1. Assign one pilot user to the Okta application.\n2. Confirm the person appears in the intended application organization with the\n approved role—not an administrator role.\n3. Change one mapped profile value and confirm it in the application.\n4. If unit mapping is enabled, move the pilot between two mapped departments and\n confirm both addition and removal.\n5. Unassign or deactivate the pilot. Confirm the user and membership state in\n the application and verify the effect on any other organization membership.\n6. Reassign the pilot. Confirm that the organization membership is usable again;\n a globally active user alone is not sufficient proof.\n\nUse Okta’s **System Log** and provisioning task details to correlate failures.\nRecord time, Okta user/application identifiers, SCIM operation, HTTP status,\nredacted SCIM error and resulting application state. Never record the API token.\n\n## Okta documentation to keep with the runbook\n\n- Use Okta’s [connect a private SCIM integration](https://developer.okta.com/docs/guides/scim-provisioning-integration-connect/main/)\n guide for current Admin Console fields and connector setup.\n- Use the [Okta SCIM protocol reference](https://developer.okta.com/docs/api/openapi/okta-scim/guides)\n when diagnosing the operation, filter, payload or response Okta expects.\n- Use [Understanding SCIM](https://developer.okta.com/docs/concepts/scim/)\n to align directory and application owners on assignment, provisioning and\n deprovisioning responsibilities.\n\nKeep the application profile on this page beside those provider references:\nOkta’s support for a feature does not mean this application exposes it.";
207
210
  }, {
208
211
  readonly managedPath: "user-administration/scim-ldap-and-active-directory.md";
209
212
  readonly unitRef: "technical-documentation:unit/scim-ldap-and-active-directory";
210
213
  readonly sourceRefs: readonly ["saas-technical-doc:engine-content/scim-ldap-and-active-directory"];
211
- readonly markdown: "# Provision from LDAP or Active Directory\n\nLDAP and SCIM solve different parts of directory integration. LDAP is a\ndirectory access protocol; this application exposes an HTTPS SCIM 2.0 service.\n**Do not send LDAP requests to the SCIM URL and do not expose an internal LDAP\nserver to the application.** Place a provisioning service or controlled bridge\nbetween the source directory and SCIM.\n\n## Choose an architecture\n\n~~~mermaid\nflowchart LR\n subgraph source[\"Directory source\"]\n ad[\"Active Directory Domain Services\"]\n ldap[\"LDAP directory\"]\n end\n ad --> entra[\"Microsoft Entra synchronization and provisioning\"]\n ldap --> bridge[\"Managed provisioning agent or owned bridge\"]\n entra -->|\"HTTPS + SCIM 2.0\"| app[\"Application SCIM Users service\"]\n bridge -->|\"HTTPS + SCIM 2.0\"| app\n~~~\n\n| Source situation | Practical route |\n| --- | --- |\n| Active Directory identities already synchronized to Microsoft Entra ID | Configure Entra enterprise-application provisioning and let Entra emit SCIM |\n| LDAP identities governed through Okta | Use the supported Okta directory/agent path, then configure Okta’s application provisioning connector |\n| Another LDAP directory with a supported identity-governance product | Use that product’s SCIM connector after validating this application’s implemented profile |\n| No provider can emit the required SCIM profile | Build and operate a narrow LDAP-to-SCIM bridge with explicit ownership, tests and monitoring |\n\nThe last option is software you own. It should not be treated as a configuration\nscript: it becomes an identity lifecycle and access-control component.\n\n## Define the attribute transformation\n\nRead the source directory using its documented schema, then emit a standards-\ncompliant SCIM User. A common starting point is:\n\n| LDAP / Active Directory value | SCIM value | Required decision |\n| --- | --- | --- |\n| `userPrincipalName` or approved login attribute | `userName` | Stable uniqueness and rename policy |\n| `mail` | `emails[type eq \"work\"].value` | Missing email and verified-domain policy |\n| `givenName` | `name.givenName` | Empty and internationalized values |\n| `sn` | `name.familyName` | Empty-value behavior |\n| `displayName` | `displayName` | Which system owns later edits |\n| `department` | Enterprise User `department` | Whether it is authoritative for unit access |\n| Disabled-account state | `active:false` | Global user and membership deactivation consequence |\n\nThese are mapping decisions, not guaranteed attributes in every LDAP schema.\nInspect representative entries and document the source object classes,\nattribute ownership and null behavior.\n\n### Example SCIM document emitted by a bridge\n\n~~~json\n{\n \"schemas\": [\n \"urn:ietf:params:scim:schemas:core:2.0:User\",\n \"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User\"\n ],\n \"externalId\": \"4fd9cc8d-7f42-4ab4-9036-07c94b2ac663\",\n \"userName\": \"alex.morgan@example.com\",\n \"active\": true,\n \"name\": {\n \"givenName\": \"Alex\",\n \"familyName\": \"Morgan\"\n },\n \"emails\": [\n { \"type\": \"work\", \"primary\": true, \"value\": \"alex.morgan@example.com\" }\n ],\n \"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User\": {\n \"department\": \"Engineering\"\n }\n}\n~~~\n\n## Requirements for an owned bridge\n\nA production bridge needs all of the following:\n\n- TLS validation for LDAP and HTTPS, and secrets held in an approved vault;\n- a durable relationship between source identifiers, SCIM `externalId` and the\n application’s returned SCIM resource identifier;\n- deterministic create-versus-update matching and a documented rename policy;\n- bounded pagination, checkpoints, retry with backoff and idempotent replay;\n- explicit handling for disable, delete, restore and a person missing from a\n source query;\n- redacted operational evidence linking one source change to one SCIM response;\n- reconciliation that detects drift rather than repeatedly overwriting it;\n- a tested response to rate limiting, token rotation and partial batch failure.\n\nDo not use Bulk for a first implementation merely for speed. The application\nsupports a bounded Bulk request, but Bulk currently does not perform\norganization-unit reconciliation. Start with observable individual operations.\n\n## Validate before production\n\nRun a positive and negative lifecycle: create an admitted user, reject a user\nfrom a disallowed domain when restrictions exist, update the profile, change a\ndepartment, disable the source account and restore it. At every step compare\nthe directory state, emitted SCIM document, HTTP result, application user,\nmembership, role and unit assignments.\n\n## Standards and provider documentation\n\n- [RFC 4511](https://www.rfc-editor.org/rfc/rfc4511.html) defines LDAP’s\n protocol. It explains the source-side boundary; it does not make an LDAP\n directory a SCIM provider.\n- [RFC 7643](https://www.rfc-editor.org/rfc/rfc7643.html) and\n [RFC 7644](https://www.rfc-editor.org/rfc/rfc7644.html) define the SCIM\n resource and protocol boundaries the bridge must emit.\n- Microsoft documents the path from connected systems to SCIM in\n [How application provisioning works](https://learn.microsoft.com/en-us/entra/identity/app-provisioning/how-provisioning-works).\n- For an Okta-governed directory, compare the bridge design with Okta’s\n [private SCIM integration guide](https://developer.okta.com/docs/guides/scim-provisioning-integration-connect/main/)\n and [SCIM protocol reference](https://developer.okta.com/docs/api/openapi/okta-scim/guides).\n\nThese references define the systems on either side of the bridge. The bridge’s\nmatching, checkpoint, retry and reconciliation behavior remains an operated\ncomponent your organization must specify and test.";
214
+ readonly markdown: "# Provision from LDAP or Active Directory\n\nLDAP and SCIM solve different parts of directory integration. LDAP is a\ndirectory access protocol; this application exposes an HTTPS SCIM 2.0 service.\n**Do not send LDAP requests to the SCIM URL and do not expose an internal LDAP\nserver to the application.** Place a provisioning service or controlled bridge\nbetween the source directory and SCIM.\n\n## Choose an architecture\n\n~~~mermaid\nflowchart LR\n subgraph source[\"Directory source\"]\n ad[\"Active Directory Domain Services\"]\n ldap[\"LDAP directory\"]\n end\n ad --> entra[\"Microsoft Entra synchronization and provisioning\"]\n ldap --> bridge[\"Managed provisioning agent or owned bridge\"]\n entra -->|\"HTTPS + SCIM 2.0\"| app[\"Application SCIM Users service\"]\n bridge -->|\"HTTPS + SCIM 2.0\"| app\n~~~\n\n| Source situation | Practical route |\n| --- | --- |\n| Active Directory identities already synchronized to Microsoft Entra ID | Configure Entra enterprise-application provisioning and let Entra emit SCIM |\n| LDAP identities governed through Okta | Use the supported Okta directory/agent path, then configure Okta’s application provisioning connector |\n| Another LDAP directory with a supported identity-governance product | Use that product’s SCIM connector after validating this application’s implemented profile |\n| No provider can emit the required SCIM profile | Build and operate a narrow LDAP-to-SCIM bridge with explicit ownership, tests and monitoring |\n\nThe last option is software you own. It should not be treated as a configuration\nscript: it becomes an identity lifecycle and access-control component.\n\n## Define the attribute transformation\n\nRead the source directory using its documented schema, then emit a standards-\ncompliant SCIM User. A common starting point is:\n\n| LDAP / Active Directory value | SCIM value | Required decision |\n| --- | --- | --- |\n| `userPrincipalName` or approved login attribute | `userName` | Stable uniqueness and rename policy |\n| `mail` | `emails[type eq \"work\"].value` | Missing email and verified-domain policy |\n| `givenName` | `name.givenName` | Empty and internationalized values |\n| `sn` | `name.familyName` | Empty-value behavior |\n| `displayName` | `displayName` | Which system owns later edits |\n| `department` | Enterprise User `department` | Whether it is authoritative for unit access |\n| Disabled-account state | `active:false` | Withdraws the membership in this organization only; the account and other memberships stay |\n\nThese are mapping decisions, not guaranteed attributes in every LDAP schema.\nInspect representative entries and document the source object classes,\nattribute ownership and null behavior.\n\n### Example SCIM document emitted by a bridge\n\n~~~json\n{\n \"schemas\": [\n \"urn:ietf:params:scim:schemas:core:2.0:User\",\n \"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User\"\n ],\n \"externalId\": \"4fd9cc8d-7f42-4ab4-9036-07c94b2ac663\",\n \"userName\": \"alex.morgan@example.com\",\n \"active\": true,\n \"name\": {\n \"givenName\": \"Alex\",\n \"familyName\": \"Morgan\"\n },\n \"emails\": [\n { \"type\": \"work\", \"primary\": true, \"value\": \"alex.morgan@example.com\" }\n ],\n \"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User\": {\n \"department\": \"Engineering\"\n }\n}\n~~~\n\n## Requirements for an owned bridge\n\nA production bridge needs all of the following:\n\n- TLS validation for LDAP and HTTPS, and secrets held in an approved vault;\n- a durable relationship between source identifiers, SCIM `externalId` and the\n application’s returned SCIM resource identifier;\n- deterministic create-versus-update matching and a documented rename policy;\n- bounded pagination, checkpoints, retry with backoff and idempotent replay;\n- explicit handling for disable, delete, restore and a person missing from a\n source query;\n- redacted operational evidence linking one source change to one SCIM response;\n- reconciliation that detects drift rather than repeatedly overwriting it;\n- a tested response to rate limiting, token rotation and partial batch failure.\n\nDo not use Bulk for a first implementation merely for speed. The application\nsupports a bounded Bulk request whose operations behave exactly as the same\nindividual requests, but a Bulk response reports each operation's status\nseparately, which makes failures harder to observe. Start with observable\nindividual operations.\n\n## Validate before production\n\nRun a positive and negative lifecycle: create an admitted user, reject a user\nfrom a disallowed domain when restrictions exist, update the profile, change a\ndepartment, disable the source account and restore it. At every step compare\nthe directory state, emitted SCIM document, HTTP result, application user,\nmembership, role and unit assignments.\n\n## Standards and provider documentation\n\n- [RFC 4511](https://www.rfc-editor.org/rfc/rfc4511.html) defines LDAP’s\n protocol. It explains the source-side boundary; it does not make an LDAP\n directory a SCIM provider.\n- [RFC 7643](https://www.rfc-editor.org/rfc/rfc7643.html) and\n [RFC 7644](https://www.rfc-editor.org/rfc/rfc7644.html) define the SCIM\n resource and protocol boundaries the bridge must emit.\n- Microsoft documents the path from connected systems to SCIM in\n [How application provisioning works](https://learn.microsoft.com/en-us/entra/identity/app-provisioning/how-provisioning-works).\n- For an Okta-governed directory, compare the bridge design with Okta’s\n [private SCIM integration guide](https://developer.okta.com/docs/guides/scim-provisioning-integration-connect/main/)\n and [SCIM protocol reference](https://developer.okta.com/docs/api/openapi/okta-scim/guides).\n\nThese references define the systems on either side of the bridge. The bridge’s\nmatching, checkpoint, retry and reconciliation behavior remains an operated\ncomponent your organization must specify and test.";
212
215
  }, {
213
216
  readonly managedPath: "user-administration/scim-map-profile-and-units.md";
214
217
  readonly unitRef: "technical-documentation:unit/scim-map-profile-and-units";
215
218
  readonly sourceRefs: readonly ["saas-technical-doc:engine-content/scim-map-profile-and-units"];
216
- readonly markdown: "# Map SCIM profiles and organization units\n\nMap the directory’s actual payload to the profile values the application needs.\nThen, only when department data should control access, map exact department\nvalues to existing organization units.\n\n## What you need and what success looks like\n\n| | |\n| --- | --- |\n| **Who performs this task** | The organization administrator and directory engineer who know the real SCIM payload |\n| **Where the mapping applies** | One organization’s SCIM provisioning configuration |\n| **Before you begin** | Capture representative non-production payloads, create every target unit and decide whether department data should be authoritative for unit assignments |\n| **Successful result** | Each required profile field resolves predictably, each approved department maps exactly once, and unmapped or malformed values have a tested outcome |\n\nOpen **Settings → User provisioning → Provisioning** for the organization, then\nedit the attribute and organization-unit mappings. Use the linked SCIM\nconfiguration API reference when the mapping is maintained by automation.\n\n## Map profile values\n\n| Application value | Built-in SCIM path |\n| --- | --- |\n| Email | `emails[0].value` |\n| Given name | `name.givenName` |\n| Family name | `name.familyName` |\n| Display name | `displayName` |\n\nCustom expressions may use dotted fields, an array index or an `eq` filter:\n\n- `name.givenName`\n- `emails[primary eq true].value`\n- `emails[type eq \"work\"].value`\n\n> **Test paths against a real directory payload.** A malformed or unmatched\n> expression does not necessarily reject the request. It can produce no value;\n> email may fall back to `userName`, the primary email or the first email,\n> while another profile field remains empty.\n\n## Understand verified email domains\n\nSCIM mirrors verified domains from the organization’s SSO configuration; it\ndoes not keep another list. A non-empty list restricts admitted email domains.\nAn empty or unavailable list leaves provisioning unrestricted by email domain.\nIf your policy requires a restriction, stop until at least one verified domain\nis visible and a deliberately invalid domain is refused.\n\n## Map a department to a unit\n\nEach mapping binds one exact directory value to one existing unit:\n\n~~~text\n\"Sales\" -> existing Sales organization unit\n~~~\n\nMatching trims surrounding whitespace but is case-sensitive. `Sales` and\n`sales` are different. The application does not search by unit name or code,\ndoes not use fuzzy matching and never creates the missing unit.\n\n~~~mermaid\nflowchart LR\n accTitle: Reconcile a directory department to unit access\n accDescr: An exact department value selects one configured unit. With a default unit role, a supported full reconciliation replaces the person's directory-managed unit assignments.\n payload[\"SCIM User department\"] --> exact{\"Exact configured value?\"}\n exact -->|\"Yes\"| unit[\"Existing organization unit\"]\n unit --> role[\"Configured default unit role\"]\n role --> replace[\"Replace desired unit assignments\"]\n exact -->|\"No or blank\"| remove[\"No mapped desired assignment\"]\n~~~\n\nReconciliation becomes active only with at least one explicit mapping and a\ndefault unit role. On supported direct user creation and full replacement, the\ndirectory becomes authoritative: a changed, blank or unmapped department can\nremove former assignments, including manual ones. **PATCH and Bulk do not\ncurrently perform this reconciliation.** Prove the exact operation used by\nyour identity provider.";
219
+ readonly markdown: "# Map SCIM profiles and organization units\n\nMap the directory’s actual payload to the profile values the application needs.\nThen, only when department data should control access, map exact department\nvalues to existing organization units.\n\n## What you need and what success looks like\n\n| | |\n| --- | --- |\n| **Who performs this task** | The organization administrator and directory engineer who know the real SCIM payload |\n| **Where the mapping applies** | One organization’s SCIM provisioning configuration |\n| **Before you begin** | Capture representative non-production payloads, create every target unit and decide whether department data should be authoritative for unit assignments |\n| **Successful result** | Each required profile field resolves predictably, each approved department maps exactly once, and unmapped or malformed values have a tested outcome |\n\nOpen **Settings → User provisioning → Provisioning** for the organization, then\nedit the attribute and organization-unit mappings. Use the linked SCIM\nconfiguration API reference when the mapping is maintained by automation.\n\n## Map profile values\n\n| Application value | Built-in SCIM path |\n| --- | --- |\n| Email | `emails[0].value` |\n| Given name | `name.givenName` |\n| Family name | `name.familyName` |\n| Display name | `displayName` |\n\nCustom expressions may use dotted fields, an array index or an `eq` filter:\n\n- `name.givenName`\n- `emails[primary eq true].value`\n- `emails[type eq \"work\"].value`\n\n> **Test paths against a real directory payload.** A malformed or unmatched\n> expression does not necessarily reject the request. It can produce no value;\n> email may fall back to `userName`, the primary email or the first email,\n> while another profile field remains empty.\n\n## Understand verified email domains\n\nSCIM mirrors verified domains from the organization’s SSO configuration; it\ndoes not keep another list. A non-empty list restricts admitted email domains.\nAn empty or unavailable list leaves provisioning unrestricted by email domain.\nIf your policy requires a restriction, stop until at least one verified domain\nis visible and a deliberately invalid domain is refused.\n\n## Map a department to a unit\n\nEach mapping binds one exact directory value to one existing unit:\n\n~~~text\n\"Sales\" -> existing Sales organization unit\n~~~\n\nMatching trims surrounding whitespace but is case-sensitive. `Sales` and\n`sales` are different. The application does not search by unit name or code,\ndoes not use fuzzy matching and never creates the missing unit.\n\n~~~mermaid\nflowchart LR\n accTitle: Reconcile a directory department to unit access\n accDescr: An exact department value selects one configured unit. With a default unit role, a supported full reconciliation replaces the person's directory-managed unit assignments.\n payload[\"SCIM User department\"] --> exact{\"Exact configured value?\"}\n exact -->|\"Yes\"| unit[\"Existing organization unit\"]\n unit --> role[\"Configured default unit role\"]\n role --> replace[\"Replace desired unit assignments\"]\n exact -->|\"No or blank\"| remove[\"No mapped desired assignment\"]\n~~~\n\nReconciliation becomes active only with at least one explicit mapping and a\ndefault unit role. On supported direct user creation and full replacement, the\ndirectory becomes authoritative: a changed, blank or unmapped department can\nremove former assignments, including manual ones. A PATCH performs this\nreconciliation only when it sets or removes the department; Bulk operations\nbehave as the same individual requests. Prove the exact operation used by\nyour identity provider.";
217
220
  }, {
218
221
  readonly managedPath: "user-administration/scim-validate-and-roll-out.md";
219
222
  readonly unitRef: "technical-documentation:unit/scim-validate-and-roll-out";
220
223
  readonly sourceRefs: readonly ["saas-technical-doc:engine-content/scim-validate-and-roll-out"];
221
- readonly markdown: "# Validate and roll out SCIM\n\nDo not enable a full directory population after a successful connection check.\nUse a small controlled group and inspect the resulting user, membership, role,\nunit assignment and sign-in behavior after every change.\n\n## What you need and what success looks like\n\n| | |\n| --- | --- |\n| **Who performs this task** | The identity-directory owner, an organization administrator and the owner of the pilot population |\n| **Where validation applies** | One non-production or tightly controlled organization cohort |\n| **Before you begin** | Define expected identities, roles, units and states for every test case, plus the stop and rollback decision |\n| **Successful result** | Real SCIM operations match the expected application state for creation, update, movement, deactivation and recovery before the next cohort is enabled |\n\n> **The current connection-test and provisioning-statistics actions are not\n> readiness evidence.** Prove the integration with real controlled SCIM\n> operations and authoritative application state.\n\n## Run the validation matrix\n\n1. **Create a new person.** Verify the user state, organization membership,\n organization role and enterprise sign-in path.\n2. **Send an existing email.** Confirm that it links to the intended identity\n and does not create a duplicate.\n3. **Change each mapped profile value.** Inspect the destination after the\n directory operation.\n4. **Exercise email verification.** When automatic verification is off, prove\n the pending-verification and resend journey.\n5. **Move a department.** Use a direct full replacement, then confirm the former\n unit assignment was removed.\n6. **Send blank, unmapped and wrong-case departments.** Verify the exact result\n before making mapping authoritative.\n7. **Deactivate a multi-organization person.** Inspect both the global user and\n every affected membership.\n8. **Recover the person.** Confirm that the user and intended membership are\n both **Active** and that enterprise sign-in succeeds.\n\n## Roll out in stages\n\n~~~mermaid\nflowchart LR\n accTitle: Expand SCIM only after each cohort is verified\n accDescr: Begin with controlled identities, then a representative pilot, then broader cohorts. Stop and reconcile differences before proceeding.\n controlled[\"Controlled identities\"] --> pilot[\"Representative pilot\"]\n pilot --> cohort[\"First production cohort\"]\n cohort --> broad[\"Broader population\"]\n controlled -.-> stop[\"Stop on unexplained difference\"]\n pilot -.-> stop\n cohort -.-> stop\n~~~\n\nFor each stage, name the expected count and membership states, reconcile the\nresult, document exceptions and retain a rollback decision. Do not silently\nrepair directory-owned people in the application; fix the authoritative input\nor explicitly move the person to manual ownership.";
224
+ readonly markdown: "# Validate and roll out SCIM\n\nDo not enable a full directory population after a successful connection check.\nUse a small controlled group and inspect the resulting user, membership, role,\nunit assignment and sign-in behavior after every change.\n\n## What you need and what success looks like\n\n| | |\n| --- | --- |\n| **Who performs this task** | The identity-directory owner, an organization administrator and the owner of the pilot population |\n| **Where validation applies** | One non-production or tightly controlled organization cohort |\n| **Before you begin** | Define expected identities, roles, units and states for every test case, plus the stop and rollback decision |\n| **Successful result** | Real SCIM operations match the expected application state for creation, update, movement, deactivation and recovery before the next cohort is enabled |\n\n> **The current connection-test and provisioning-statistics actions are not\n> readiness evidence.** Prove the integration with real controlled SCIM\n> operations and authoritative application state.\n\n## Run the validation matrix\n\n1. **Create a new person.** Verify the user state, organization membership,\n organization role and enterprise sign-in path.\n2. **Send an existing email.** Confirm that it links to the intended identity\n and does not create a duplicate.\n3. **Change each mapped profile value.** Inspect the destination after the\n directory operation.\n4. **Exercise email verification.** When automatic verification is off, prove\n the pending-verification and resend journey.\n5. **Move a department.** Use a direct full replacement, then confirm the former\n unit assignment was removed.\n6. **Send blank, unmapped and wrong-case departments.** Verify the exact result\n before making mapping authoritative.\n7. **Deactivate a multi-organization person.** Confirm that only this\n organization's membership became inactive and their other memberships\n are unchanged.\n8. **Recover the person.** Confirm that the user and intended membership are\n both **Active** and that enterprise sign-in succeeds.\n\n## Roll out in stages\n\n~~~mermaid\nflowchart LR\n accTitle: Expand SCIM only after each cohort is verified\n accDescr: Begin with controlled identities, then a representative pilot, then broader cohorts. Stop and reconcile differences before proceeding.\n controlled[\"Controlled identities\"] --> pilot[\"Representative pilot\"]\n pilot --> cohort[\"First production cohort\"]\n cohort --> broad[\"Broader population\"]\n controlled -.-> stop[\"Stop on unexplained difference\"]\n pilot -.-> stop\n cohort -.-> stop\n~~~\n\nFor each stage, name the expected count and membership states, reconcile the\nresult, document exceptions and retain a rollback decision. Do not silently\nrepair directory-owned people in the application; fix the authoritative input\nor explicitly move the person to manual ownership.";
222
225
  }, {
223
226
  readonly managedPath: "user-administration/scim-operate-and-troubleshoot.md";
224
227
  readonly unitRef: "technical-documentation:unit/scim-operate-and-troubleshoot";
225
228
  readonly sourceRefs: readonly ["saas-technical-doc:engine-content/scim-operate-and-troubleshoot"];
226
- readonly markdown: "# Operate and troubleshoot SCIM\n\nOperate SCIM as a security-sensitive directory connection: protect its token,\nreconcile outcomes from authoritative state and investigate errors before\nretrying. A request reaching the service is not proof that provisioning\nsucceeded.\n\n## What you need and what success looks like\n\n| | |\n| --- | --- |\n| **Who performs this task** | The directory operator and an organization administrator able to inspect provisioning state |\n| **Where the operation applies** | One organization, directory environment and dedicated SCIM credential |\n| **Before you begin** | Record the affected user, operation, time and redacted response; identify the authoritative owner before making a correction |\n| **Successful result** | The credential or provisioning failure is corrected, one controlled operation succeeds, and the final user, membership, role and unit state is verified |\n\nUse **Settings → User provisioning → Tokens** for token lifecycle work and\n**Provisioning** for configuration and mapping checks. The linked API references\nremain authoritative for exact automation operations and responses.\n\n## Replace or revoke a token\n\nAn in-place rotation is an **immediate cutover**. The previous secret stops\nworking with no overlap. For a planned replacement without interruption:\n\n1. create a second dedicated token;\n2. install it in the identity provider;\n3. prove it with a controlled user operation;\n4. revoke the former token; and\n5. retain only the non-secret metadata needed for review.\n\nRevocation keeps the token record and marks it inactive. A last-used time proves\nthat authenticated traffic reached the service; it does not prove that the user\nchange completed successfully.\n\n## Start from the symptom\n\n| Symptom | First checks |\n| --- | --- |\n| **401** | Token is exact, active, unexpired and sent as a bearer credential |\n| **403** | The organization type permits SCIM and the request belongs to the intended organization |\n| **409** | An existing identity or membership conflicts; inspect it instead of creating a duplicate |\n| **429** | Follow retry information and reduce concurrency |\n| Profile value is missing | Test the exact mapping expression against the real directory payload |\n| Unit did not change | Confirm exact department value and case, explicit mapping, existing unit, default role and a supported direct create/full replacement operation |\n| Person remains unable to sign in | Check enterprise sign-in, global user state and organization membership state separately |\n\n## Recover safely\n\n- Read the SCIM error returned to the identity provider before retrying.\n- Inspect the user, membership, role and unit assignments in the application.\n- Correct the directory or mapping when it owns the person; do not create a\n manual competing state.\n- For deactivation recovery, confirm both the global user and intended\n membership are **Active**.\n- Re-run one controlled operation and inspect its final resource state.\n\nRedact bearer tokens and unnecessary personal data before sharing payloads or\nerrors with support.";
229
+ readonly markdown: "# Operate and troubleshoot SCIM\n\nOperate SCIM as a security-sensitive directory connection: protect its token,\nreconcile outcomes from authoritative state and investigate errors before\nretrying. A request reaching the service is not proof that provisioning\nsucceeded.\n\n## What you need and what success looks like\n\n| | |\n| --- | --- |\n| **Who performs this task** | The directory operator and an organization administrator able to inspect provisioning state |\n| **Where the operation applies** | One organization, directory environment and dedicated SCIM credential |\n| **Before you begin** | Record the affected user, operation, time and redacted response; identify the authoritative owner before making a correction |\n| **Successful result** | The credential or provisioning failure is corrected, one controlled operation succeeds, and the final user, membership, role and unit state is verified |\n\nUse **Settings → User provisioning → Tokens** for token lifecycle work and\n**Provisioning** for configuration and mapping checks. The linked API references\nremain authoritative for exact automation operations and responses.\n\n## Replace or revoke a token\n\nAn in-place rotation is an **immediate cutover**. The previous secret stops\nworking with no overlap. For a planned replacement without interruption:\n\n1. create a second dedicated token;\n2. install it in the identity provider;\n3. prove it with a controlled user operation;\n4. revoke the former token; and\n5. retain only the non-secret metadata needed for review.\n\nRevocation keeps the token record and marks it inactive. A last-used time proves\nthat authenticated traffic reached the service; it does not prove that the user\nchange completed successfully.\n\n## Start from the symptom\n\n| Symptom | First checks |\n| --- | --- |\n| **401** | Token is exact, active, unexpired and sent as a bearer credential |\n| **403** | The organization type permits SCIM and the request belongs to the intended organization |\n| **409** | An existing identity or membership conflicts; inspect it instead of creating a duplicate |\n| **429** | Follow retry information and reduce concurrency |\n| Profile value is missing | Test the exact mapping expression against the real directory payload |\n| Unit did not change | Confirm exact department value and case, explicit mapping, existing unit, default role, and that the operation carried the department (create, full replacement, or a PATCH that sets it) |\n| Person remains unable to sign in | Check enterprise sign-in, global user state and organization membership state separately |\n\n## Recover safely\n\n- Read the SCIM error returned to the identity provider before retrying.\n- Inspect the user, membership, role and unit assignments in the application.\n- Correct the directory or mapping when it owns the person; do not create a\n manual competing state.\n- For deactivation recovery, confirm both the global user and intended\n membership are **Active**.\n- Re-run one controlled operation and inspect its final resource state.\n\nRedact bearer tokens and unnecessary personal data before sharing payloads or\nerrors with support.";
227
230
  }, {
228
231
  readonly managedPath: "security-and-audit/audit-trail-and-siem.md";
229
232
  readonly unitRef: "technical-documentation:unit/audit-and-siem";
@@ -248,22 +251,22 @@ export declare const APPLICATION_CONSUMER_DOCUMENTATION_AUTHORED_CONTENT_V1: rea
248
251
  readonly managedPath: "security-and-audit/configure-siem.md";
249
252
  readonly unitRef: "technical-documentation:unit/configure-siem-export";
250
253
  readonly sourceRefs: readonly ["saas-technical-doc:engine-content/configure-siem-export", "source:consumer-fact:organization-siem-export"];
251
- readonly markdown: "# Configure organization SIEM export\n\nSIEM export sends selected organization audit events to one webhook destination.\nCreate a destination dedicated to the organization and environment, then choose\nthe authentication, wire format and filters your receiver can actually verify.\n\n| Before you begin | Successful result |\n| --- | --- |\n| The organization security owner and SIEM owner agree on destination, TLS, authentication, event scope, format, volume, retention and a controlled test event | One organization/environment sends only the approved event set, the receiver validates and correlates it, failures are recoverable, and the destination secret remains protected |\n\n~~~mermaid\nflowchart TD\n accTitle: Configure a bounded organization SIEM export\n accDescr: The organization and SIEM owners prepare one receiver, choose authentication and a format, select a narrow category and severity filter, keep export disabled while validating configuration, enable it for one controlled event, compare the received copy with the source audit row, then expand deliberately.\n owners[\"Agree owners, organization and receiver\"] --> receiver[\"Prepare TLS, authentication and acknowledgement\"]\n receiver --> format[\"Choose one receiver-supported format\"]\n format --> filter[\"Select minimum event set and severity\"]\n filter --> disabled[\"Save while export remains disabled\"]\n disabled --> enable[\"Enable and perform one controlled event\"]\n enable --> compare[\"Compare event ID, scope, time, actor and outcome\"]\n compare --> expand[\"Expand only after volume and recovery checks\"]\n~~~\n\nSIEM export is an organization-routed copy of source audit events. Configure one\nreceiver per intended organization/environment boundary; do not use a shared\ndestination when its access and retention rules cannot preserve that separation.\n\n## Follow one event from source record to searchable copy\n\n~~~mermaid\nsequenceDiagram\n accTitle: From application audit record to searchable SIEM copy\n accDescr: The application records an audit event, applies the organization export filter, formats one outbound event, authenticates an HTTPS request, and sends it to the receiver. A successful HTTP response acknowledges the configured delivery boundary; the SIEM then parses and indexes the copy. Operators prove completion by searching for the source event identifier. Failed delivery follows retry and dead-letter recovery without removing the source audit record.\n participant Source as Source audit trail\n participant Export as Organization exporter\n participant Receiver as Receiver or relay\n participant SIEM as SIEM index\n actor Operator as Security operator\n Source->>Export: Eligible audit event\n Export->>Export: Apply filter and format one event\n Export->>Receiver: Authenticated HTTPS request\n alt Receiver acknowledges configured boundary\n Receiver-->>Export: Successful HTTP response\n Receiver->>SIEM: Parse, transform and index\n Operator->>SIEM: Search exact eventId\n SIEM-->>Operator: Searchable correlated copy\n else Receiver refuses or times out\n Receiver-->>Export: Error or timeout\n Export->>Export: Retry, then capture recoverable failure\n end\n~~~\n\nThere are three different facts to verify: **the source event exists**, **the\nreceiver acknowledged the request**, and **the transformed event is searchable\nin the intended index or table**. An HTTP 2xx response proves only the delivery\nboundary implemented by that receiver. It is not automatically proof that a\nparser, transformation, index or detection rule accepted the event.\n\n## Decide whether direct delivery is compatible\n\n| Receiver requirement | Recommended path | Why |\n| --- | --- | --- |\n| One HTTPS request containing one JSON object, with a static header or HMAC credential | Test direct delivery | This matches the current structured-JSON worker closely |\n| A provider-specific wrapper around the event | Use a narrow relay unless the exact endpoint accepts the native envelope | The relay owns the wrapper while preserving source identifiers |\n| Short-lived OAuth access tokens or managed identity | Use a provider-side relay | Token acquisition and refresh do not belong in a static credential field |\n| A JSON array or provider batch protocol | Use a relay that batches deliberately | Current delivery is one event per request; configured batch fields are reserved |\n| A syslog, agent, queue or private-network input | Use an adapter or relay inside that boundary | The application sends outbound HTTPS webhooks, not those transports |\n| CEF, LEEF or OCSF ingestion | Test actual emitted samples with the receiver | A format name does not prove field mapping, escaping, severity or class compatibility |\n\nPrefer the smallest component that makes the contracts compatible. A relay is\nnot a generic event platform: it should authenticate before parsing, preserve\nthe source event and correlation identifiers, perform one documented\ntransformation, expose bounded health signals and fail without silently\ndiscarding the event.\n\n## Choose the delivery contract\n\nThe following table is generated from the maintained SIEM configuration schema\nand resource specification. It distinguishes enforced values from reserved\nconfiguration so an accepted field is not mistaken for working delivery\nbehavior.\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#configurationMarkdown}}\n\n### Authentication values\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#authenticationValuesMarkdown}}\n\n### Wire-format values\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#formatValuesMarkdown}}\n\nChoose the simplest format the receiver can validate end to end:\n\n| Format | Use when | Verify before rollout |\n| --- | --- | --- |\n| Structured JSON | The receiver can preserve named fields and nested event data | Schema/field parsing, timestamps, identifiers and unknown-field handling |\n| CEF | The receiver has a tested CEF ingestion path | Header and extension parsing, escaping and the receiver's event classification |\n| LEEF | The receiver has a tested LEEF/QRadar path | Tab-delimited attributes, escaping and event mapping |\n| OCSF | The receiver consumes the emitted OCSF class documents | Class, activity, required fields and receiver validation for the actual event samples |\n\nDo not choose a format from its name alone. Preserve a receiver-tested sample\nfor each event family that matters to detection; syntactically accepted input\ncan still be mapped to the wrong fields or severity by the downstream product.\n\nAuthentication credentials are write-only secrets. A read returns a masked\nstored-credential marker, not the secret. Leaving that marker unchanged during\nan edit preserves the stored value; entering a new value replaces it. Never\ncopy the secret into a ticket or detection rule.\n\n## Configure filters from their exact values\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#filterValuesMarkdown}}\n\nThe optional `specificEventTypes` list is an **exact identifier allowlist**.\nIt is not a substring, prefix, regular expression or wildcard filter. Add an\nidentifier only after confirming that the corresponding event is emitted in the\napplication path you operate.\n\n## Configure delivery behavior\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#deliveryValuesMarkdown}}\n\nThe current worker posts **one event per HTTP request**. Do not configure a\nreceiver, load balancer or billing estimate on the assumption that `batchSize`\nor `batchWindowSeconds` reduces request volume. The\n`includeRawEventData` and `includeDeviceContext` flags are also reserved in\nthe current runtime: changing them does not remove those fields from the emitted\nenvelope. Treat data minimization at the receiver as necessary until those\nconfiguration controls are implemented end to end.\n\n## Filter for purpose and volume\n\nStart with the categories needed by the monitoring use case and a minimum\nseverity that preserves administrative and security-relevant activity. Add an\nevent-type allowlist only when the receiver intentionally needs that narrower\nset. An allowlist can silently exclude newly introduced event types, so record\nits owner and review it when the application's event catalogue changes.\n\nFilters govern future delivery copies; they do not delete the source audit\ntrail. A narrow SIEM feed is therefore not evidence that no other audit activity\nexists in the application.\n\n## Roll out deliberately\n\n1. Keep export disabled while the receiver, TLS and authentication are prepared.\n2. Start with structured JSON and a narrow event filter that includes one\n controlled administrative event.\n3. Enable export and perform the controlled action in the intended organization.\n4. Match the received event ID, timestamp, organization, outcome and correlation ID.\n5. Trigger a controlled event outside the filter and confirm it remains in the\n source trail but is not delivered to this receiver.\n6. Exercise an acknowledged receiver response and one safe temporary failure so\n ownership of retry/dead-letter recovery is known.\n7. Expand categories and lower the severity threshold only after the receiver\n handles expected volume and redaction.\n\nConfiguration is cached by the running application for up to five minutes.\nEnabling may therefore miss exports during that interval, and changing a\ndestination may continue sending to the former receiver until the cache expires.\nTreat a destination change as a security operation and verify the old receiver\nhas stopped receiving before closing the change.\n\nFor credential rotation or destination replacement, keep the change window and\nold/new receiver ownership explicit. Verify the current receiver accepts a new\ncontrolled event and the former receiver no longer receives selected traffic\nafter the cache window. Retain configuration approval, non-secret destination\nidentity, format/filter choices, test event and correlation IDs, delivery result\nand recovery owner—never the bearer token, API-key value or HMAC secret.\n\n## Format standards and receiver references\n\n- OpenText’s [Common Event Format implementation standard](https://www.microfocus.com/documentation/arcsight/arcsight-smartconnectors-24.4/cef-implementation-standard/)\n describes CEF header and extension construction. Validate the application’s\n actual event samples against the target connector rather than assuming every\n CEF consumer maps extensions identically.\n- IBM documents [LEEF event components](https://www.ibm.com/docs/en/qradar-on-cloud?topic=overview-leef-event-components)\n and [predefined LEEF attributes](https://www.ibm.com/docs/en/qradar-on-cloud?topic=overview-predefined-leef-event-attributes)\n for QRadar ingestion and field mapping.\n- The [OCSF schema browser](https://schema.ocsf.io) and\n [OCSF schema repository](https://github.com/ocsf/ocsf-schema) define the open\n event classes and attributes. Confirm the emitted class, activity and\n required fields for every selected event family.\n\nThese external standards describe receiver-side expectations. The generated\nconfiguration tables above remain the authority for values and behavior this\napplication actually supports.";
254
+ readonly markdown: "# Configure organization SIEM export\n\nSIEM export sends selected organization audit events to one webhook destination.\nCreate a destination dedicated to the organization and environment, then choose\nthe authentication, wire format and filters your receiver can actually verify.\n\n| Before you begin | Successful result |\n| --- | --- |\n| The organization security owner and SIEM owner agree on destination, TLS, authentication, event scope, format, volume, retention and a controlled test event | One organization/environment sends only the approved event set, the receiver validates and correlates it, failures are recoverable, and the destination secret remains protected |\n\n~~~mermaid\nflowchart TD\n accTitle: Configure a bounded organization SIEM export\n accDescr: The organization and SIEM owners prepare one receiver, choose authentication and a format, select a narrow category and severity filter, keep export disabled while validating configuration, enable it for one controlled event, compare the received copy with the source audit row, then expand deliberately.\n owners[\"Agree owners, organization and receiver\"] --> receiver[\"Prepare TLS, authentication and acknowledgement\"]\n receiver --> format[\"Choose one receiver-supported format\"]\n format --> filter[\"Select minimum event set and severity\"]\n filter --> disabled[\"Save while export remains disabled\"]\n disabled --> enable[\"Enable and perform one controlled event\"]\n enable --> compare[\"Compare event ID, scope, time, actor and outcome\"]\n compare --> expand[\"Expand only after volume and recovery checks\"]\n~~~\n\nSIEM export is an organization-routed copy of source audit events. Configure one\nreceiver per intended organization/environment boundary; do not use a shared\ndestination when its access and retention rules cannot preserve that separation.\n\n## Follow one event from source record to searchable copy\n\n~~~mermaid\nsequenceDiagram\n accTitle: From application audit record to searchable SIEM copy\n accDescr: The application records an audit event, applies the organization export filter, formats one outbound event, authenticates an HTTPS request, and sends it to the receiver. A successful HTTP response acknowledges the configured delivery boundary; the SIEM then parses and indexes the copy. Operators prove completion by searching for the source event identifier. Failed delivery follows retry and dead-letter recovery without removing the source audit record.\n participant Source as Source audit trail\n participant Export as Organization exporter\n participant Receiver as Receiver or relay\n participant SIEM as SIEM index\n actor Operator as Security operator\n Source->>Export: Eligible audit event\n Export->>Export: Apply filter and format one event\n Export->>Receiver: Authenticated HTTPS request\n alt Receiver acknowledges configured boundary\n Receiver-->>Export: Successful HTTP response\n Receiver->>SIEM: Parse, transform and index\n Operator->>SIEM: Search exact eventId\n SIEM-->>Operator: Searchable correlated copy\n else Receiver refuses or times out\n Receiver-->>Export: Error or timeout\n Export->>Export: Retry, then capture recoverable failure\n end\n~~~\n\nThere are three different facts to verify: **the source event exists**, **the\nreceiver acknowledged the request**, and **the transformed event is searchable\nin the intended index or table**. An HTTP 2xx response proves only the delivery\nboundary implemented by that receiver. It is not automatically proof that a\nparser, transformation, index or detection rule accepted the event.\n\n## Decide whether direct delivery is compatible\n\n| Receiver requirement | Recommended path | Why |\n| --- | --- | --- |\n| One HTTPS request containing one JSON object, with a static header or HMAC credential | Test direct delivery | This matches the current structured-JSON worker closely |\n| A provider-specific wrapper around the event | Use a narrow relay unless the exact endpoint accepts the native envelope | The relay owns the wrapper while preserving source identifiers |\n| Short-lived OAuth access tokens or managed identity | Use a provider-side relay | Token acquisition and refresh do not belong in a static credential field |\n| A plain JSON array of events | Test direct delivery with `batchSize` above 1 | A batch of `json_structured` or `ocsf` events is sent as one JSON array |\n| A provider-specific batch protocol | Use a relay that batches deliberately | Batching sends a plain array or one line per event, never a provider wrapper |\n| A syslog, agent, queue or private-network input | Use an adapter or relay inside that boundary | The application sends outbound HTTPS webhooks, not those transports |\n| CEF, LEEF or OCSF ingestion | Test actual emitted samples with the receiver | A format name does not prove field mapping, escaping, severity or class compatibility |\n\nPrefer the smallest component that makes the contracts compatible. A relay is\nnot a generic event platform: it should authenticate before parsing, preserve\nthe source event and correlation identifiers, perform one documented\ntransformation, expose bounded health signals and fail without silently\ndiscarding the event.\n\n## Choose the delivery contract\n\nThe following table is generated from the maintained SIEM configuration schema\nand resource specification. It distinguishes enforced values from reserved\nconfiguration so an accepted field is not mistaken for working delivery\nbehavior.\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#configurationMarkdown}}\n\n### Authentication values\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#authenticationValuesMarkdown}}\n\n### Wire-format values\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#formatValuesMarkdown}}\n\nChoose the simplest format the receiver can validate end to end:\n\n| Format | Use when | Verify before rollout |\n| --- | --- | --- |\n| Structured JSON | The receiver can preserve named fields and nested event data | Schema/field parsing, timestamps, identifiers and unknown-field handling |\n| CEF | The receiver has a tested CEF ingestion path | Header and extension parsing, escaping and the receiver's event classification |\n| LEEF | The receiver has a tested LEEF/QRadar path | Tab-delimited attributes, escaping and event mapping |\n| OCSF | The receiver consumes the emitted OCSF class documents | Class, activity, required fields and receiver validation for the actual event samples |\n\nDo not choose a format from its name alone. Preserve a receiver-tested sample\nfor each event family that matters to detection; syntactically accepted input\ncan still be mapped to the wrong fields or severity by the downstream product.\n\nAuthentication credentials are write-only secrets. A read returns a masked\nstored-credential marker, not the secret. Leaving that marker unchanged during\nan edit preserves the stored value; entering a new value replaces it. Never\ncopy the secret into a ticket or detection rule.\n\n## Configure filters from their exact values\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#filterValuesMarkdown}}\n\nThe optional `specificEventTypes` list is an **exact identifier allowlist**.\nIt is not a substring, prefix, regular expression or wildcard filter. Add an\nidentifier only after confirming that the corresponding event is emitted in the\napplication path you operate.\n\n## Configure delivery behavior\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#deliveryValuesMarkdown}}\n\nWith the default `batchSize` of 1, each event is its own HTTP request. Set\n`batchSize` above 1 and this destination's events wait, then travel together:\na batch is sent as soon as `batchSize` events are waiting, or when the oldest has\nwaited `batchWindowSeconds`. A batch is one request body, framed the way its format\nframes several records:\n\n| Format | Body of a batch |\n| --- | --- |\n| `json_structured`, `ocsf` | A JSON array of the events |\n| `cef`, `leef` | One line per event, separated by newlines |\n\nA batch that holds one event is sent exactly like a single event, with no array and\nno trailing newline, so a receiver written for one event per request keeps working\nuntil you raise `batchSize`. If the receiver answers `413 Payload Too Large`, the\nbatch is halved and sent again until the receiver accepts it; the events left out\ngo in the next request. Size a receiver, load balancer or billing estimate on the\nbatch size you choose.\n\n## Limit what an exported event carries\n\n`exportProjection` decides what this destination receives. It is the only place\nan export can be narrowed **before** the data leaves; everything else — a filter,\na severity minimum — decides *whether* an event is sent, not *what* it contains.\n\nSet it per destination, not per application: two receivers under two different\nagreements are two different answers.\n\n| Declaration | Admits |\n| --- | --- |\n| `disclosedTiers: [\"attribution\"]` | the user's email address, IP address, user agent, geolocation and client-install identifier |\n| `disclosedTiers: [\"context\"]` | correlation identifier, originating frontend, organization and application names, authentication method and source |\n| `disclosedTiers: [\"detail\"]` | the per-event `eventData` object **and the outcome reason**, subject to the next row |\n| `disclosedEventDataClasses: [\"administrative\"]` | only the `eventData` of events describing configuration or system state |\n| `disclosedEventDataClasses: [\"subject-detail\"]` | also the `eventData` of events describing a person |\n\n**Declaring `detail` while withholding `attribution` is the mistake to avoid.**\nAn authentication event's `eventData` carries the email address and IP address\nthat withholding attribution was meant to keep back, so the narrowing reads as a\ncontrol while changing nothing that matters. Pair it with\n`disclosedEventDataClasses: [\"administrative\"]`.\n\nThe outcome reason sits in `detail` rather than `context` for the same reason,\nand it is worth understanding before you rely on either tier. It is not a field of\nits own: the application lifts it out of the event's own `eventData`. Most of the\ntime it is a short, impersonal failure reason — but **19 event types carry a\nreason somebody typed**, including organization lifecycle changes, emergency\naccess, forced password resets and retained-data access, where it is the\noperator's own words and may name anyone. Withholding an event's detail therefore\nwithholds its reason too.\n\nA **floor always survives** whatever you declare: event identifier, event type,\ncategory, severity, timestamp, organization, the acting user's identifier, source\nservice, source version, source environment, and outcome. Two reasons, and only\nthe first is about privacy. The event identifier is what your receiver\nde-duplicates on, and deliveries are retried — an export minimized past it\nproduces duplicates in your SIEM rather than fewer records. The event type,\nseverity and source version are header fields of the CEF and LEEF grammars, which\nare positional: omitting one does not shorten the record, it corrupts every field\nafter it. The acting user's identifier is an opaque reference, never a name or an\naddress, so it lets you correlate one actor's activity without receiving their\nidentity — which is usually the trade a minimized export exists to make.\n\nOne capability cost to know about, because nothing warns you at the time:\nwithholding `detail` makes OCSF exports coarser. The application refines an\nAPI-activity event's `activity_id` by reading the verb out of `eventData`, so\nwith the object withheld a create and a delete both report the generic\n`Other` activity and share a `type_uid`. The event type is still carried in\n`activity_name` and `metadata.event_code`, so nothing is wrong — but a\ndetection rule or dashboard that groups by `type_uid` will stop separating them.\nCEF, LEEF and structured JSON are unaffected.\n\nWithheld fields are **absent**, not empty. No blank CEF custom-string slot, no\nnull JSON key, no empty OCSF attribute — so a receiver's \"field is present but\nempty\" rule will not fire, and a rule keyed on a withheld field simply never\nmatches. The same projection applies to every wire format, because it is applied\nonce, before the event is signed and queued, rather than per format.\n\nOmit the whole block and the destination receives the full envelope. That is the\nbehaviour of every destination configured before this control existed, so\nintroducing it changes nothing until you declare a narrowing.\n\nVerify a narrowing the way you verify a filter: perform one controlled event,\nread the received copy, and confirm both that the withheld fields are absent and\nthat the event identifier still matches the source audit record. Minimization\ndoes not alter the source audit trail — the full record remains in the\napplication, and a narrowed feed is not evidence that less was recorded.\n\n## Filter for purpose and volume\n\nStart with the categories needed by the monitoring use case and a minimum\nseverity that preserves administrative and security-relevant activity. Add an\nevent-type allowlist only when the receiver intentionally needs that narrower\nset. An allowlist can silently exclude newly introduced event types, so record\nits owner and review it when the application's event catalogue changes.\n\nFilters govern future delivery copies; they do not delete the source audit\ntrail. A narrow SIEM feed is therefore not evidence that no other audit activity\nexists in the application.\n\n## Roll out deliberately\n\n1. Keep export disabled while the receiver, TLS and authentication are prepared.\n2. Start with structured JSON and a narrow event filter that includes one\n controlled administrative event.\n3. Enable export and perform the controlled action in the intended organization.\n4. Match the received event ID, timestamp, organization, outcome and correlation ID.\n5. Trigger a controlled event outside the filter and confirm it remains in the\n source trail but is not delivered to this receiver.\n6. Exercise an acknowledged receiver response and one safe temporary failure so\n ownership of retry/dead-letter recovery is known.\n7. Expand categories and lower the severity threshold only after the receiver\n handles expected volume and redaction.\n\nConfiguration is cached by the running application for up to five minutes.\nEnabling may therefore miss exports during that interval, and changing a\ndestination may continue sending to the former receiver until the cache expires.\nTreat a destination change as a security operation and verify the old receiver\nhas stopped receiving before closing the change.\n\nFor credential rotation or destination replacement, keep the change window and\nold/new receiver ownership explicit. Verify the current receiver accepts a new\ncontrolled event and the former receiver no longer receives selected traffic\nafter the cache window. Retain configuration approval, non-secret destination\nidentity, format/filter choices, test event and correlation IDs, delivery result\nand recovery owner—never the bearer token, API-key value or HMAC secret.\n\n## Format standards and receiver references\n\n- OpenText’s [Common Event Format implementation standard](https://www.microfocus.com/documentation/arcsight/arcsight-smartconnectors-24.4/cef-implementation-standard/)\n describes CEF header and extension construction. Validate the application’s\n actual event samples against the target connector rather than assuming every\n CEF consumer maps extensions identically.\n- IBM documents [LEEF event components](https://www.ibm.com/docs/en/qradar-on-cloud?topic=overview-leef-event-components)\n and [predefined LEEF attributes](https://www.ibm.com/docs/en/qradar-on-cloud?topic=overview-predefined-leef-event-attributes)\n for QRadar ingestion and field mapping.\n- The [OCSF schema browser](https://schema.ocsf.io) and\n [OCSF schema repository](https://github.com/ocsf/ocsf-schema) define the open\n event classes and attributes. Confirm the emitted class, activity and\n required fields for every selected event family.\n\nThese external standards describe receiver-side expectations. The generated\nconfiguration tables above remain the authority for values and behavior this\napplication actually supports.";
252
255
  }, {
253
256
  readonly managedPath: "security-and-audit/siem-splunk.md";
254
257
  readonly unitRef: "technical-documentation:unit/siem-splunk";
255
258
  readonly sourceRefs: readonly ["saas-technical-doc:engine-content/siem-splunk", "source:consumer-fact:organization-siem-export"];
256
- readonly markdown: "# Send audit events to Splunk\n\nSplunk HTTP Event Collector (HEC) accepts events over HTTPS with a token in the\n`Authorization` header. The application can supply that header, but its native\nstructured JSON body is a security-audit envelope—not Splunk’s HEC\n`{\"event\": ...}` wrapper. **Use a small controlled relay unless your chosen HEC\nendpoint and source type have been proven to accept and extract the exact body.**\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#markdown}}\n\n~~~mermaid\nflowchart LR\n audit[\"Organization audit event\"] --> exporter[\"Application SIEM export\"]\n exporter -->|\"JSON + authenticated HTTPS\"| relay[\"Owned HEC relay\"]\n relay -->|\"HEC event wrapper\"| hec[\"Splunk HEC\"]\n hec --> index[\"Dedicated index and source type\"]\n index --> search[\"Search by eventId and correlationId\"]\n~~~\n\n## Prepare Splunk\n\n1. Create a dedicated Splunk index or confirm the approved existing index.\n2. In Splunk Cloud or Splunk Enterprise, create an HEC token dedicated to this\n application organization and environment.\n3. Assign the token only to the intended index and choose a JSON-capable source\n type. Wait until token deployment is complete before testing.\n4. Record the HEC base URL, token owner, index, source type, rotation process and\n retention policy. Store the token only in approved secret stores.\n\nSplunk’s event endpoint expects a body shaped like:\n\n~~~json\n{\n \"time\": 1776631800,\n \"host\": \"application-production\",\n \"source\": \"application-security-audit\",\n \"sourcetype\": \"_json\",\n \"index\": \"security\",\n \"event\": {\n \"eventId\": \"7b45a61c-9bcc-4bf2-9a29-0f111bff6d07\",\n \"eventType\": \"user_login_failed\",\n \"organizationId\": \"org_example\",\n \"severity\": \"warning\"\n }\n}\n~~~\n\nThe relay owns this wrapper and any approved metadata; it must preserve the\napplication event object without renaming `eventId`, `correlationId`, actor,\norganization, timestamp, outcome or severity fields.\n\n### Choose the acknowledgement boundary\n\nA normal HEC success response confirms that HEC accepted the request. Splunk\nalso supports **indexer acknowledgement**, where a client submits a channel\nidentifier and later checks whether the event reached the indexing pipeline.\nIf the relay uses that mode, return success to the application only after the\nrelay’s documented durability boundary; do not hold the application request\nopen indefinitely while waiting for a search result.\n\nWhichever mode you choose, the operating proof is still an exact\n`eventId` search in the intended index. Record separately whether a failure\nhappened before HEC acceptance, while awaiting an indexer acknowledgement, or\nafter indexing during parsing and field extraction.\n\n## Configure the application-to-relay request\n\nRecommended application settings:\n\n| Setting | Value |\n| --- | --- |\n| Destination | Relay HTTPS URL dedicated to the organization/environment |\n| Authentication | `hmac_sha256` or a dedicated `api_key_header` |\n| Format | `json_structured` |\n| Delivery | One event per request; choose timeout/retry values below the relay’s bounded acknowledgement time |\n\nIf a controlled test proves direct HEC compatibility, configure:\n\n| Setting | Direct HEC value |\n| --- | --- |\n| `authMethod` | `api_key_header` |\n| `authHeaderName` | `Authorization` |\n| `authCredential` | The complete value `Splunk HEC_TOKEN`, including the `Splunk ` prefix |\n| `webhookUrl` | The exact HEC event or raw endpoint validated by the Splunk owner |\n\nThe API-key-header mode sends the configured credential verbatim. Do not choose\n`bearer_token`: it would send `Authorization: Bearer ...`, which is not\nSplunk HEC token authentication.\n\n## Prove ingestion, not only HTTP acceptance\n\n1. Keep broad export disabled and select one controlled event type.\n2. Trigger the event and find the source audit row.\n3. Confirm relay/HEC HTTP acceptance without logging the token.\n4. Search the intended Splunk index for the exact `eventId`.\n5. Verify organization, timestamp, event type, severity, actor/outcome and\n correlation identifier.\n6. Trigger an event outside the filter and confirm it remains only in the source\n audit trail.\n7. Temporarily refuse one request, restore the receiver and prove dead-letter\n recovery without creating a duplicate indexed event.\n\n## Splunk documentation to keep with the runbook\n\n- Splunk’s [HTTP Event Collector examples](https://help.splunk.com/en/splunk-enterprise/get-data-in/collect-http-event-data/http-event-collector-examples)\n show the HEC authorization header, event wrapper and endpoint shapes used to\n validate the relay output.\n- Splunk’s [HEC indexer acknowledgement](https://help.splunk.com/en/splunk-enterprise/get-started/get-data-in/9.2/get-data-with-http-event-collector/about-http-event-collector-indexer-acknowledgment)\n documentation explains the optional channel and acknowledgement protocol.\n\nKeep the tested HEC endpoint, source type, acknowledgement mode and sample\nsearch beside these links. Provider documentation defines Splunk’s contract;\nthis guide defines the application envelope that must be conserved.";
259
+ readonly markdown: "# Send audit events to Splunk\n\nSplunk HTTP Event Collector (HEC) accepts events over HTTPS with a token in the\n`Authorization` header. The application can supply that header, but its native\nstructured JSON body is a security-audit envelope—not Splunk’s HEC\n`{\"event\": ...}` wrapper. **Use a small controlled relay unless your chosen HEC\nendpoint and source type have been proven to accept and extract the exact body.**\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#markdown}}\n\n~~~mermaid\nflowchart LR\n audit[\"Organization audit event\"] --> exporter[\"Application SIEM export\"]\n exporter -->|\"JSON + authenticated HTTPS\"| relay[\"Owned HEC relay\"]\n relay -->|\"HEC event wrapper\"| hec[\"Splunk HEC\"]\n hec --> index[\"Dedicated index and source type\"]\n index --> search[\"Search by eventId and correlationId\"]\n~~~\n\n## Prepare Splunk\n\n1. Create a dedicated Splunk index or confirm the approved existing index.\n2. In Splunk Cloud or Splunk Enterprise, create an HEC token dedicated to this\n application organization and environment.\n3. Assign the token only to the intended index and choose a JSON-capable source\n type. Wait until token deployment is complete before testing.\n4. Record the HEC base URL, token owner, index, source type, rotation process and\n retention policy. Store the token only in approved secret stores.\n\nSplunk’s event endpoint expects a body shaped like:\n\n~~~json\n{\n \"time\": 1776631800,\n \"host\": \"application-production\",\n \"source\": \"application-security-audit\",\n \"sourcetype\": \"_json\",\n \"index\": \"security\",\n \"event\": {\n \"eventId\": \"7b45a61c-9bcc-4bf2-9a29-0f111bff6d07\",\n \"eventType\": \"user_login_failed\",\n \"organizationId\": \"org_example\",\n \"severity\": \"warning\"\n }\n}\n~~~\n\nThe relay owns this wrapper and any approved metadata; it must preserve the\napplication event object without renaming `eventId`, `correlationId`, actor,\norganization, timestamp, outcome or severity fields.\n\n### Choose the acknowledgement boundary\n\nA normal HEC success response confirms that HEC accepted the request. Splunk\nalso supports **indexer acknowledgement**, where a client submits a channel\nidentifier and later checks whether the event reached the indexing pipeline.\nIf the relay uses that mode, return success to the application only after the\nrelay’s documented durability boundary; do not hold the application request\nopen indefinitely while waiting for a search result.\n\nWhichever mode you choose, the operating proof is still an exact\n`eventId` search in the intended index. Record separately whether a failure\nhappened before HEC acceptance, while awaiting an indexer acknowledgement, or\nafter indexing during parsing and field extraction.\n\n## Configure the application-to-relay request\n\nRecommended application settings:\n\n| Setting | Value |\n| --- | --- |\n| Destination | Relay HTTPS URL dedicated to the organization/environment |\n| Authentication | `hmac_sha256` or a dedicated `api_key_header` |\n| Format | `json_structured` |\n| Delivery | `batchSize` 1 (one event per request) unless the relay accepts a JSON array; choose timeout/retry values below the relay’s bounded acknowledgement time |\n\nIf a controlled test proves direct HEC compatibility, configure:\n\n| Setting | Direct HEC value |\n| --- | --- |\n| `authMethod` | `api_key_header` |\n| `authHeaderName` | `Authorization` |\n| `authCredential` | The complete value `Splunk HEC_TOKEN`, including the `Splunk ` prefix |\n| `webhookUrl` | The exact HEC event or raw endpoint validated by the Splunk owner |\n\nThe API-key-header mode sends the configured credential verbatim. Do not choose\n`bearer_token`: it would send `Authorization: Bearer ...`, which is not\nSplunk HEC token authentication.\n\n## Prove ingestion, not only HTTP acceptance\n\n1. Keep broad export disabled and select one controlled event type.\n2. Trigger the event and find the source audit row.\n3. Confirm relay/HEC HTTP acceptance without logging the token.\n4. Search the intended Splunk index for the exact `eventId`.\n5. Verify organization, timestamp, event type, severity, actor/outcome and\n correlation identifier.\n6. Trigger an event outside the filter and confirm it remains only in the source\n audit trail.\n7. Temporarily refuse one request, restore the receiver and prove dead-letter\n recovery without creating a duplicate indexed event.\n\n## Splunk documentation to keep with the runbook\n\n- Splunk’s [HTTP Event Collector examples](https://help.splunk.com/en/splunk-enterprise/get-data-in/collect-http-event-data/http-event-collector-examples)\n show the HEC authorization header, event wrapper and endpoint shapes used to\n validate the relay output.\n- Splunk’s [HEC indexer acknowledgement](https://help.splunk.com/en/splunk-enterprise/get-started/get-data-in/9.2/get-data-with-http-event-collector/about-http-event-collector-indexer-acknowledgment)\n documentation explains the optional channel and acknowledgement protocol.\n\nKeep the tested HEC endpoint, source type, acknowledgement mode and sample\nsearch beside these links. Provider documentation defines Splunk’s contract;\nthis guide defines the application envelope that must be conserved.";
257
260
  }, {
258
261
  readonly managedPath: "security-and-audit/siem-microsoft-sentinel.md";
259
262
  readonly unitRef: "technical-documentation:unit/siem-microsoft-sentinel";
260
263
  readonly sourceRefs: readonly ["saas-technical-doc:engine-content/siem-microsoft-sentinel", "source:consumer-fact:organization-siem-export"];
261
- readonly markdown: "# Send audit events to Microsoft Sentinel\n\nMicrosoft Sentinel commonly receives custom data through the Azure Monitor Logs\nIngestion API. That API requires a Data Collection Rule (DCR), a matching JSON\nschema and Microsoft Entra OAuth authorization. The application’s SIEM exporter\nuses a static outbound credential and posts one JSON object per event; it does\nnot acquire or refresh Azure OAuth tokens and does not wrap events as the JSON\narray expected by Logs Ingestion. **Use an Azure-hosted relay rather than pointing\nthe application directly at the Logs Ingestion API.**\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#markdown}}\n\n~~~mermaid\nflowchart LR\n app[\"Application SIEM export\"] -->|\"HMAC or API-key authenticated JSON\"| relay[\"Azure Function, Logic App or API Management relay\"]\n relay --> transform[\"Validate, transform and batch as an array\"]\n transform -->|\"Entra OAuth token\"| dcr[\"Azure Monitor DCR ingestion endpoint\"]\n dcr --> table[\"Log Analytics custom table\"]\n table --> sentinel[\"Microsoft Sentinel analytics\"]\n~~~\n\n## Prepare Azure Monitor and Sentinel\n\n1. Create a custom Log Analytics table whose columns preserve the application\n event identifiers, timestamp, organization, actor, outcome, severity and\n event-specific data needed by detections.\n2. Create a DCR with a direct Logs Ingestion endpoint (or a Data Collection\n Endpoint when private-link architecture requires it), the input stream and a\n transformation into the table.\n3. Create a relay identity and grant it only the DCR ingestion permission it\n needs. Keep Azure client credentials or managed identity inside Azure.\n4. Deploy an HTTPS relay that validates the application request **before**\n parsing, converts the event into the DCR input schema, sends a JSON array to\n Logs Ingestion and returns success only after the chosen delivery boundary.\n\n### Relay input contract\n\nUse `json_structured` so the relay receives the complete application envelope.\nFor HMAC authentication, validate:\n\n~~~text\nX-Signature-256: sha256=LOWERCASE_HEXADECIMAL_HMAC\n~~~\n\nCompute HMAC-SHA256 over the exact received bytes with the shared secret and use\na constant-time comparison. Do not parse and reserialize before verification.\nAlternatively, configure a dedicated API-key header accepted only by the relay.\n\nThe relay should emit a DCR record similar to:\n\n~~~json\n[\n {\n \"TimeGenerated\": \"2026-08-20T19:30:00.000Z\",\n \"EventId\": \"7b45a61c-9bcc-4bf2-9a29-0f111bff6d07\",\n \"CorrelationId\": \"req_01HXEXAMPLE\",\n \"OrganizationId\": \"org_example\",\n \"EventType\": \"user_login_failed\",\n \"Severity\": \"warning\",\n \"Outcome\": \"failure\"\n }\n]\n~~~\n\n## Configure and prove the path\n\n1. Configure the application destination as the relay URL, authentication as\n HMAC or API-key header, and format as structured JSON.\n2. Start with one exact event type and leave broad categories disabled.\n3. Trigger the controlled event and record its source `eventId`.\n4. Prove signature/API-key validation at the relay, DCR acceptance, arrival in\n the custom table and Sentinel queryability by the same `eventId`.\n5. Compare timestamp, organization, actor, outcome and severity with the source\n row; a transformed row must remain traceable.\n6. Refuse an invalid signature and malformed schema without forwarding either.\n7. Simulate an Azure ingestion failure, restore the path, re-enqueue one\n dead-letter row and verify the table contains one intended event.\n\nDo not store a short-lived Azure access token as the application’s static bearer\ncredential; token acquisition and renewal belong to the relay identity.\n\n## Microsoft documentation to keep with the runbook\n\n- The [Logs Ingestion API overview](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/logs-ingestion-api-overview)\n defines the endpoint, JSON-array and OAuth boundaries the relay must satisfy.\n- The [Data Collection Rule overview](https://learn.microsoft.com/en-us/azure/azure-monitor/data-collection/data-collection-rule-overview)\n explains the input stream, destination and transformation relationship.\n- [Data collection transformations](https://learn.microsoft.com/en-us/azure/azure-monitor/data-collection/data-collection-transformations)\n describes the KQL transformation applied before the target table.\n- Microsoft Sentinel’s [data connector reference](https://learn.microsoft.com/en-us/azure/sentinel/connect-data-sources)\n helps the security owner decide whether the resulting table should feed a\n custom connector, analytics rule or another supported ingestion route.\n\nPin the DCR immutable identifier, stream name, table, transformation revision\nand relay identity in the runbook. A portal display name alone is not enough to\nreconstruct or audit the delivery path.";
264
+ readonly markdown: "# Send audit events to Microsoft Sentinel\n\nMicrosoft Sentinel commonly receives custom data through the Azure Monitor Logs\nIngestion API. That API requires a Data Collection Rule (DCR), a matching JSON\nschema and Microsoft Entra OAuth authorization. The application’s SIEM exporter\nuses a static outbound credential and posts one JSON object per event, or a plain\nJSON array when `batchSize` is above 1; it does not acquire or refresh Azure OAuth\ntokens and does not shape events to the Data Collection Rule's schema. **Use an Azure-hosted relay rather than pointing\nthe application directly at the Logs Ingestion API.**\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#markdown}}\n\n~~~mermaid\nflowchart LR\n app[\"Application SIEM export\"] -->|\"HMAC or API-key authenticated JSON\"| relay[\"Azure Function, Logic App or API Management relay\"]\n relay --> transform[\"Validate, transform and batch as an array\"]\n transform -->|\"Entra OAuth token\"| dcr[\"Azure Monitor DCR ingestion endpoint\"]\n dcr --> table[\"Log Analytics custom table\"]\n table --> sentinel[\"Microsoft Sentinel analytics\"]\n~~~\n\n## Prepare Azure Monitor and Sentinel\n\n1. Create a custom Log Analytics table whose columns preserve the application\n event identifiers, timestamp, organization, actor, outcome, severity and\n event-specific data needed by detections.\n2. Create a DCR with a direct Logs Ingestion endpoint (or a Data Collection\n Endpoint when private-link architecture requires it), the input stream and a\n transformation into the table.\n3. Create a relay identity and grant it only the DCR ingestion permission it\n needs. Keep Azure client credentials or managed identity inside Azure.\n4. Deploy an HTTPS relay that validates the application request **before**\n parsing, converts the event into the DCR input schema, sends a JSON array to\n Logs Ingestion and returns success only after the chosen delivery boundary.\n\n### Relay input contract\n\nUse `json_structured` so the relay receives the complete application envelope.\nFor HMAC authentication, validate:\n\n~~~text\nX-Signature-256: sha256=LOWERCASE_HEXADECIMAL_HMAC\n~~~\n\nCompute HMAC-SHA256 over the exact received bytes with the shared secret and use\na constant-time comparison. Do not parse and reserialize before verification.\nAlternatively, configure a dedicated API-key header accepted only by the relay.\n\nThe relay should emit a DCR record similar to:\n\n~~~json\n[\n {\n \"TimeGenerated\": \"2026-08-20T19:30:00.000Z\",\n \"EventId\": \"7b45a61c-9bcc-4bf2-9a29-0f111bff6d07\",\n \"CorrelationId\": \"req_01HXEXAMPLE\",\n \"OrganizationId\": \"org_example\",\n \"EventType\": \"user_login_failed\",\n \"Severity\": \"warning\",\n \"Outcome\": \"failure\"\n }\n]\n~~~\n\n## Configure and prove the path\n\n1. Configure the application destination as the relay URL, authentication as\n HMAC or API-key header, and format as structured JSON.\n2. Start with one exact event type and leave broad categories disabled.\n3. Trigger the controlled event and record its source `eventId`.\n4. Prove signature/API-key validation at the relay, DCR acceptance, arrival in\n the custom table and Sentinel queryability by the same `eventId`.\n5. Compare timestamp, organization, actor, outcome and severity with the source\n row; a transformed row must remain traceable.\n6. Refuse an invalid signature and malformed schema without forwarding either.\n7. Simulate an Azure ingestion failure, restore the path, re-enqueue one\n dead-letter row and verify the table contains one intended event.\n\nDo not store a short-lived Azure access token as the application’s static bearer\ncredential; token acquisition and renewal belong to the relay identity.\n\n## Microsoft documentation to keep with the runbook\n\n- The [Logs Ingestion API overview](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/logs-ingestion-api-overview)\n defines the endpoint, JSON-array and OAuth boundaries the relay must satisfy.\n- The [Data Collection Rule overview](https://learn.microsoft.com/en-us/azure/azure-monitor/data-collection/data-collection-rule-overview)\n explains the input stream, destination and transformation relationship.\n- [Data collection transformations](https://learn.microsoft.com/en-us/azure/azure-monitor/data-collection/data-collection-transformations)\n describes the KQL transformation applied before the target table.\n- Microsoft Sentinel’s [data connector reference](https://learn.microsoft.com/en-us/azure/sentinel/connect-data-sources)\n helps the security owner decide whether the resulting table should feed a\n custom connector, analytics rule or another supported ingestion route.\n\nPin the DCR immutable identifier, stream name, table, transformation revision\nand relay identity in the runbook. A portal display name alone is not enough to\nreconstruct or audit the delivery path.";
262
265
  }, {
263
266
  readonly managedPath: "security-and-audit/siem-elastic.md";
264
267
  readonly unitRef: "technical-documentation:unit/siem-elastic";
265
268
  readonly sourceRefs: readonly ["saas-technical-doc:engine-content/siem-elastic", "source:consumer-fact:organization-siem-export"];
266
- readonly markdown: "# Send audit events to Elastic\n\nElastic Filebeat’s `http_endpoint` input can receive an HTTPS POST containing a\nJSON object and can validate a fixed secret header or an HMAC signature. This is\na close match for the application’s one-event structured JSON delivery. Run the\nlistener behind a production TLS and network boundary; the example below is a\nstarting contract, not a complete Elastic deployment.\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#markdown}}\n\n## Configure the receiver\n\nThe following Filebeat shape places the application envelope at the document\nroot and validates a dedicated header:\n\n~~~yaml\nfilebeat.inputs:\n - type: http_endpoint\n enabled: true\n listen_address: 0.0.0.0\n listen_port: 8443\n url: /application-security-audit\n prefix: \".\"\n content_type: application/json\n secret.header: X-Application-SIEM-Token\n secret.value: ${APPLICATION_SIEM_TOKEN}\n ssl.enabled: true\n ssl.certificate: /run/secrets/tls.crt\n ssl.key: /run/secrets/tls.key\n tags: [application-security-audit]\n~~~\n\nConfigure the application with:\n\n| Setting | Value |\n| --- | --- |\n| `webhookUrl` | Public/proxied HTTPS endpoint ending in `/application-security-audit` |\n| `authMethod` | `api_key_header` |\n| `authHeaderName` | `X-Application-SIEM-Token` |\n| `authCredential` | The same dedicated secret value, stored once |\n| `eventFormat` | `json_structured` |\n\nFor HMAC instead, configure the Elastic input’s HMAC header as\n`X-Signature-256`, type `sha256`, prefix `sha256=` and the same shared key;\nthen select `hmac_sha256` in the application. Keep either mechanism scoped to\none organization/environment.\n\n## Map and retain the event\n\nKeep the complete application envelope in a controlled namespace, then add\nElastic Common Schema (ECS) fields through an ingest pipeline. Do not destroy\nthe source value merely to make it resemble an ECS value.\n\n~~~mermaid\nflowchart LR\n accTitle: Preserve the source event while creating an Elastic search view\n accDescr: Filebeat receives the application JSON envelope. An ingest pipeline preserves it under an application audit namespace, copies only semantically compatible values into Elastic Common Schema fields, sends the document to a scoped data stream, and makes source and normalized identifiers available to searches and detections.\n receive[\"Filebeat HTTP endpoint\"] --> pipeline[\"Ingest pipeline\"]\n pipeline --> original[\"Preserved application.audit fields\"]\n pipeline --> ecs[\"Explicit ECS mappings\"]\n original --> stream[\"Scoped data stream\"]\n ecs --> stream\n stream --> search[\"Search, dashboards and detections\"]\n~~~\n\n| Application field | Safe Elastic treatment | Important condition |\n| --- | --- | --- |\n| `timestamp` | Copy to `@timestamp` | Parse as the source-event time; keep receiver ingestion time distinct |\n| `eventId` | Copy to `event.id` | Preserve as an exact keyword for correlation and deduplication |\n| `eventType` | Copy to `event.action` | Keep the original identifier unchanged |\n| `eventCategory` | Preserve under `application.audit.category` | Map to ECS `event.category` only when the value is translated to an allowed ECS category |\n| `severity` | Preserve the source label; optionally derive numeric `event.severity` | ECS severity is numeric, so a text value such as `warning` needs an explicit mapping |\n| `outcome` | Preserve the source value; copy to `event.outcome` only after validation | ECS restricts outcome values; do not copy an incompatible value blindly |\n| `correlationId` | Preserve under `application.audit.correlation_id` | Use `trace.id` only when the identifier truly represents the same distributed trace |\n| `organizationId` and `applicationId` | Preserve as exact scoped keywords | Use them in data-stream access controls and investigation filters |\n\nActor/user identifiers and authentication source remain important for\ninvestigation, but map them only after deciding whether each identifier denotes\nthe acting account, the affected account or another subject. A convenient\n`user.id` mapping that merges those roles makes investigations misleading.\n\nApply an ingest pipeline or index template deliberately. Do not let dynamic\nmapping turn identifiers into analyzed text or allow arbitrary event data to\ncause uncontrolled field growth.\n\n## Prove end-to-end behavior\n\n1. Run the receiver on a controlled endpoint and confirm TLS trust from the\n application runtime.\n2. Send one selected test event and find it in the source audit trail.\n3. Confirm the Elastic input acknowledges the request, then search by exact\n `eventId` in the target data stream/index.\n4. Compare organization, time, event type, severity, actor and outcome.\n5. Send a wrong header value or signature and confirm Elastic returns 401 and\n the document is absent.\n6. Return a temporary 503, restore the endpoint and prove dead-letter recovery\n without an unintended duplicate detection.\n7. Record receiver capacity for **one request per selected event**; application\n batching fields are currently reserved and do not reduce that rate.\n\n## Elastic documentation to keep with the runbook\n\n- The [Filebeat HTTP Endpoint input reference](https://www.elastic.co/docs/reference/beats/filebeat/filebeat-input-http_endpoint)\n defines JSON-object handling, secret headers, HMAC validation, response codes\n and acknowledgement options.\n- The [ECS event field reference](https://www.elastic.co/docs/reference/ecs/ecs-event)\n defines fields such as `event.id`, `event.action`, `event.category`,\n `event.outcome` and `event.severity`.\n- Elastic’s [custom fields guidance](https://www.elastic.co/docs/reference/ecs/ecs-custom-fields-in-ecs)\n and [ECS mapping guidelines](https://www.elastic.co/docs/reference/ecs/ecs-guidelines)\n explain how to preserve application-owned semantics without creating field\n conflicts.\n- The Elastic Security [SIEM field reference](https://www.elastic.co/docs/reference/security/fields-and-object-schemas/siem-field-reference)\n identifies fields used by detections and investigations; treat it as a\n consumer requirement, not permission to invent missing source meaning.\n\nVersion the index template and ingest pipeline with the runbook. Re-run the\ncontrolled-event proof after changing either one, because successful HTTP\ndelivery can coexist with a broken mapping or detection.";
269
+ readonly markdown: "# Send audit events to Elastic\n\nElastic Filebeat’s `http_endpoint` input can receive an HTTPS POST containing a\nJSON object and can validate a fixed secret header or an HMAC signature. This is\na close match for the application’s one-event structured JSON delivery. Run the\nlistener behind a production TLS and network boundary; the example below is a\nstarting contract, not a complete Elastic deployment.\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#markdown}}\n\n## Configure the receiver\n\nThe following Filebeat shape places the application envelope at the document\nroot and validates a dedicated header:\n\n~~~yaml\nfilebeat.inputs:\n - type: http_endpoint\n enabled: true\n listen_address: 0.0.0.0\n listen_port: 8443\n url: /application-security-audit\n prefix: \".\"\n content_type: application/json\n secret.header: X-Application-SIEM-Token\n secret.value: ${APPLICATION_SIEM_TOKEN}\n ssl.enabled: true\n ssl.certificate: /run/secrets/tls.crt\n ssl.key: /run/secrets/tls.key\n tags: [application-security-audit]\n~~~\n\nConfigure the application with:\n\n| Setting | Value |\n| --- | --- |\n| `webhookUrl` | Public/proxied HTTPS endpoint ending in `/application-security-audit` |\n| `authMethod` | `api_key_header` |\n| `authHeaderName` | `X-Application-SIEM-Token` |\n| `authCredential` | The same dedicated secret value, stored once |\n| `eventFormat` | `json_structured` |\n\nFor HMAC instead, configure the Elastic input’s HMAC header as\n`X-Signature-256`, type `sha256`, prefix `sha256=` and the same shared key;\nthen select `hmac_sha256` in the application. Keep either mechanism scoped to\none organization/environment.\n\n## Map and retain the event\n\nKeep the complete application envelope in a controlled namespace, then add\nElastic Common Schema (ECS) fields through an ingest pipeline. Do not destroy\nthe source value merely to make it resemble an ECS value.\n\n~~~mermaid\nflowchart LR\n accTitle: Preserve the source event while creating an Elastic search view\n accDescr: Filebeat receives the application JSON envelope. An ingest pipeline preserves it under an application audit namespace, copies only semantically compatible values into Elastic Common Schema fields, sends the document to a scoped data stream, and makes source and normalized identifiers available to searches and detections.\n receive[\"Filebeat HTTP endpoint\"] --> pipeline[\"Ingest pipeline\"]\n pipeline --> original[\"Preserved application.audit fields\"]\n pipeline --> ecs[\"Explicit ECS mappings\"]\n original --> stream[\"Scoped data stream\"]\n ecs --> stream\n stream --> search[\"Search, dashboards and detections\"]\n~~~\n\n| Application field | Safe Elastic treatment | Important condition |\n| --- | --- | --- |\n| `timestamp` | Copy to `@timestamp` | Parse as the source-event time; keep receiver ingestion time distinct |\n| `eventId` | Copy to `event.id` | Preserve as an exact keyword for correlation and deduplication |\n| `eventType` | Copy to `event.action` | Keep the original identifier unchanged |\n| `eventCategory` | Preserve under `application.audit.category` | Map to ECS `event.category` only when the value is translated to an allowed ECS category |\n| `severity` | Preserve the source label; optionally derive numeric `event.severity` | ECS severity is numeric, so a text value such as `warning` needs an explicit mapping |\n| `outcome` | Preserve the source value; copy to `event.outcome` only after validation | ECS restricts outcome values; do not copy an incompatible value blindly |\n| `correlationId` | Preserve under `application.audit.correlation_id` | Use `trace.id` only when the identifier truly represents the same distributed trace |\n| `organizationId` and `applicationId` | Preserve as exact scoped keywords | Use them in data-stream access controls and investigation filters |\n\nActor/user identifiers and authentication source remain important for\ninvestigation, but map them only after deciding whether each identifier denotes\nthe acting account, the affected account or another subject. A convenient\n`user.id` mapping that merges those roles makes investigations misleading.\n\nApply an ingest pipeline or index template deliberately. Do not let dynamic\nmapping turn identifiers into analyzed text or allow arbitrary event data to\ncause uncontrolled field growth.\n\n## Prove end-to-end behavior\n\n1. Run the receiver on a controlled endpoint and confirm TLS trust from the\n application runtime.\n2. Send one selected test event and find it in the source audit trail.\n3. Confirm the Elastic input acknowledges the request, then search by exact\n `eventId` in the target data stream/index.\n4. Compare organization, time, event type, severity, actor and outcome.\n5. Send a wrong header value or signature and confirm Elastic returns 401 and\n the document is absent.\n6. Return a temporary 503, restore the endpoint and prove dead-letter recovery\n without an unintended duplicate detection.\n7. Record receiver capacity for the request rate you configure: **one request per\n selected event** at the default `batchSize` of 1, or one per batch above it.\n\n## Elastic documentation to keep with the runbook\n\n- The [Filebeat HTTP Endpoint input reference](https://www.elastic.co/docs/reference/beats/filebeat/filebeat-input-http_endpoint)\n defines JSON-object handling, secret headers, HMAC validation, response codes\n and acknowledgement options.\n- The [ECS event field reference](https://www.elastic.co/docs/reference/ecs/ecs-event)\n defines fields such as `event.id`, `event.action`, `event.category`,\n `event.outcome` and `event.severity`.\n- Elastic’s [custom fields guidance](https://www.elastic.co/docs/reference/ecs/ecs-custom-fields-in-ecs)\n and [ECS mapping guidelines](https://www.elastic.co/docs/reference/ecs/ecs-guidelines)\n explain how to preserve application-owned semantics without creating field\n conflicts.\n- The Elastic Security [SIEM field reference](https://www.elastic.co/docs/reference/security/fields-and-object-schemas/siem-field-reference)\n identifies fields used by detections and investigations; treat it as a\n consumer requirement, not permission to invent missing source meaning.\n\nVersion the index template and ingest pipeline with the runbook. Re-run the\ncontrolled-event proof after changing either one, because successful HTTP\ndelivery can coexist with a broken mapping or detection.";
267
270
  }, {
268
271
  readonly managedPath: "security-and-audit/operate-siem.md";
269
272
  readonly unitRef: "technical-documentation:unit/operate-and-troubleshoot-siem-delivery";
@@ -343,17 +346,17 @@ export declare const APPLICATION_CONSUMER_DOCUMENTATION_AUTHORED_CONTENT_V1: rea
343
346
  readonly managedPath: "integrations/rest/conventions.md";
344
347
  readonly unitRef: "technical-documentation:unit/rest-api-conventions";
345
348
  readonly sourceRefs: readonly ["saas-technical-doc:engine-content/rest-api-conventions", "source:companion-projection:application-connection", "source:consumer-fact:access-api-keys", "source:consumer-fact:rest-conventions"];
346
- readonly markdown: "# REST API conventions\n\nEvery operation in the API reference follows the same rules for addressing, authentication, collections, writes, errors and limits. Read this page once. After that, an operation's entry in the reference only has to tell you what is specific to it: its path, its fields, the roles it accepts and the failures it can return.\n\n## Addressing\n\n- Every path in the API reference already starts with the `/api/v1` mount. Prepend the base URL of the environment you are calling:\n\n{{APPLICATION_CONNECTION:baseUrls}}\n\n- Organization data lives under `/api/v1/organizations/{organizationId}/…`. The organization identifier is the one shown in the application. A collection under an organization your credential is not a member of answers **403**; a single record that belongs to another organization answers **404**, so that the application never confirms what exists outside your scope.\n- The same resource is often reachable through more than one parent path (for example through the organization directly and through a related record). Those paths are aliases of one operation and answer with the same data; use whichever matches the identifiers you already hold.\n- Send and expect `application/json`. Identifiers are opaque strings: store them, compare them, never parse them.\n- Header names are case-insensitive; this documentation writes them the way the application emits them.\n\n## Authentication\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#markdown}}\n\nSigned-in people and OAuth clients use a bearer token instead: `Authorization: Bearer <access token>`. Each operation's **Security** entry in the reference lists which of the two it accepts. Send exactly one credential per request.\n\n## Collections\n\nList and search operations share one query vocabulary:\n\n{{CONSUMER_FACT:source:consumer-fact:rest-conventions#collectionQueryMarkdown}}\n\n{{CONSUMER_FACT:source:consumer-fact:rest-conventions#paginationResponseMarkdown}}\n\nA concrete request and its response, using the members of your own organization:\n\n~~~bash\ncurl --fail-with-body \\\n --url \"$BASE_URL/api/v1/organizations/$ORGANIZATION_ID/organization-members?page=1&limit=20&sort=joinedAt:desc\" \\\n --header \"Authorization: $ORGANIZATION_API_KEY\" \\\n --header \"accept: application/json\"\n~~~\n\n~~~json\n{\n \"data\": [\n {\n \"_id\": \"0d3f2a9e-6c41-4b7a-8e15-5f9c2b7d4a10\",\n \"userId\": \"b8e4c2f1-3a57-4d09-9f6e-1c2d3e4f5a6b\",\n \"userEmail\": \"alex.morgan@example.com\",\n \"organizationId\": \"7c1f6f0a-4b1e-4d8f-9a0c-2e5b3c9d1f42\",\n \"roles\": [\"ORG_MEMBER\"],\n \"status\": \"ACTIVE\",\n \"createdAt\": \"2026-07-03T09:15:00.000Z\",\n \"updatedAt\": \"2026-08-18T08:00:00.000Z\",\n \"_version\": 4\n }\n ],\n \"pagination\": { \"page\": 1, \"limit\": 20, \"total\": 1, \"totalPages\": 1 }\n}\n~~~\n\n## Writes\n\n- The reference states each operation's success status and the fields it accepts. A field you see in a read response is not automatically writable; send only what the request schema lists.\n- Operations marked **idempotent** in the reference can be repeated safely. For any other write, a lost response is an ambiguous outcome: read the record back before sending the write again. [Write and reconcile changes](/integrations/rest/write-and-reconcile) shows the procedure.\n- Bulk variants (`…/bulk` paths) apply one change to several identifiers. Read the operation's response schema before assuming every identifier was applied, and reconcile each one with a read after a failure.\n\n{{CONSUMER_FACT:source:consumer-fact:rest-conventions#concurrencyMarkdown}}\n\n## Errors\n\n{{CONSUMER_FACT:source:consumer-fact:rest-conventions#errorEnvelopeMarkdown}}\n\nFor example, removing the last owner of an organization is refused like this:\n\n~~~json\n{{CONSUMER_FACT:source:consumer-fact:rest-conventions#errorExampleJson}}\n~~~\n\nBranch on the HTTP status first, then on `error.type`, and on `error.code` only for refusals the operation documents by name:\n\n{{CONSUMER_FACT:source:consumer-fact:rest-conventions#errorStatusMarkdown}}\n\n## Rate limits\n\nThe application enforces several windows at once and reports the tightest one:\n\n{{CONSUMER_FACT:source:consumer-fact:rest-conventions#rateLimitMarkdown}}\n\nBack off when `x-ratelimit-remaining` reaches zero rather than waiting for the **429**. Parallel workers share the same counters when they share a credential.\n\n## Support evidence\n\nWhen you ask for help, quote the operation path, the HTTP status, `error.type`, `error.code` when present, and `error.correlationId`. That identifier joins your request to the application's logs and audit trail and contains no personal data. Never paste a credential, a bearer token or a full response body into a ticket.";
349
+ readonly markdown: "# REST API conventions\n\nEvery operation in the API reference follows the same rules for addressing, authentication, collections, writes, errors and limits. Read this page once. After that, an operation's entry in the reference only has to tell you what is specific to it: its path, its fields, the roles it accepts and the failures it can return.\n\n## Addressing\n\n- Every path in the API reference already starts with the `/api/v1` mount. Prepend the base URL of the environment you are calling:\n\n{{APPLICATION_CONNECTION:baseUrls}}\n\n- Organization data lives under `/api/v1/organizations/{organizationId}/…`. The organization identifier is the one shown in the application. A collection under an organization your credential is not a member of answers **403**; a single record that belongs to another organization answers **404**, so that the application never confirms what exists outside your scope.\n- The same resource is often reachable through more than one parent path (for example through the organization directly and through a related record). Those paths are aliases of one operation and answer with the same data; use whichever matches the identifiers you already hold.\n- Send and expect `application/json`. Identifiers are opaque strings: store them, compare them, never parse them.\n- Header names are case-insensitive; this documentation writes them the way the application emits them.\n\n## Authentication\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#markdown}}\n\nSigned-in people and OAuth clients use a bearer token instead: `Authorization: Bearer <access token>`. Each operation's **Security** entry in the reference lists which of the two it accepts. Send exactly one credential per request.\n\n## Collections\n\nList and search operations share one query vocabulary:\n\n{{CONSUMER_FACT:source:consumer-fact:rest-conventions#collectionQueryMarkdown}}\n\n{{CONSUMER_FACT:source:consumer-fact:rest-conventions#paginationResponseMarkdown}}\n\nA concrete request and its response, using the members of your own organization:\n\n~~~bash\ncurl --fail-with-body \\\n --url \"$BASE_URL/api/v1/organizations/$ORGANIZATION_ID/organization-members?page=1&limit=20&sort=createdAt:desc\" \\\n --header \"Authorization: $ORGANIZATION_API_KEY\" \\\n --header \"accept: application/json\"\n~~~\n\n~~~json\n{\n \"data\": [\n {\n \"_id\": \"0d3f2a9e-6c41-4b7a-8e15-5f9c2b7d4a10\",\n \"userId\": \"b8e4c2f1-3a57-4d09-9f6e-1c2d3e4f5a6b\",\n \"userEmail\": \"alex.morgan@example.com\",\n \"organizationId\": \"7c1f6f0a-4b1e-4d8f-9a0c-2e5b3c9d1f42\",\n \"roles\": [\"ORG_MEMBER\"],\n \"status\": \"ACTIVE\",\n \"createdAt\": \"2026-07-03T09:15:00.000Z\",\n \"updatedAt\": \"2026-08-18T08:00:00.000Z\",\n \"_version\": 4\n }\n ],\n \"pagination\": { \"page\": 1, \"limit\": 20, \"total\": 1, \"totalPages\": 1 }\n}\n~~~\n\n## Writes\n\n- The reference states each operation's success status and the fields it accepts. A field you see in a read response is not automatically writable; send only what the request schema lists.\n- Operations marked **idempotent** in the reference can be repeated safely. For any other write, a lost response is an ambiguous outcome: read the record back before sending the write again. [Write and reconcile changes](/integrations/rest/write-and-reconcile) shows the procedure.\n- Bulk variants (`…/bulk` paths) apply one change to several identifiers. Read the operation's response schema before assuming every identifier was applied, and reconcile each one with a read after a failure.\n\n{{CONSUMER_FACT:source:consumer-fact:rest-conventions#concurrencyMarkdown}}\n\n## Errors\n\n{{CONSUMER_FACT:source:consumer-fact:rest-conventions#errorEnvelopeMarkdown}}\n\nFor example, removing the last owner of an organization is refused like this:\n\n~~~json\n{{CONSUMER_FACT:source:consumer-fact:rest-conventions#errorExampleJson}}\n~~~\n\nBranch on the HTTP status first, then on `error.type`, and on `error.code` only for refusals the operation documents by name:\n\n{{CONSUMER_FACT:source:consumer-fact:rest-conventions#errorStatusMarkdown}}\n\n## Rate limits\n\nThe application enforces several windows at once and reports the tightest one:\n\n{{CONSUMER_FACT:source:consumer-fact:rest-conventions#rateLimitMarkdown}}\n\nBack off when `x-ratelimit-remaining` reaches zero rather than waiting for the **429**. Parallel workers share the same counters when they share a credential.\n\n## Support evidence\n\nWhen you ask for help, quote the operation path, the HTTP status, `error.type`, `error.code` when present, and `error.correlationId`. That identifier joins your request to the application's logs and audit trail and contains no personal data. Never paste a credential, a bearer token or a full response body into a ticket.";
347
350
  }, {
348
351
  readonly managedPath: "integrations/rest/send-request.md";
349
352
  readonly unitRef: "technical-documentation:unit/send-api-request";
350
353
  readonly sourceRefs: readonly ["saas-technical-doc:engine-content/send-api-request", "source:companion-projection:application-connection", "source:consumer-fact:access-api-keys"];
351
- readonly markdown: "# Send your first API request\n\nTen minutes from an API key to a verified connection. The first request proves four things and nothing else: you reached the right environment, the credential is accepted, it sees the organization you expect, and you can read the response. Use a read operation that changes nothing.\n\n## What you need\n\n- The **base URL** of the environment you are calling. {{APPLICATION_NAME}} publishes these:\n\n{{APPLICATION_CONNECTION:baseUrls}}\n\n- Your **organization identifier**, shown in the application's organization settings and present in the URL of most screens.\n- An **organization API key** created for this integration, following [Create and store an API key](/access-and-identity/api-keys-create-and-store). Keep it in a secret store or an environment variable, never in the request URL or a build log.\n\nGive the request a name in your notes before you send it. \"List the members of the Support organization, expect Alex Morgan\" is a result you can check; \"the call returned JSON\" is not.\n\n## Step 1: read your own organization\n\nThe safest first call reads the organization the key belongs to. It needs no other identifier and changes nothing.\n\n~~~bash\nBASE_URL=\"{{APPLICATION_CONNECTION_VALUE:baseUrl}}\" # this application's own origin\nORGANIZATION_ID=\"7c1f6f0a-4b1e-4d8f-9a0c-2e5b3c9d1f42\" # from the application's organization settings\nORGANIZATION_API_KEY=\"sk_org_…\" # the key you created\n\ncurl --fail-with-body \\\n --url \"$BASE_URL/api/v1/organizations/$ORGANIZATION_ID\" \\\n {{CONSUMER_FACT:source:consumer-fact:access-api-keys#curlRequestHeader}} \\\n --header \"accept: application/json\"\n~~~\n\nReplace the organization id and the key with yours; the base URL above is already this application's. Leave the header exactly as shown. {{CONSUMER_FACT:source:consumer-fact:access-api-keys#markdown}}\n\nA successful answer is **200** with the organization record: its `_id` is the identifier you sent, and `name` is the organization you expected. Anything else, read the [failure table](#if-it-fails) below before changing more than one thing.\n\n## Step 2: read a collection\n\nNow list the organization's members. This exercises the collection envelope you will meet on every list and search operation:\n\n~~~bash\ncurl --fail-with-body \\\n --url \"$BASE_URL/api/v1/organizations/$ORGANIZATION_ID/organization-members?limit=5&sort=joinedAt:desc\" \\\n --header \"Authorization: $ORGANIZATION_API_KEY\" \\\n --header \"accept: application/json\"\n~~~\n\nThe response is `{ \"data\": [ … ], \"pagination\": { \"page\": 1, \"limit\": 5, \"total\": …, \"totalPages\": … } }`. Check that `total` matches the member count you see in the application. [Read collections](/integrations/rest/read-collections) covers paging, sorting and filters in full.\n\n## Step 3: prove the boundary holds\n\nA connection is only safe when a wrong credential is refused. Send the first request again with the key deliberately broken:\n\n~~~bash\ncurl --include \\\n --url \"$BASE_URL/api/v1/organizations/$ORGANIZATION_ID\" \\\n --header \"Authorization: sk_org_not_a_real_key\" \\\n --header \"accept: application/json\"\n~~~\n\nExpect **401** with `\"type\": \"AUTHENTICATION\"` in the error body. Then send the correct key against an organization it does not belong to and expect **404**: the application does not confirm that organizations outside your scope exist. Those two refusals are the negative proof; record them beside the successful read.\n\n## If it fails\n\n| You see | It means | Do this |\n| --- | --- | --- |\n| No response, or a TLS or DNS error | The base URL is wrong or unreachable from where you run | Compare the URL with the Servers list; test from the network the integration will run on |\n| **401** `AUTHENTICATION` | The key was not accepted | Check the header carries the full key with no `Bearer` prefix, that the key is `active`, and that it belongs to this environment |\n| **403** `AUTHORIZATION` | The key is valid but its roles do not allow this operation | Compare the roles on the key with the roles the operation lists in the reference |\n| **404** `NOT_FOUND` | The organization identifier is wrong, or this key cannot see it | Copy the identifier from the application again |\n| **429** `RATE_LIMIT` | Too many requests | Wait `Retry-After` seconds |\n\nEvery error an operation produces carries `error.correlationId`. Quote it when you ask for help. [Troubleshoot an API request](/integrations/rest/troubleshoot) goes deeper.\n\n## Before your first write\n\nRepeat Step 1 from the environment where the integration will actually run. Then rotate the key once ([API key lifecycle](/access-and-identity/api-keys-lifecycle)) to prove that the operating procedure works before you depend on it. Only then choose one small write and read [Write and reconcile changes](/integrations/rest/write-and-reconcile).";
354
+ readonly markdown: "# Send your first API request\n\nTen minutes from an API key to a verified connection. The first request proves four things and nothing else: you reached the right environment, the credential is accepted, it sees the organization you expect, and you can read the response. Use a read operation that changes nothing.\n\n## What you need\n\n- The **base URL** of the environment you are calling. {{APPLICATION_NAME}} publishes these:\n\n{{APPLICATION_CONNECTION:baseUrls}}\n\n- Your **organization identifier**, shown in the application's organization settings and present in the URL of most screens.\n- An **organization API key** created for this integration, following [Create and store an API key](/access-and-identity/api-keys-create-and-store). Keep it in a secret store or an environment variable, never in the request URL or a build log.\n\nGive the request a name in your notes before you send it. \"List the members of the Support organization, expect Alex Morgan\" is a result you can check; \"the call returned JSON\" is not.\n\n## Step 1: read your own organization\n\nThe safest first call reads the organization the key belongs to. It needs no other identifier and changes nothing.\n\n~~~bash\nBASE_URL=\"{{APPLICATION_CONNECTION_VALUE:baseUrl}}\" # this application's own origin\nORGANIZATION_ID=\"7c1f6f0a-4b1e-4d8f-9a0c-2e5b3c9d1f42\" # from the application's organization settings\nORGANIZATION_API_KEY=\"sk_org_…\" # the key you created\n\ncurl --fail-with-body \\\n --url \"$BASE_URL/api/v1/organizations/$ORGANIZATION_ID\" \\\n {{CONSUMER_FACT:source:consumer-fact:access-api-keys#curlRequestHeader}} \\\n --header \"accept: application/json\"\n~~~\n\nReplace the organization id and the key with yours; the base URL above is already this application's. Leave the header exactly as shown. {{CONSUMER_FACT:source:consumer-fact:access-api-keys#markdown}}\n\nA successful answer is **200** with the organization record: its `_id` is the identifier you sent, and `name` is the organization you expected. Anything else, read the [failure table](#if-it-fails) below before changing more than one thing.\n\n## Step 2: read a collection\n\nNow list the organization's members. This exercises the collection envelope you will meet on every list and search operation:\n\n~~~bash\ncurl --fail-with-body \\\n --url \"$BASE_URL/api/v1/organizations/$ORGANIZATION_ID/organization-members?limit=5&sort=createdAt:desc\" \\\n --header \"Authorization: $ORGANIZATION_API_KEY\" \\\n --header \"accept: application/json\"\n~~~\n\nThe response is `{ \"data\": [ … ], \"pagination\": { \"page\": 1, \"limit\": 5, \"total\": …, \"totalPages\": … } }`. Check that `total` matches the member count you see in the application. [Read collections](/integrations/rest/read-collections) covers paging, sorting and filters in full.\n\n## Step 3: prove the boundary holds\n\nA connection is only safe when a wrong credential is refused. Send the first request again with the key deliberately broken:\n\n~~~bash\ncurl --include \\\n --url \"$BASE_URL/api/v1/organizations/$ORGANIZATION_ID\" \\\n --header \"Authorization: sk_org_not_a_real_key\" \\\n --header \"accept: application/json\"\n~~~\n\nExpect **401** with `\"type\": \"AUTHENTICATION\"` in the error body. Then send the correct key against an organization it does not belong to and expect **404**: the application does not confirm that organizations outside your scope exist. Those two refusals are the negative proof; record them beside the successful read.\n\n## If it fails\n\n| You see | It means | Do this |\n| --- | --- | --- |\n| No response, or a TLS or DNS error | The base URL is wrong or unreachable from where you run | Compare the URL with the Servers list; test from the network the integration will run on |\n| **401** `AUTHENTICATION` | The key was not accepted | Check the header carries the full key with no `Bearer` prefix, that the key is `active`, and that it belongs to this environment |\n| **403** `AUTHORIZATION` | The key is valid but its roles do not allow this operation | Compare the roles on the key with the roles the operation lists in the reference |\n| **404** `NOT_FOUND` | The organization identifier is wrong, or this key cannot see it | Copy the identifier from the application again |\n| **429** `RATE_LIMIT` | Too many requests | Wait `Retry-After` seconds |\n\nEvery error an operation produces carries `error.correlationId`. Quote it when you ask for help. [Troubleshoot an API request](/integrations/rest/troubleshoot) goes deeper.\n\n## Before your first write\n\nRepeat Step 1 from the environment where the integration will actually run. Then rotate the key once ([API key lifecycle](/access-and-identity/api-keys-lifecycle)) to prove that the operating procedure works before you depend on it. Only then choose one small write and read [Write and reconcile changes](/integrations/rest/write-and-reconcile).";
352
355
  }, {
353
356
  readonly managedPath: "integrations/rest/read-collections.md";
354
357
  readonly unitRef: "technical-documentation:unit/work-with-api-collections";
355
358
  readonly sourceRefs: readonly ["saas-technical-doc:engine-content/work-with-api-collections", "source:consumer-fact:rest-conventions"];
356
- readonly markdown: "# Read collections\n\nA collection is the set of records one list or search operation lets your credential see in one organization. Read it in pages, sort it deliberately, filter it on the fields the operation offers, and stop where the response says to stop. Every list and search operation in the API reference uses the vocabulary below.\n\n## The query vocabulary\n\n{{CONSUMER_FACT:source:consumer-fact:rest-conventions#collectionQueryMarkdown}}\n\nFilter and sort fields are per operation. Each operation's entry in the API reference lists them as query parameters, so open the operation before writing the request; a filter accepted by one resource is not a convention for another.\n\n## The response envelope\n\n{{CONSUMER_FACT:source:consumer-fact:rest-conventions#paginationResponseMarkdown}}\n\nAn empty `data` array on page 1 is a valid answer. Confirm the organization and the filters before treating it as a failure.\n\n## Walk every page\n\n~~~bash\npage=1\nwhile : ; do\n response=$(curl --fail-with-body --silent \\\n --url \"$BASE_URL/api/v1/organizations/$ORGANIZATION_ID/organization-members?page=$page&limit=100&sort=joinedAt:asc\" \\\n --header \"Authorization: $ORGANIZATION_API_KEY\" \\\n --header \"accept: application/json\")\n echo \"$response\" | jq -c '.data[]' >> members.ndjson\n totalPages=$(echo \"$response\" | jq '.pagination.totalPages')\n [ \"$page\" -ge \"$totalPages\" ] && break\n page=$((page + 1))\ndone\n~~~\n\nThree rules keep a scan correct:\n\n1. **Sort by a field the reference lists as sortable, or a stable timestamp** such as `joinedAt:asc` for members, when you walk more than one page. A sort field the operation does not accept is ignored, not refused, and the default order applies; sorting by a field that changes during the scan (a status, a name being edited) can move a record between pages and make you skip or repeat it.\n2. **Stop on `totalPages`**, not on a short page. The last page is short by definition; an earlier page is short only when records were deleted while you scanned.\n3. **Process each record idempotently** and key your own records on `_id`. If the scan is interrupted, resume from the last page whose work you completed; repeating a page is safe when processing is idempotent, skipping one never is.\n\n## Search and filter\n\nSearch operations (`…/search`) add `q` for free text. Combine it with filters and sorting:\n\n~~~bash\ncurl --fail-with-body \\\n --url \"$BASE_URL/api/v1/organizations/$ORGANIZATION_ID/organization-members/search?q=morgan&status=ACTIVE&sort=joinedAt:desc\" \\\n --header \"Authorization: $ORGANIZATION_API_KEY\" \\\n --header \"accept: application/json\"\n~~~\n\nDate-range filters are objects and use bracket notation, one key per bound:\n\n~~~text\n?createdAt[startDate]=2026-09-01T00:00:00Z&createdAt[endDate]=2026-09-30T23:59:59Z\n~~~\n\nSend instants in ISO 8601 with a timezone. An unparseable bound answers **400** with the field named in `error.validationErrors`.\n\n## Counts and summaries\n\nBeside the full list, most collections expose `…/summary`, which answers the fields the application uses for pickers and tables and is smaller and faster than the full record. Some also expose `…/count`, which answers only the total without loading records. The API reference shows which variants an operation has. Use them for dashboards and reconciliation counts; use the full list only when you need every field.\n\n## Reconcile a long scan\n\nRecords can change while a scan runs. When the scan feeds a report, a later complete pass corrects it. When it feeds a synchronization, keep the `_id` and `_version` of each record you processed and compare them with a fresh read before you overwrite anything downstream; `_version` increases on every write, so a changed value tells you the record moved.\n\n## When a page fails\n\nA failed page answers with the same error envelope as any request; the status table in [REST API conventions](/integrations/rest/conventions#errors) says what each status means. A **429** carries `Retry-After`; wait that long before resuming from the same page. Do not resume from page 1.";
359
+ readonly markdown: "# Read collections\n\nA collection is the set of records one list or search operation lets your credential see in one organization. Read it in pages, sort it deliberately, filter it on the fields the operation offers, and stop where the response says to stop. Every list and search operation in the API reference uses the vocabulary below.\n\n## The query vocabulary\n\n{{CONSUMER_FACT:source:consumer-fact:rest-conventions#collectionQueryMarkdown}}\n\nFilter and sort fields are per operation. Each operation's entry in the API reference lists them as query parameters, so open the operation before writing the request; a filter accepted by one resource is not a convention for another.\n\n## The response envelope\n\n{{CONSUMER_FACT:source:consumer-fact:rest-conventions#paginationResponseMarkdown}}\n\nAn empty `data` array on page 1 is a valid answer. Confirm the organization and the filters before treating it as a failure.\n\n## Walk every page\n\n~~~bash\npage=1\nwhile : ; do\n response=$(curl --fail-with-body --silent \\\n --url \"$BASE_URL/api/v1/organizations/$ORGANIZATION_ID/organization-members?page=$page&limit=100&sort=createdAt:asc\" \\\n --header \"Authorization: $ORGANIZATION_API_KEY\" \\\n --header \"accept: application/json\")\n echo \"$response\" | jq -c '.data[]' >> members.ndjson\n totalPages=$(echo \"$response\" | jq '.pagination.totalPages')\n [ \"$page\" -ge \"$totalPages\" ] && break\n page=$((page + 1))\ndone\n~~~\n\nThree rules keep a scan correct:\n\n1. **Sort by a field the reference lists as sortable, or a stable timestamp** such as `createdAt:asc` for members (when the membership was created), when you walk more than one page. A sort field the operation does not accept is ignored, not refused, and the default order applies; sorting by a field that changes during the scan (a status, a name being edited) can move a record between pages and make you skip or repeat it.\n2. **Stop on `totalPages`**, not on a short page. The last page is short by definition; an earlier page is short only when records were deleted while you scanned.\n3. **Process each record idempotently** and key your own records on `_id`. If the scan is interrupted, resume from the last page whose work you completed; repeating a page is safe when processing is idempotent, skipping one never is.\n\n## Search and filter\n\nSearch operations (`…/search`) add `q` for free text. Combine it with filters and sorting:\n\n~~~bash\ncurl --fail-with-body \\\n --url \"$BASE_URL/api/v1/organizations/$ORGANIZATION_ID/organization-members/search?q=morgan&status=ACTIVE&sort=createdAt:desc\" \\\n --header \"Authorization: $ORGANIZATION_API_KEY\" \\\n --header \"accept: application/json\"\n~~~\n\nDate-range filters are objects and use bracket notation, one key per bound:\n\n~~~text\n?createdAt[startDate]=2026-09-01T00:00:00Z&createdAt[endDate]=2026-09-30T23:59:59Z\n~~~\n\nSend instants in ISO 8601 with a timezone. An unparseable bound answers **400** with the field named in `error.validationErrors`.\n\n## Counts and summaries\n\nBeside the full list, most collections expose `…/summary`, which answers the fields the application uses for pickers and tables and is smaller and faster than the full record. Some also expose `…/count`, which answers only the total without loading records. The API reference shows which variants an operation has. Use them for dashboards and reconciliation counts; use the full list only when you need every field.\n\n## Reconcile a long scan\n\nRecords can change while a scan runs. When the scan feeds a report, a later complete pass corrects it. When it feeds a synchronization, keep the `_id` and `_version` of each record you processed and compare them with a fresh read before you overwrite anything downstream; `_version` increases on every write, so a changed value tells you the record moved.\n\n## When a page fails\n\nA failed page answers with the same error envelope as any request; the status table in [REST API conventions](/integrations/rest/conventions#errors) says what each status means. A **429** carries `Retry-After`; wait that long before resuming from the same page. Do not resume from page 1.";
357
360
  }, {
358
361
  readonly managedPath: "integrations/rest/write-and-reconcile.md";
359
362
  readonly unitRef: "technical-documentation:unit/write-and-reconcile-api-changes";