Shopify Admin + App Bridgerecord 1
{
"id": "P10-C-001",
"evidence_class": "observed",
"source": "https://shopify.dev/docs/api/app-home/app-bridge-web-components/app-nav",
"observed": "2026-08-27",
"name": "Shopify Admin + App Bridge",
"category": "embedded-app-host",
"claim": "Shopify admin mounts third-party apps in an App Home iframe; the app declares its own left-sidebar nav via the <s-app-nav> web component with <s-link> children, and identity flows via an App Bridge ID token exchanged server-side for an access token.",
"identity_pattern": "App Bridge issues a short-lived session/ID token to the iframe; the app backend performs OAuth token exchange (urn:ietf:params:oauth:grant-type:token-exchange) for online/offline access tokens. authenticatedFetch attaches the token as Authorization: Bearer; a 401 with X-Shopify-Retry-Invalid-Session-Request triggers App Bridge to refresh the token and retry once.",
"settings_pattern": "Host owns install, scopes (managed installation) and merchant-level admin settings; the app owns its own in-app settings page reached via a nav link. No shared settings tree — the host does not render app settings.",
"navigation_pattern": "Declarative nav registration from inside the iframe: <s-app-nav> renders OUTSIDE the iframe in the admin sidebar. hrefs must be relative in-app paths; navigation is client-side with no full reload; nesting is not supported (one flat level); exactly one link may carry rel=\"home\" and it is hidden from the rendered menu.",
"limitations": "Flat single-level nav only; app name always links home; the app must keep its internal router in sync with host-rendered nav; nav renders only when loaded through the admin, not on direct URL visit (reported TitleBar/link breakage).",
"disposition": "top10"
}
Atlassian Forge (Jira/Confluence global page)record 2
{
"id": "P10-C-002",
"evidence_class": "observed",
"source": "https://developer.atlassian.com/platform/forge/manifest-reference/modules/jira-global-page/",
"observed": "2026-08-27",
"name": "Atlassian Forge (Jira/Confluence global page)",
"category": "embedded-app-host",
"claim": "Forge apps extend the host by declaring modules in manifest.yml that bind to named extension points; jira:globalPage places an item in the Apps section of Jira's main nav and can register a whole sidebar of pages or grouped sections.",
"identity_pattern": "Host-managed: Forge runs app code on Atlassian infrastructure with platform-issued context; the app never brokers its own login. Resolvers run as hosted functions or Forge Remote endpoints, receiving invocation context rather than an app-owned session.",
"settings_pattern": "Host chrome owns placement and app listing; app-owned configuration lives inside its own page routes. Admin-scoped modules are separate extension points from end-user ones (admin area is excluded from top-nav web items in Connect).",
"navigation_pattern": "Manifest-declared nav registration. URL is host-assigned: /jira/apps/{appId}/{envId}, with subroutes appended. `pages` adds individual sidebar entries (title + route + optional icon); `sections` groups them under a header; the two are mutually exclusive. Sidebar clicks only change the URL — the app must handle routing internally via view.createHistory().",
"limitations": "Exactly one jira:globalPage per app — a second entry fails deployment. Single-global-page apps get no sidebar at all. Many modules still beta with breaking-change risk. Connect→Forge migration needs a platform URL-persistence bridge to keep old deep links alive.",
"disposition": "top10"
}
WorkOSrecord 3
{
"id": "P10-C-003",
"evidence_class": "observed",
"source": "https://workos.com/docs/integrations/scim",
"observed": "2026-08-27",
"name": "WorkOS",
"category": "b2b-multi-tenant-idp",
"claim": "Organizations are the top-level tenant primitive; SSO connections and SCIM directories are configured per organization, with role mapping from IdP groups onto organization memberships.",
"identity_pattern": "Organization-scoped connections: each org gets its own SCIM endpoint plus a bearer token (shown once at creation). Users arrive via JIT or Directory Sync; membership and role live on /organization_memberships rather than on a global user record.",
"settings_pattern": "Per-organization configuration surface with an Admin Portal that customer admins operate themselves — delegated tenant settings, not host-rendered app settings.",
"navigation_pattern": "None — headless API/portal product. Contributes the tenant/role substrate a host nav would gate on, not the nav itself.",
"limitations": "No UI shell or navigation registry; consumption of directory changes requires either the events API (recommended, more robust) or webhooks, both of which the host must reconcile. Role mapping is set at directory-connection time in the Admin Portal.",
"disposition": "top10"
}
Fronteggrecord 4
{
"id": "P10-C-004",
"evidence_class": "observed",
"source": "https://developers.frontegg.com/guides/admin-portal/intro",
"observed": "2026-08-27",
"name": "Frontegg",
"category": "b2b-multi-tenant-idp",
"claim": "Ships an embeddable self-service Admin Portal plus a three-level tenancy hierarchy (Environment → Account → Sub-account), with entitlements gating which portal modules a given user can even see.",
"identity_pattern": "Environment-scoped identity where accounts are tenants and sub-accounts nest beneath a parent (must be explicitly enabled). An admin in tenant A can act on A's sub-accounts and their users. Management API endpoints require environment-level authorization; self-service endpoints are tenant-scoped.",
"settings_pattern": "The strongest commercial precedent for a HOST-OWNED settings tree: a Builder configures which Admin Portal modules exist, then per-user visibility is the AND of (role/permission) and (entitlement/feature). A feature toggled on in Builder still stays invisible without both.",
"navigation_pattern": "Portal modules are the nav — activating a module in the Builder adds its section to the embedded portal. Not a general third-party nav registry.",
"limitations": "Nav model only covers Frontegg's own portal modules, not arbitrary donor apps. Sub-account hierarchy is opt-in per parent. Narrower B2C coverage and smaller ecosystem than Auth0/WorkOS per third-party analysis.",
"disposition": "top10"
}
Cerbos / Cerbos Hubrecord 5
{
"id": "P10-C-005",
"evidence_class": "observed",
"source": "https://www.cerbos.dev/blog/multi-tenant-saas-authorization-role-policies-and-scoped-resource-policies",
"observed": "2026-08-27",
"name": "Cerbos / Cerbos Hub",
"category": "authorization-service",
"claim": "Scoped policies give a root/platform policy layer plus per-tenant scopes, with an explicit mode that forbids a tenant scope from granting more than its parent allows — the cleanest published model of safe delegated policy authoring.",
"identity_pattern": "Not an IdP; consumes a principal with attributes. Tenant isolation is expressed as policy conditions such as R.attr.tenantId == P.attr.tenantId at the root scope.",
"settings_pattern": "Hierarchical scope tree is itself the settings model. scopePermissions=SCOPE_PERMISSIONS_OVERRIDE_PARENT lets the child decide outright; SCOPE_PERMISSIONS_REQUIRE_PARENTAL_CONSENT_FOR_ALLOWS makes a child ALLOW effective only if the parent would also allow, while child DENY always wins. Role policies inherit parentRoles and may only narrow them.",
"navigation_pattern": "None directly, but the allow/deny decision is the natural gate for whether a nav entry renders.",
"limitations": "Holds no relationship data — true ReBAC must be encoded as attributes plus hierarchy functions, which gets awkward at graph complexity SpiceDB handles natively. Policy authoring is YAML, so tenant self-service needs a UI the host builds.",
"disposition": "top10"
}
Superblocks (embedded apps)record 6
{
"id": "P10-C-006",
"evidence_class": "observed",
"source": "https://docs.superblocks.com/hosting/embedded-apps/authentication",
"observed": "2026-08-27",
"name": "Superblocks (embedded apps)",
"category": "embedded-portal-platform",
"claim": "Cleanest documented host-to-guest token exchange: the host authenticates the user with its own auth, then mints a Superblocks session token server-side carrying tamper-proof custom claims.",
"identity_pattern": "Two-token exchange. An org admin creates a long-lived Embed access token (default 90-day expiry, shown once). The host backend verifies its own user, then POSTs /api/v1/public/token with that embed token as Bearer plus the user's email, optional name, groupIds and metadata; Superblocks returns a session access_token (e.g. expires_in 86400). The embedded app reads claims via useSuperblocksUser().",
"settings_pattern": "Host supplies identity and entitlement facts as JWT claims (externalUserId, externalOrgId, isAdmin); the guest app branches its own UI on those claims. Settings authority stays with the host, expressed as signed claims rather than a shared store.",
"navigation_pattern": "Guest mounts as a React component (SuperblocksEmbed with a token prop) inside the host's own shell, so the host keeps its nav entirely. No nav registry from guest to host.",
"limitations": "Metadata is opaque to the platform beyond claim delivery. Embed users get group permissions only for the token session's duration and never become real group members, so audit/membership views won't show them. Embeds, SSO and white-labeling are enterprise-tier gated.",
"disposition": "top10"
}
monday.com apps frameworkrecord 7
{
"id": "P10-C-007",
"evidence_class": "observed",
"source": "https://developer.monday.com/apps/docs/choosing-auth",
"observed": "2026-08-27",
"name": "monday.com apps framework",
"category": "embedded-app-host",
"claim": "Apps render as iframes inside monday views and get identity through seamless SDK authentication that works only inside the iframe; server-side calls use a signing-secret JWT carrying a 5-minute short-lived token.",
"identity_pattern": "Four documented lanes: (1) seamless SDK auth for iframe views — SeamlessApiClient calls the API as the logged-in user by talking to the parent frame, no keys stored; (2) signing-secret JWT in the Authorization header on platform→app requests, decoding to a shortLivedToken valid 5 minutes; (3) OAuth for background/server-side work; (4) a global personal token, explicitly discouraged and disqualifying for marketplace approval.",
"settings_pattern": "Host owns board/workspace context; the app reads location (href, query, search) via monday.get and can subscribe with monday.listen(\"location\") to react to host navigation.",
"navigation_pattern": "Host-driven: the app does not register nav entries so much as observe host location changes and re-render. Navigation authority is entirely the host's.",
"limitations": "Seamless auth breaks the moment the app runs outside an iframe (local dev, direct URL), forcing a second auth path. No declarative nav registry comparable to Shopify's or Forge's.",
"disposition": "register"
}
Wix apps (iframe SDK + app instances)record 8
{
"id": "P10-C-008",
"evidence_class": "observed",
"source": "https://dev.wix.com/docs/build-apps/develop-your-app/access/app-instances/identify-the-app-instance-in-frontend-environments",
"observed": "2026-08-27",
"name": "Wix apps (iframe SDK + app instances)",
"category": "embedded-app-host",
"claim": "Wix passes iframes a signed `instance` query parameter identifying which user, which site and what role — and explicitly warns that a plain-text instanceId must not be trusted.",
"identity_pattern": "Signed app-instance parameter delivered as a query param to dashboard pages, dashboard plugins, settings panels and external links. instanceId is deliberately NOT exposed in site widgets or settings panels; the correct path is sending a Wix access token to your backend which decodes it. revalidateSession returns a newly signed instance but does not refresh the iframe, so the app must listen for INSTANCE_CHANGED.",
"settings_pattern": "Host provides a dedicated App Settings iframe embedded in the Wix Editor for widget configuration; getOrigCompId identifies which page extension opened the panel so the right settings surface renders. This is a host-provided settings SLOT rather than a host-owned settings tree.",
"navigation_pattern": "Wix.Utils.navigateToSection with queryParams, noTransition and shouldRefreshIframe — imperative host navigation API rather than declarative registration.",
"limitations": "Classic iframe widget/page extensions are now in the deprecated docs; newer apps are steered to self-hosted extensions with WixClient/fetchWithAuth. Query-param identity delivery is a documented tampering surface requiring backend verification.",
"disposition": "register"
}
Salesforce Lightning + Canvasrecord 9
{
"id": "P10-C-009",
"evidence_class": "observed",
"source": "https://developer.salesforce.com/docs/atlas.en-us.platform_connect.meta/platform_connect/user_flow_signed_request.htm",
"observed": "2026-08-27",
"name": "Salesforce Lightning + Canvas",
"category": "embedded-app-host",
"claim": "Canvas embeds third-party apps as tabs, links and buttons inside Salesforce, POSTing an encrypted signed_request containing user context and an access_token — the oldest mainstream host-absorption pattern still in production.",
"identity_pattern": "signed_request: Salesforce HTTP-POSTs an encrypted payload carrying user information plus an OAuth access_token to the Canvas app URL configured on the Connected App. The guest verifies the signature and trusts the enclosed context — no redirect handshake.",
"settings_pattern": "Lightning App Builder owns page composition and per-tab visibility rules (Add Filter → criteria). If every component in a tab is hidden the tab disappears; if all tabs in a Tabs component are hidden the whole component disappears — cascading visibility as a settings primitive.",
"navigation_pattern": "Navigation tabs configured in App Manager form the app nav bar; the first navigation item becomes the landing page; a Lightning App Page can be exposed as a nav tab. Mobile has a separate Mobile Navigation Menu the page must be added to explicitly.",
"limitations": "Plain web tabs to sites with strict X-Frame-Options or CSP render blank — you must use Canvas or a Lightning component instead. Tabs cannot be reordered by dragging on the canvas, only in the properties pane. Desktop and mobile nav are separately maintained.",
"disposition": "top10"
}
Clerkrecord 10
{
"id": "P10-C-010",
"evidence_class": "observed",
"source": "https://clerk.com/docs/guides/organizations/overview",
"observed": "2026-08-27",
"name": "Clerk",
"category": "b2b-multi-tenant-idp",
"claim": "Application-level roles and permissions applied uniformly across all organizations, with an Active Organization carried in every session as the tenant-scoping key.",
"identity_pattern": "Shared user pool: one account belongs to many organizations with a distinct role in each. The session exposes the active organization's id, metadata and role, which the app uses to isolate data. <OrganizationSwitcher /> changes the active org without leaking between tenants.",
"settings_pattern": "Roles and permissions are defined ONCE at application level and apply everywhere — deliberately NOT per-tenant role definitions. Verified Domains govern auto-enrollment. Organizations must be explicitly enabled before any org API, hook or component functions.",
"navigation_pattern": "UI gating rather than nav registration: <Show when={{role:'org:admin'}}> / when={{permission:'org:sys_memberships:manage'}} in Core 3, replacing Core 2's <Protect>.",
"limitations": "Organization slugs are disabled by default for applications created after 2025-10-07. System permission slugs follow a strict naming convention (org:sys_domains:manage) and intuitive-sounding names like org:manage_members are not real slugs. Custom roles need the paid B2B add-on. Pricing meters Monthly Retained Organizations.",
"disposition": "register"
}
Auth0 / Okta Customer Identity Cloudrecord 11
{
"id": "P10-C-011",
"evidence_class": "observed",
"source": "https://auth0.com/blog/using-auth0-for-b2b-multi-and-single-tenant-saas-solutions/",
"observed": "2026-08-27",
"name": "Auth0 / Okta Customer Identity Cloud",
"category": "b2b-multi-tenant-idp",
"claim": "Organizations map 1:1 to customer tenants inside a single Auth0 tenant that remains the root of trust, scaling to ~2 million organizations, with a My Organization API for in-app delegated administration.",
"identity_pattern": "Single tenant as root of trust; applications, users, roles and organizations all live inside it. Organizations group users but do NOT own identities — the user object stays tenant-scoped and one user can be in many orgs at once. Roles are defined once at tenant level and assigned within an org context.",
"settings_pattern": "Per-organization branding and login experience, org-scoped connections, and delegated administration via the Management API (invite/remove users, manage roles, update org name and branding). Pre-built white-labeled components are offered for embedding.",
"navigation_pattern": "None — headless. Documents sub-domain vs sub-folder organization addressing as the routing convention hosts adopt.",
"limitations": "B2B concepts are contextual layers rather than first-class at the tenant level, which third-party reviews flag as an architectural tradeoff for isolation and token design. Enterprise pricing.",
"disposition": "register"
}
Stytch B2Brecord 12
{
"id": "P10-C-012",
"evidence_class": "observed",
"source": "https://stytch.com/docs/b2b/guides/what-is-stytch-b2b-auth",
"observed": "2026-08-27",
"name": "Stytch B2B",
"category": "b2b-multi-tenant-idp",
"claim": "Organizations and Members are both first-class API entities; email is unique WITHIN an organization, and a cross-org user is literally multiple Member records sharing an email.",
"identity_pattern": "Member-per-organization rather than one global user with memberships. Each Organization carries its own approved auth methods, JIT provisioning rules, SSO connections, MFA policy and custom metadata. Offers a choice between cross-organization passwords and organization-scoped passwords, the latter giving stronger separation so a reset in one org does not affect another.",
"settings_pattern": "Configuration is genuinely per-organization rather than global-with-overrides — the org record IS the settings object.",
"navigation_pattern": "None — headless API.",
"limitations": "Recommends the multi-tenant model even for consumer-shaped apps by silently creating an Organization per individual user, which inflates the tenant count. Migrating Consumer→B2B requires an explicit data-model reconciliation.",
"disposition": "register"
}
Descoperecord 13
{
"id": "P10-C-013",
"evidence_class": "observed",
"source": "https://docs.descope.com/b2b/multi-tenancy",
"observed": "2026-08-27",
"name": "Descope",
"category": "b2b-multi-tenant-idp",
"claim": "Project → Tenants → Users, where users share ONE identity record across tenants by default but Tenant User Isolation can be switched on to give the same login ID separate credentials and MFA state per tenant.",
"identity_pattern": "Default shared identity: login ID, credentials and MFA state are common across all a user's tenants. Opt-in Tenant User Isolation flips this. Domain-based auto-mapping assigns users to tenants; SSO with JIT and SCIM provisioning are per-tenant, and multiple SSO configs per tenant are supported.",
"settings_pattern": "Explicit inheritance: tenants inherit project-level auth settings by default with per-tenant overrides. Conflict resolution is documented — when a user belongs to multiple tenants the MOST RESTRICTIVE combination of password policies applies. This is a directly transferable settings-hierarchy precedent.",
"navigation_pattern": "None — headless, flow-based.",
"limitations": "Shared-identity default is a real cross-tenant coupling hazard if isolation is not deliberately enabled. No UI shell.",
"disposition": "top10"
}
Kinderecord 14
{
"id": "P10-C-014",
"evidence_class": "observed",
"source": "https://docs.kinde.com/build/organizations/multi-tenancy-using-organizations/",
"observed": "2026-08-27",
"name": "Kinde",
"category": "b2b-multi-tenant-idp",
"claim": "Organizations within a Kinde business, backed by a single database with a schema per tenant, but explicitly limited to two hierarchy layers (organizations → users) with N-layer on the roadmap.",
"identity_pattern": "Every business ships with one default organization; more are created for multi-tenancy. Users in multiple orgs are prompted to pick one at sign-in. Per-org custom domains, per-org auth methods (SAML for one org, Google/email for another), default roles on join, and org-specific MFA policies. M2M apps can be scoped to an organization.",
"settings_pattern": "Per-org auth/branding/billing overrides. Feature-flag values can be overridden per organization, which is a settings-hierarchy signal.",
"navigation_pattern": "None — headless.",
"limitations": "Organizations CANNOT be nested — a top-level org per project with sub-orgs per tenant beneath is not supported; the Kinde team confirmed only two layers of tenant hierarchy today. This is disqualifying for a host that needs workspace→project→environment depth.",
"disposition": "register"
}
FusionAuthrecord 15
{
"id": "P10-C-015",
"evidence_class": "observed",
"source": "https://fusionauth.io/docs/get-started/core-concepts/tenants",
"observed": "2026-08-27",
"name": "FusionAuth",
"category": "b2b-multi-tenant-idp",
"claim": "A Tenant is a discrete namespace for Users, Applications and Groups; uniqueness of email/username is scoped to the tenant, so the same email can exist repeatedly across tenants with different passwords.",
"identity_pattern": "Tenant-namespaced identity. The majority of configuration is managed at tenant level, with some values acting as defaults an Application can override — an explicit two-level settings cascade. API keys can be tenant-scoped.",
"settings_pattern": "Tenant-level defaults overridden per Application: login screen look and feel, password requirements, email configuration. Delegated administration is a separate Tenant Manager app, because the core admin role for managing users grants access to ALL tenants.",
"navigation_pattern": "Documents a control-plane / data-plane split: a control plane app at app.example.com where tenants are created, and per-tenant data-plane apps at subdomains like dantest.example.com.",
"limitations": "FusionAuth itself is always a single-tenant DEPLOYMENT that supports multiple logical tenants inside it — do not confuse the two. The Default tenant cannot be deleted. Delegated admin needs the separate Tenant Manager rather than being built into the core console.",
"disposition": "register"
}
PropelAuthrecord 16
{
"id": "P10-C-016",
"evidence_class": "observed",
"source": "https://github.com/api-evangelist/propelauth",
"observed": "2026-08-27",
"name": "PropelAuth",
"category": "b2b-multi-tenant-idp",
"claim": "B2B-only by design: organizations are first-class with custom roles definable globally OR per organization, plus SAML/OIDC, SCIM and org-scoped end-user API keys.",
"identity_pattern": "Organizations own membership and role; per-org security controls (password policy, enforced MFA, session controls) are configurable without code changes. Hosted login UIs supplied.",
"settings_pattern": "Notable contrast with Clerk: roles/permissions can be defined per organization, not only application-wide — the more permissive end of the delegation spectrum.",
"navigation_pattern": "None beyond hosted account/org management UIs.",
"limitations": "Small vendor relative to Auth0/WorkOS; consumer/B2C scenarios out of scope by design. Much of the strongest claim material is vendor marketing rather than reference docs.",
"disposition": "register"
}
Oso Cloudrecord 17
{
"id": "P10-C-017",
"evidence_class": "observed",
"source": "https://www.osohq.com/learn/spicedb-alternatives-authorization-tools-comparison",
"observed": "2026-08-27",
"name": "Oso Cloud",
"category": "authorization-service",
"claim": "Authorization as a service that can answer questions using data read directly from the application's own databases, avoiding a separate data-sync pipeline into the authz service.",
"identity_pattern": "Consumes application principals; policies written in Polar, a declarative policy language.",
"settings_pattern": "Centralized policy gives discoverability, sharing and testability of rules without the host having to mirror its data into the authz store.",
"navigation_pattern": "None.",
"limitations": "Polar is a bespoke language — real policy-language lock-in. Reading from application databases constrains where and how the service is deployed. Most comparison material is Oso's own.",
"disposition": "register"
}
Permit.iorecord 18
{
"id": "P10-C-018",
"evidence_class": "observed",
"source": "https://guptadeepak.com/tools/top-5-authorization-pbac-tools-2026/",
"observed": "2026-08-27",
"name": "Permit.io",
"category": "authorization-service",
"claim": "Full-stack permissions as a service aimed at SaaS teams needing multi-tenant access control, role delegation and ADMIN-FACING permission UIs — the last of which is the distinguishing feature for a host layer.",
"identity_pattern": "Tenant is a first-class billing and modeling unit (plan tiers quoted by MAU and tenant count, e.g. Startup ~25k MAU / 100 tenants).",
"settings_pattern": "Ships the admin UI for permission management, so tenant admins edit their own roles without the host building that screen — directly relevant to who owns the settings surface.",
"navigation_pattern": "Embeddable permission-management UI components rather than a nav registry.",
"limitations": "Pricing figures differ across secondary sources (one lists Startup at $150/mo for 10k MAU) and must be verified against the vendor page before quoting. Building the equivalent on raw SpiceDB is explicitly the alternative being sold against.",
"disposition": "register"
}
AuthZed / SpiceDB Cloudrecord 19
{
"id": "P10-C-019",
"evidence_class": "observed",
"source": "https://www.osohq.com/learn/spicedb-alternatives-authorization-tools-comparison",
"observed": "2026-08-27",
"name": "AuthZed / SpiceDB Cloud",
"category": "authorization-service",
"claim": "Most mature open-source Zanzibar implementation, used by OpenAI for ChatGPT Enterprise at tens of billions of permissions, with ZedTokens providing consistency guarantees.",
"identity_pattern": "Relationship tuples rather than principals-with-attributes; ReBAC-first, so multi-tenant graphs and resource hierarchies are the native shape.",
"settings_pattern": "Schema defines object types and relations; tenancy is modeled as objects in the graph, not as a separate configuration tier.",
"navigation_pattern": "None.",
"limitations": "Self-hosting means operating a stateful distributed system with a documented dual-write consistency problem; ABAC needs workarounds since the model is ReBAC-first; the Zanzibar graph model is unintuitive for teams used to attributes, and many teams end up paying for AuthZed Cloud instead of self-hosting.",
"disposition": "register"
}
LaunchDarklyrecord 20
{
"id": "P10-C-020",
"evidence_class": "observed",
"source": "https://launchdarkly.com/docs/guides/flags/flag-hierarchy/",
"observed": "2026-08-27",
"name": "LaunchDarkly",
"category": "feature-flag-settings-platform",
"claim": "Environments are a top-level concept requiring flags and segments to be managed separately per environment; hierarchy is expressed through PREREQUISITE flags evaluated before any other targeting rule.",
"identity_pattern": "Contexts evaluate multiple entities at once — a user, their organization and their device in a single evaluation — which is the closest commercial analogue to a host resolving identity across nested scopes.",
"settings_pattern": "Prerequisite flags define precedence: a dependent flag checks its prerequisite BEFORE its own targeting rules. A prerequisite added at creation applies across all environments. Flags from different projects cannot be prerequisites of one another, so the hierarchy is project-bounded. Feature bundling — many subfeatures behind one prerequisite — is the documented pattern for coordinating a large release.",
"navigation_pattern": "None, but flag evaluation is the standard commercial gate for whether a nav entry or module appears.",
"limitations": "Per-environment duplication of flags and segments is real operational overhead. Users report the Contexts group-targeting model feels unintuitive. Enterprise pricing.",
"disposition": "register"
}
Statsigrecord 21
{
"id": "P10-C-021",
"evidence_class": "observed",
"source": "https://docs.statsig.com/guides/migrate-from-launchdarkly",
"observed": "2026-08-27",
"name": "Statsig",
"category": "feature-flag-settings-platform",
"claim": "Deliberately inverts LaunchDarkly's model — a centralized flag/config where environment-specific behavior lives INSIDE targeting rules rather than in duplicated per-environment flags.",
"identity_pattern": "Rule-based targeting on user attributes, with rollouts doubling as controlled experiments.",
"settings_pattern": "Typed configuration objects: boolean flags become Feature Gates while string, number and JSON flags become Dynamic Configs. That split — booleans as gates, structured values as configs — is a useful precedent for separating a host's capability toggles from its settings values.",
"navigation_pattern": "None.",
"limitations": "Migration is lossy in the sense that flag types are converted, not preserved. Centralized-environment model means an environment mistake in a rule affects every environment at once.",
"disposition": "register"
}
ConfigCatrecord 22
{
"id": "P10-C-022",
"evidence_class": "observed",
"source": "https://configcat.com/launchdarkly-vs-configcat/",
"observed": "2026-08-27",
"name": "ConfigCat",
"category": "feature-flag-settings-platform",
"claim": "Multiple environments out of the box with separate flag configurations per environment; targeting by user attribute, percentage rollout and scheduled release, aimed at non-engineers changing config without a deploy.",
"identity_pattern": "User attribute matching (e.g. users in a region, a percentage of premium accounts).",
"settings_pattern": "Product → environment → flag as the config tree; pricing itself is metered on number of flags, environments and products plus config JSON download volume, which reveals the intended shape of the hierarchy.",
"navigation_pattern": "None.",
"limitations": "Deliberately simpler than LaunchDarkly — no prerequisite/dependency hierarchy, so cross-flag precedence must be modeled by the host. Cost scales with the very dimensions a deep settings tree multiplies.",
"disposition": "rejected"
}
Retool (External Apps / Embed)record 23
{
"id": "P10-C-023",
"evidence_class": "observed",
"source": "https://retool.com/blog/external-apps",
"observed": "2026-08-27",
"name": "Retool (External Apps / Embed)",
"category": "embedded-portal-platform",
"claim": "Embeds full-stack portals for users OUTSIDE the organization into an existing application, passing data both ways through React and JavaScript SDKs, with white-labeling as the stated goal.",
"identity_pattern": "Two documented options: configure SSO so users already authenticated with the host IdP are logged into embedded apps automatically, or an API-based method usable with any login where the host generates a secure SINGLE-USE link after its own login completes.",
"settings_pattern": "Host owns the surrounding shell and passes data in; Retool owns app-internal configuration. Custom branding is enterprise-gated.",
"navigation_pattern": "Guest mounts inside the host's shell; the host retains navigation. No guest→host nav registration.",
"limitations": "External users and embedded apps require a Business license; SAML/OpenID SSO and custom branding are enterprise-only; self-hosted tiers capped at 25 users. Single-use link generation puts link lifecycle burden on the host.",
"disposition": "register"
}
Budibaserecord 24
{
"id": "P10-C-024",
"evidence_class": "inferred",
"source": "https://budibase.com/blog/alternatives/superblocks-vs-retool/",
"observed": "2026-08-27",
"name": "Budibase",
"category": "embedded-portal-platform",
"claim": "A single self-hosted instance serves multiple apps, RBAC roles, SSO, automations and embeds from one builder UI — the cheapest route to a multi-app shell with SSO included.",
"identity_pattern": "Built-in SSO and RBAC on the free self-hosted tier (up to ~20 users); custom SSO policies move to Premium. Inferred rather than observed: the tenancy boundary between apps in one instance was not confirmed from primary docs.",
"settings_pattern": "One builder governs all apps in the instance — instance-level settings with per-app roles. Not verified against reference docs.",
"navigation_pattern": "Per-app navigation inside the Budibase shell; no documented cross-app nav registry read in this pass.",
"limitations": "All claims here come from a competitor/vendor comparison blog, not Budibase reference documentation. GPL-v3 core has licensing implications for a commercial host that embeds or modifies it — NOT verified in this pass and must be read from the LICENSE body before any adoption decision.",
"disposition": "rejected"
}
ServiceNow UI Builder / Next Experiencerecord 25
{
"id": "P10-C-025",
"evidence_class": "observed",
"source": "https://www.servicenow.com/docs/r/application-development/ui-builder/workspace-side-navigation-settings.html",
"observed": "2026-08-27",
"name": "ServiceNow UI Builder / Next Experience",
"category": "embedded-portal-platform",
"claim": "Workspace side navigation and menu items are configured as structured data on a UX page property rather than authored as components — navigation as a stored configuration document.",
"identity_pattern": "Platform-native identity; UI Builder pages inherit the instance session rather than brokering their own.",
"settings_pattern": "Navigation menus were historically edited as a JSON value on a UX Page Property — a real-world example of a nav MANIFEST stored as data, with the documented failure mode that the property's type must be JSON rather than String or the side menu silently fails to appear.",
"navigation_pattern": "Declarative JSON nav config plus URL parameters (sm, menu) selecting the active tab, updatable at runtime through a CONTENT_UPDATED API from a click event.",
"limitations": "Editing navigation as raw JSON is widely reported as a pain point; silent failure when the property type is wrong is a cautionary precedent for any manifest-as-data design. Heavily coupled to the ServiceNow platform.",
"disposition": "top10"
}
Salesforce Lightning App Builder (composition)record 26
{
"id": "P10-C-026",
"evidence_class": "observed",
"source": "https://help.salesforce.com/s/articleView?language=en_US&id=lightning_app_builder_customize_lex_pages_add_tabs.htm",
"observed": "2026-08-27",
"name": "Salesforce Lightning App Builder (composition)",
"category": "navigation-registry-precedent",
"claim": "Page composition with per-tab visibility filters, where emptiness cascades: hiding all components in a tab hides the tab, and hiding all tabs hides the whole Tabs component.",
"identity_pattern": "Inherits the Salesforce session; visibility rules evaluate against user/record context.",
"settings_pattern": "Visibility filters attached to individual tabs (click tab → Add Filter → criteria → Done) are the settings mechanism, and cascading emptiness prevents dead chrome — a pattern a host absorbing donor apps needs so an entitlement-stripped module leaves no empty shell behind.",
"navigation_pattern": "Tabs reorder only in the properties pane, never by dragging on the canvas.",
"limitations": "Same-vendor-only composition; no third-party mounting without Canvas. Listed separately from P10-C-009 because the composition model and the Canvas embed model are distinct mechanisms.",
"disposition": "register"
}
Atlassian Connect (legacy descriptor model)record 27
{
"id": "P10-C-027",
"evidence_class": "observed",
"source": "https://developer.atlassian.com/cloud/jira/platform/extension-points-for-the-end-user-ui/",
"observed": "2026-08-27",
"name": "Atlassian Connect (legacy descriptor model)",
"category": "navigation-registry-precedent",
"claim": "Apps declare modules in a JSON app descriptor OR register some modules DYNAMICALLY via REST API — precedent for runtime nav registration rather than deploy-time-only manifests.",
"identity_pattern": "JWT-based iframe embedding with query-string signing between host and app (Connect's classic model, superseded by Forge's hosted-context approach).",
"settings_pattern": "Web items placed at named locations; the end-user extension points are explicitly scoped to exclude the administration area, so admin chrome is a separate registration namespace from user chrome.",
"navigation_pattern": "Named locations such as system.top.navigation.bar; the Connect→Forge migration maps a jira:generalPages module at that location onto a Forge jira:globalPage.",
"limitations": "Legacy — Atlassian is migrating the ecosystem to Forge, and URL persistence exists precisely because deep links break otherwise. Retained here for the dynamic-registration precedent, which Forge's static manifest does not offer.",
"disposition": "register"
}
Microsoft 365 admin centerrecord 28
{
"id": "P10-C-028",
"evidence_class": "observed",
"source": "https://learn.microsoft.com/en-us/microsoft-365/admin/admin-overview/admin-center-overview?view=o365-worldwide",
"observed": "2026-08-27",
"name": "Microsoft 365 admin center",
"category": "suite-unification",
"claim": "One console fronting Exchange, SharePoint, Teams and more, with a deliberate two-mode UI — Simplified view for common tasks and Dashboard view for the full surface, switchable from a top-level button.",
"identity_pattern": "Tenant-wide identity with RBAC roles (Global Admin, User Admin, Billing Admin) plus administrative units delegating control by geography or department — a second axis of scoping orthogonal to role.",
"settings_pattern": "The Simplified/Dashboard split is the strongest commercial precedent for PROGRESSIVE DISCLOSURE of an absorbed settings surface: the same underlying settings, two curated depths, user-switchable rather than permission-locked. Specialized workloads keep their own dedicated admin centers behind the unified one.",
"navigation_pattern": "Central console links out to per-workload admin centers rather than fully absorbing their UI — federation of consoles, not replacement.",
"limitations": "Federation means donor chrome is never fully suppressed; admins still context-switch into Exchange or Teams admin centers. Decades of accreted settings make it a cautionary example as much as a model.",
"disposition": "register"
}
Zoho Onerecord 29
{
"id": "P10-C-029",
"evidence_class": "observed",
"source": "https://www.zoho.com/directory/features/single-sign-on.html",
"observed": "2026-08-27",
"name": "Zoho One",
"category": "suite-unification",
"claim": "45+ separately built apps unified behind one directory, one credential and one admin console — the closest commercial analogue to absorbing many donor apps under a single identity and shell.",
"identity_pattern": "Zoho Directory SSO as the unification layer; registering with Zoho One is a prerequisite for enabling SSO configuration in Zoho Accounts. SSO is explicitly framed as the FIRST step that then enables org-level MFA, password policy and IP restrictions.",
"settings_pattern": "Central console owns users, access, security, telephony and adoption, with dashboards for signed-in users, failed logins and most-used apps, plus exportable audit reports. Each constituent app still keeps its own deep settings.",
"navigation_pattern": "App-launcher federation: a common shell and switcher over apps that each retain their own UI. Donor chrome is NOT suppressed.",
"limitations": "Unification is at the identity and admin tier, not the UI tier — the apps still look and behave like separate products, which is precisely the failure mode a true host layer is trying to avoid. Much of the operational detail comes from partner/consultancy write-ups rather than Zoho reference docs.",
"disposition": "register"
}
HubSpotrecord 30
{
"id": "P10-C-030",
"evidence_class": "observed",
"source": "https://knowledge.hubspot.com/user-management/create-and-manage-teams",
"observed": "2026-08-27",
"name": "HubSpot",
"category": "suite-unification",
"claim": "Hierarchy is expressed through nested TEAMS rather than a formal org structure, with deliberately asymmetric visibility: parent teams see everything owned below them, but a nested team cannot see everything the parent owns.",
"identity_pattern": "Users belong to teams; teams nest under parent teams. Team nesting is gated to Professional and Enterprise tiers.",
"settings_pattern": "Permissions are scoped per object area (contacts, companies, deals, tickets, custom objects) with view/edit/delete/none, each further restricted to 'owned only', 'team only' or 'all records'. Two independent axes — verb and scope — composed per object type.",
"navigation_pattern": "Settings → Users & Teams in the left sidebar; a conventional single-product console rather than an extensible shell.",
"limitations": "Downward-only visibility is a specific product opinion, not a general rule. Without teams the only lever is 'owned only', which managers escape anyway. Users have repeatedly requested a true account-hierarchy view as an idea, indicating the teams model does not fully cover org structure.",
"disposition": "register"
}
Frontegg Entitlementsrecord 31
{
"id": "P10-C-031",
"evidence_class": "observed",
"source": "https://developers.frontegg.com/guides/authorization/entitlements/feature-based/entitlements-features",
"observed": "2026-08-27",
"name": "Frontegg Entitlements",
"category": "feature-flag-settings-platform",
"claim": "Access requires BOTH the permission and the entitlement — a user holding the permission but lacking the feature is denied, making plan-tier and role two independent gates that must both pass.",
"identity_pattern": "Entitlements attach to the account/tenant while permissions attach to the role, so the AND is evaluated across two different scopes.",
"settings_pattern": "Configured at [ENVIRONMENT] → Configurations → Entitlements → Features. This is the cleanest published statement of the two-gate rule a host needs when a module is both plan-gated and role-gated.",
"navigation_pattern": "Determines which self-service portal modules render for a given user.",
"limitations": "Listed separately from P10-C-004 because entitlements are a distinct mechanism from the Admin Portal shell. Coupled to Frontegg's own portal; no third-party module support.",
"disposition": "top10"
}
Shopify token exchange grantrecord 32
{
"id": "P10-C-032",
"evidence_class": "observed",
"source": "https://shopify.dev/docs/apps/build/authentication-authorization/access-tokens#token-exchange-grant",
"observed": "2026-08-27",
"name": "Shopify token exchange grant",
"category": "embedded-app-host",
"claim": "Token exchange is available ONLY to embedded apps and removes redirects entirely, making authorization faster and preventing the load flicker that the redirect-based OAuth flow caused.",
"identity_pattern": "The embedded app swaps its session token for online/offline access tokens with no browser redirect. New public apps must use EXPIRING offline access tokens — pass expiring=1 and Shopify returns a refresh token alongside the access token. Scope changes are handled by Shopify under managed installation.",
"settings_pattern": "Managed installation moves scope/consent out of the app's hands into the host, so the host owns the permission-grant surface rather than each guest re-implementing consent.",
"navigation_pattern": "n/a — this row covers the identity mechanism specifically.",
"limitations": "Embedded-only; a non-embedded surface must keep the old redirect flow. The app must subscribe to app/uninstalled and update shop records or OAuth silently breaks. Listed separately from P10-C-001 because the identity grant and the nav registry are independently reusable mechanisms.",
"disposition": "register"
}
WorkOS + Cerbos composition patternrecord 33
{
"id": "P10-C-033",
"evidence_class": "inferred",
"source": "https://www.cerbos.dev/ecosystem/cerbos-workos",
"observed": "2026-08-27",
"name": "WorkOS + Cerbos composition pattern",
"category": "authorization-service",
"claim": "The prevailing commercial architecture is to compose a tenant/identity vendor with a separate policy engine rather than buying one product that does both — WorkOS supplies orgs, roles and directory data while Cerbos decides.",
"identity_pattern": "WorkOS organization membership and IdP-mapped roles become the principal attributes Cerbos evaluates. Inferred: the split is evidenced by a vendor-published integration page, not by a reference architecture doc.",
"settings_pattern": "Implies a clean seam for a host layer — identity/tenancy state in one system, decision logic in another, with the host owning the mapping between them.",
"navigation_pattern": "n/a.",
"limitations": "Sourced from a vendor ecosystem/marketing page, so treat the specific integration claims as unverified. The general pattern is corroborated by the separate existence and positioning of both product categories, but the seam's actual cost (attribute freshness, latency, dual configuration) is not documented in what was read.",
"disposition": "register"
}