Skip to main content

AI in Practice

How to Bind a SaaS Tenant to the Right CRM Connection

A user can sign in successfully, have permission to ask for a CRM summary, and still reach the wrong customer’s Salesforce connection if the app does not bind that request to the right tenant and installation.

Two customer tenants connect only to their own provider records through a server-side boundary.
On this page
  1. A valid login does not prove the app selected the right customer’s CRM
  2. Keep user, tenant, provider connection, and installation separate
  3. Define the authorization invariant before building the connector
  4. Make the tenant-to-installation relationship hard to bypass
  5. Pick a storage model, then apply the same rule at each lookup
  6. Test the denied route, not only the successful connection
  7. Separate app authorization from provider-side permissions
  8. Put the boundary in the design review
Three colored strands weave through one knot and lead to an open ring. View image detail

Choose Actual size to read the graphic closely.

A valid login does not prove the app selected the right customer’s CRM

A user can sign in successfully, have permission to ask for a CRM summary, and still reach the wrong customer’s Salesforce connection if the app does not bind that request to the right tenant and installation.

That is a specific product-design problem for SaaS teams building agent features across many customer organizations. The app has to make two decisions before it reads customer data: which tenant does this request belong to, and which connected CRM installation belongs to that tenant? If those two decisions live in separate, loosely related lookups, the app can authenticate a real person and still choose the wrong customer’s resource.

Ampersand’s October 6 announcement is a timely prompt for that design question. The company announced a $15 million Series A and said its Andi product was entering beta. Ampersand describes its integration infrastructure as helping enterprise agents work with customer systems of record. This article is not an evaluation of Andi or a claim about Ampersand’s security. It asks what the SaaS application using any integration platform must prove about its own tenant-to-connection authorization boundary. Ampersand’s October 6 announcement

AWS separates tenant isolation from authentication and authorization. Authentication establishes identity; authorization controls which actions a user can take. Tenant isolation applies tenant context to determine which resources that tenant can reach. AWS explains that a user may be authenticated and authorized while still reaching another tenant’s resources if the application does not apply isolation separately. That is general SaaS architecture guidance, not evidence of a defect in Ampersand or any particular app. AWS, “Tenant isolation”

Use a simple example throughout. A fictional SaaS has two customers, Acme and Birch. Both connect Salesforce. Acme’s renewal date lives in an account custom field. Birch stores the same business concept on a subscription record. An agent inside Acme’s workspace asks, “What renewals are coming up?” The app has to resolve Acme’s own Salesforce connection and the configuration associated with that installation. It cannot let the agent, browser, or a request parameter choose Birch’s connection instead.

The decision belongs to the app’s trusted server-side authorization path. Ampersand’s documentation can describe product capabilities and customer configurations; it cannot establish that an integrating SaaS app has correctly bound its own users, tenants, provider connections, and installations. The team must design and test that boundary in its own product.

The operator’s test: Given an authenticated user in tenant Acme, can any request path select Birch’s Salesforce connection or installation? A passing design should show where the app rejects that mismatch, and a test should demonstrate the rejection.

Keep user, tenant, provider connection, and installation separate

The first useful design artifact is a map of the identities and resources involved. Four references often appear close together in code, but each answers a different question.

  • User identity: Question it answers: Which person or service made this request?; Fictional example: A named user signed in to Acme’s workspace
  • SaaS tenant: Question it answers: Which customer workspace owns the request?; Fictional example: Acme’s internal tenant reference
  • Provider connection: Question it answers: Which customer-owned Salesforce organization will the provider call use?; Fictional example: Acme’s connected Salesforce environment
  • Integration installation: Question it answers: Which integration definition and customer-specific setup apply?; Fictional example: Acme’s installation and field mapping

These names are illustrative. They are not a claim about Ampersand’s internal data model or API field names.

A user ID does not automatically identify a tenant. One person may belong to more than one workspace. Even when the app has resolved the active workspace, that tenant reference does not automatically identify the correct provider account. A customer can connect more than one provider environment, replace a connection, or configure more than one integration. The installation is another relationship: it links an integration setup and its customer-specific configuration to the tenant and connection that should use it.

AWS describes SaaS identity as binding authenticated users to a specific tenant context and carrying that context through the application’s services. The point is that downstream decisions should receive the tenant context established by the identity flow. The AWS page warns against separate standalone mechanisms that map users to tenants because they can undermine security. This supports the general need for a consistent tenant context; it does not prescribe a particular identity provider, token format, or data schema. AWS, “SaaS identity”

Ampersand’s current overview describes integrations as definitions that a developer creates and customer installations that store each customer’s choices. It says an application can define a normalized field such as renewalDate once while separate customers map that field to different Salesforce fields. The example shows customer-specific field locations and says the application reads or writes the normalized field while Ampersand translates it for each customer. Those are Ampersand’s published product descriptions, not independent verification of an app’s tenant authorization. Ampersand, “Integration infrastructure for enterprise agents”

Ampersand’s `renewalDate` application field maps to different customer locations: `Account.Renewal_Date__c` and `Account.Contract_End__c`. View image detail

Choose Actual size to read the graphic closely.

For the app team, the relationship should be explicit in the data model or authorization service. An internal tenant owns or is authorized to use a provider connection. An installation is associated with that tenant and the connection. The application resolves the installation only after it has established the current tenant. If the stored relationships cannot answer “Why is this Acme request allowed to use this exact installation?”, then the design needs a clearer answer before the feature relies on it.

A table can clarify the relationship during design review:

  • Acme: Provider: Salesforce; Provider connection reference: Acme connection; Installation reference: Acme installation; Allowed?: Yes, for Acme context
  • Birch: Provider: Salesforce; Provider connection reference: Birch connection; Installation reference: Birch installation; Allowed?: Yes, for Birch context
  • Acme: Provider: Salesforce; Provider connection reference: Birch connection; Installation reference: Birch installation; Allowed?: No, relationship mismatch

This is a proposed representation for the app team, not Ampersand’s product schema. The important part is the authorization relation: a request for Acme must not be able to turn a valid Birch installation into an authorized Acme resource by supplying its identifier.

Define the authorization invariant before building the connector

An invariant is a rule that every relevant code path must preserve. For this feature, write the rule in plain terms first: the application may use a provider installation only when the authenticated request’s trusted tenant context is authorized for that installation and its provider connection.

That sentence is more useful than “check permissions” because it names the resource being protected. It also gives the team something testable. The app should not merely show that a user may access an agent feature. It should show that the feature’s server-side path resolves only the provider resources associated with the user’s current tenant.

A proposed resolution flow can be written without committing to a particular framework:

```text

  1. Authenticate the user or calling service.
  2. Resolve the tenant from the app's trusted identity and membership context.
  3. Check that the requested feature is available to that tenant.
  4. Resolve the tenant's eligible provider connection and installation server-side.
  5. Confirm the installation and connection relationship before the provider call.
  6. Keep the returned data associated with that same tenant context.
    ```
Proposed six-step app-side flow: authenticate the user or service, resolve the tenant from trusted identity and membership, check feature access, resolve that tenant’s provider connection and installation server-side, confirm their relationship before the provider call, then keep returned data in the same tenant context. View image detail

Choose Actual size to read the graphic closely.

This is an application design proposal. It is not executable code, a test result, or a feature Ampersand claims to enforce.

If the agent tool accepts an installation reference as an argument, the reference is still a request. It should not become authorization merely because the model produced it. The server can ignore that value and select the allowed installation from trusted tenant state, or compare it against the allowed installation and reject a mismatch. Which pattern fits the app depends on its design, but the check must happen in the server-side path that selects the provider resource.

A caller-provided installation reference is treated as a request; the server either resolves from trusted tenant state or checks the reference and rejects a mismatch. View image detail

Choose Actual size to read the graphic closely.

The same idea applies to browser requests and internal service calls. A form field, URL parameter, hidden page value, API request body, or model argument can identify a resource someone wants to use. None of those values should decide whether the current tenant may use it. The app must resolve or validate the relationship against trusted state.

This is deliberately narrower than a general agent-permission discussion. It does not answer whether the agent should be allowed to edit a CRM record, whether a person should approve a write, or how broad the Salesforce user’s permissions should be. It answers which customer’s CRM the application may reach for the current tenant. For the separate authority question, see Rise’s AI agent oversight guide and personal AI agent governance guide.

Make the tenant-to-installation relationship hard to bypass

The invariant needs a concrete owner in the application. Depending on the architecture, that could be a shared authorization service, a data access layer, a repository function, or a server-side integration resolver. The implementation choice varies, but the contract should be visible: callers provide the tenant context established by the app, and the resolver returns only an installation linked to that tenant.

Avoid spreading the same relationship check across unrelated pages and tools. If one route checks the tenant and another route accepts an installation ID directly, the second route can become a shortcut around the intended boundary. A shared resolver may make it easier for each feature to ask the same question, but abstraction alone does not create safety. The resolver still needs correct inputs and a test that attempts to cross the boundary.

A resolver might conceptually accept a trusted tenant context and a provider type, then return an authorized installation or no result. It should not accept an arbitrary tenant chosen by the caller as proof of access. If the product supports multiple installations for one provider and tenant, the app also needs a rule for selecting among them, such as an explicitly configured feature binding. Without such a rule, “find a Salesforce connection” may return an ambiguous result.

The exact design depends on what your app supports. One product may allow one active Salesforce installation per tenant. Another may allow several, with a named business unit or feature configuration selecting one. A third may support a connection replacement process. Do not write a universal rule from these examples. Record the product’s actual selection rule and make the resolver enforce it.

Treat state changes as authorization changes. If a customer disconnects a provider, removes an installation, or changes which connection a feature uses, later requests should reflect the new state. This does not require a particular cache invalidation or lifecycle implementation in this article. It does mean the application needs a defined answer for whether an old reference remains usable after the relationship changes. If the status is ambiguous, the safest product behavior may be to stop and require the relationship to be resolved again. That is a proposed failure policy for the product team to evaluate.

Proposed three-state policy: a tenant, provider connection, and installation have an existing relationship; disconnect, removal, or reassignment changes it; the prior reference is marked stale pending re-resolution. No cache or lifecycle mechanism is shown. View image detail

Choose Actual size to read the graphic closely.

For a security review, draw the route from the application identity to the provider call. Mark each place where code can choose a tenant, connection, or installation. Then ask whether that choice uses a trusted tenant relation or caller-controlled data. This drawing is useful because a product can have correct data in its settings screen and still have a different backend route that selects a provider connection incorrectly.

Pick a storage model, then apply the same rule at each lookup

SaaS products choose different ways to store customer state. The app might isolate a customer’s integration references in dedicated resources, place customers in separate schemas, or store multiple tenants in shared tables with tenant-aware access rules. Each choice moves the boundary to a different layer, but none removes the need to bind a request to the correct tenant and installation.

AWS’s multi-tenant architecture guidance describes silo, bridge, and pool patterns for database design. Its examples use AWS services: a silo gives each tenant a dedicated application stack and database; a bridge shares the application stack while separating database schemas; a pool shares database objects and relies on row-level security. AWS frames them as tradeoffs among tenant isolation, cost, and complexity. This is AWS-specific guidance, not an Ampersand design and not a universal prescription for storing CRM connections. AWS, “Guidance for Multi-Tenant Architectures on AWS”

Three AWS sharing patterns with equal labels: silo gives each tenant a dedicated application stack and database; bridge shares the application and database with a separate tenant schema; pool shares the application, database instance and objects while tenant rows coexist under row-level security for tenant isolation. View image detail

Choose Actual size to read the graphic closely.

The same principle applies to app-managed references. In a dedicated design, a tenant’s connection and installation reference may sit in a resource reserved for that tenant. In a shared design, rows for many customers may sit together with each record linked to a tenant. The shared design then depends on consistent tenant scoping wherever the app reads or updates that relationship. A separate schema can reduce some accidental mixing but still depends on the application selecting the right schema. A dedicated resource can reduce shared paths but still depends on the router pointing to the correct customer resource.

There is no need to declare one model universally best here. The more useful decision is whether your chosen storage and application paths can enforce the invariant with controls your team understands and can maintain. If a shared table makes it easy to query by installation ID without checking the tenant, add a stronger constraint or change the access path. If a siloed resource still relies on a caller-supplied tenant name to choose a database, that route needs review too.

Map the tenant relationship for every value that selects a provider resource. That includes the app’s stored provider connection, installation, integration configuration, and normalized customer data if the app keeps a copy. The map does not need to describe every operational detail. It needs to identify who owns the resource and which trusted path establishes that ownership before the app uses it.

Test the denied route, not only the successful connection

A “connection successful” check proves that the app can reach a provider account. It does not prove that the app selected the right account for the current tenant. The test plan should try to make the application cross the customer boundary and confirm that it refuses.

Use two fictional SaaS tenants, Acme and Birch, with distinct provider test organizations. Give each a different installation or mapping for the same normalized field. Then exercise the app’s own authorization path. The following matrix is proposed; none of these tests has been executed for Ampersand or a customer application.

  • Valid Acme request: Attempt: An Acme user asks for a renewal summary in Acme’s workspace.; Expected authorization result: The app resolves Acme’s trusted tenant context and only Acme’s authorized installation.
  • Installation substitution: Attempt: An Acme request includes Birch’s installation reference in a tool argument or request body.; Expected authorization result: The server ignores the untrusted selector or rejects it. It does not call Birch’s provider connection.
  • Tenant substitution: Attempt: A caller changes a tenant reference in a URL or request body while remaining authenticated as an Acme user.; Expected authorization result: The app resolves the tenant from trusted membership context or denies the request. Caller input does not switch the customer.
  • Connection mismatch: Attempt: Acme’s tenant points to an Acme installation, but test state associates that installation with Birch’s provider connection.; Expected authorization result: The resolver detects the inconsistent relationship and returns no authorized installation.
  • Orphan installation: Attempt: The app receives or stores an installation reference with no current tenant relationship.; Expected authorization result: The app denies provider access until an authorized relationship exists.
  • Multiple eligible installations: Attempt: Acme has two Salesforce installations and the feature has no explicit selection rule.; Expected authorization result: The app returns an ambiguity result or requires configuration; it does not select an arbitrary installation.
  • Removed connection: Attempt: Acme’s authorized connection is removed or disconnected, then the app repeats the request.; Expected authorization result: The app does not fall back to Birch or another tenant. It returns the product’s defined unavailable state.
  • Mapping separation: Attempt: Acme and Birch map renewalDate to different test fields.; Expected authorization result: Each tenant reads only the mapping associated with its own authorized installation.
  • Cross-tenant record selector: Attempt: An Acme request supplies a record reference that exists in Birch’s test organization.; Expected authorization result: The app does not use the supplied reference to choose Birch’s connection or return Birch’s data.
  • Direct route check: Attempt: Call any backend route or tool that selects an installation without going through the normal UI.; Expected authorization result: The server-side authorization rule still denies a tenant-to-installation mismatch.

The most important assertion is not merely “request failed.” It is that the provider call did not run through Birch’s connection when the request context belonged to Acme. In a test environment, the team can verify the selected tenant and installation identifiers and assert that the mismatch path returns before provider access. Do not put real customer records or credentials into fixtures.

Tests can run at several layers. A unit test can exercise the resolver with an Acme tenant and Birch installation. A route-level test can submit a forged installation argument through the same handler the product uses. An end-to-end test can connect two isolated test organizations and confirm the app does not return data from the other one. These are suggested levels, not a requirement to use a particular framework or a claim that such a test has passed.

Three suggested test scopes: a resolver test with Acme and Birch, a route test with a forged installation argument, and an end-to-end test between two isolated organizations. None is reported as run. View image detail

Choose Actual size to read the graphic closely.

A passing test only covers the route and version it exercises. It does not certify every feature, every provider connection, or future changes. For that reason, list which code paths select provider resources, and map each path to a negative test. A new integration feature should not inherit an assumption that another feature’s test covered it unless both use the same verified authorization route.

Record the expected tenant, attempted installation, and allow-or-deny result in the test assertion. Do not put real customer records or credentials into fixtures. The goal is to verify what your app selected and why.

Separate app authorization from provider-side permissions

The provider connection has its own access rules. Salesforce recommends a dedicated integration user for each integration and describes how separate users can restrict the accessible data and functionality while improving transaction traceability. Salesforce also documents API-only integration profiles and edition availability. These controls can narrow what a connected Salesforce identity may do inside a Salesforce organization. They do not decide which SaaS tenant may select that connection. Salesforce, “Give Integration Users API Only Access”

Keep the two controls distinct in the design. Salesforce permissions answer, “What can this provider identity do in this Salesforce organization?” The SaaS tenant-to-installation rule answers, “Which provider identity may this app tenant use?” A Salesforce user with narrow permissions can still be the wrong user for an Acme request if it belongs to Birch’s organization. Conversely, the SaaS app can select Acme’s correct connection while that Salesforce identity has broader permissions than the product needs. Those are separate review findings.

Two separate checks: Salesforce org scope asks what a provider identity can do, while a SaaS tenant rule asks which identity that app tenant may use. View image detail

Choose Actual size to read the graphic closely.

This distinction is useful when someone proposes that a dedicated Salesforce user solves cross-tenant access. It helps limit provider-side access, but the application still has to bind its user and tenant to the right Salesforce connection. The application’s authorization tests should focus on that binding. Provider-side permission tests can complement them, but they do not substitute for them.

Ampersand’s current overview describes the platform as managing customer configurations and making provider API calls for them. That product capability may reduce the amount of provider-specific integration code a SaaS team writes. It does not remove the SaaS team’s responsibility to decide which tenant is asking and which authorized installation the application should use. The public product page does not claim to certify an integrating app’s tenant-to-installation authorization.

The current Ampersand AI SDK documentation also labels the SDK alpha and says it may change in non-backwards-compatible ways. It lists tools for provider operations and checking or creating connections and installations. Those documented names describe available interfaces; they do not prove a security property for the application that calls them. Teams considering the SDK should verify current documentation and test their own authorization path before relying on it. Ampersand AI SDK

Put the boundary in the design review

Before a feature uses customer CRM data, ask the product and engineering owners to answer five questions in concrete terms:

  1. Where does trusted tenant context come from? Identify the authentication and membership path that establishes the active SaaS tenant.
  2. What exact relationship authorizes the installation? Name the app-owned association among tenant, provider connection, and integration installation.
  3. Which server-side component resolves it? Point to the route, tool handler, resolver, or data access path that selects the provider resource.
  4. What happens when the relationship is missing or inconsistent? State the denial behavior. The app should not guess or fall back to another customer’s connection.
  5. Which negative test proves the denied case? Show a test where Acme attempts to use Birch’s installation and the app stops before using Birch’s provider connection.

The answers should fit on a small system map. The map should show the user, trusted tenant context, provider connection, and installation as distinct references, then show the check that binds them. If the only explanation is “the user is logged in,” the team has not yet shown which customer resource the app will use.

For a feature that supports a single provider connection per tenant, the selection rule may be straightforward. For a feature with multiple connections, the product needs an explicit choice tied to its own configuration. For a disconnected or inconsistent setup, the app needs a defined denial or repair path. These are product decisions. They should be reflected in the resolver and the negative tests rather than left to incidental database ordering or model-generated arguments.

Two independent proposed product-policy checks appear in separate panels. Feature cardinality: for a single provider connection per tenant, the selection rule may be straightforward; with multiple connections, the product needs an explicit choice tied to its own configuration. Connection state: a disconnected or inconsistent setup needs a defined denial or repair path. View image detail

Choose Actual size to read the graphic closely.

The October 6 Ampersand announcement makes integrations for agents timely, but the boundary question applies to any SaaS product that connects customer-owned systems. Start with the authorization invariant, map the tenant-to-installation relationship, and test the route that should fail. The goal is not to claim a platform or product is secure because it has a connection check. The goal is to prove, for the app paths you tested, that Acme cannot select Birch’s CRM installation.

Checked for this article

Sources

  1. Ampersand, October 6 announcement
  2. AWS, Tenant isolation
  3. AWS, SaaS identity
  4. Ampersand, Integration infrastructure for enterprise agents
  5. AWS, Guidance for Multi-Tenant Architectures on AWS
  6. Salesforce, Give Integration Users API Only Access
  7. Ampersand AI SDK

Keep going

All articles