An integration is not finished when the first record appears in a demo. It is finished when identities can be revoked, duplicate events do not duplicate work, rate limits are respected, and an operator can explain what happened to a customer's data.
The most durable design separates four concerns: user identity, delegated API access, event delivery, and product-specific translation. Combining them in one callback handler produces an integration that is difficult to secure and nearly impossible to debug.
Separate SSO from API authorization
OAuth 2.0 lets a customer authorize limited access to another service. It is not, by itself, a user authentication protocol. Use OpenID Connect when the product needs an identity layer over OAuth. For a browser-based authorization flow, use current security guidance such as authorization code with PKCE, exact redirect URI matching, a protected state value, and least-privilege scopes. Do not put access tokens in URLs or logs.
SAML remains common for enterprise single sign-on. Treat the identity provider's assertion as an authenticated statement that still needs local authorization. Map the external organization to exactly one internal tenant, define how attributes and groups become product roles, and decide what happens when a user is removed upstream. SSO answers “who is this?”; your application must still answer “what may this identity do here?”
Store refresh tokens and SAML configuration as secrets, restrict who can retrieve them, and support rotation and revocation. Record the customer, scopes, installation identity, creation time, and last successful use so stale connections can be found.
Build one adapter per external product
Salesforce, Slack, and HubSpot expose different object models, permission schemes, pagination rules, rate limits, and webhook semantics. Keep those differences inside product adapters rather than teaching the rest of the application about every vendor.
A useful adapter surface might provide domain operations such as find_customer, create_follow_up, or post_approval_request. The adapter translates these into Salesforce records, Slack messages, or HubSpot objects. It also normalizes vendor-specific errors into categories such as unauthorized, rate-limited, unavailable, invalid request, and permanent rejection.
Store external identifiers alongside the tenant and provider. An object ID without a tenant and provider context is not globally meaningful. For high-volume syncs, use pagination checkpoints or vendor cursors rather than starting from the beginning after a failure.
Every adapter also has to preserve the application's tenant isolation boundary.
Verify every webhook before parsing its meaning
Follow the exact signature procedure published by the sender. Many schemes require the untouched request body, a timestamp, selected headers, and a shared secret. Parsing and re-serializing JSON before verification can change the bytes and invalidate a legitimate signature.
Enforce a replay window when timestamps are available. Only after verification should the system persist the event ID, associate it with a tenant installation, and enqueue work. Acknowledge within the provider's deadline; do not make the provider wait for model inference or several downstream calls.
Slack and HubSpot document retries and signature validation, but their details differ. Implement a provider-specific verifier behind a common internal interface rather than assuming one algorithm applies everywhere.
Design retries as a state machine
Network timeouts leave uncertainty: the remote system may have completed the write even though the response was lost. Use vendor-supported idempotency keys when available. Otherwise, create an internal operation key and reconcile against the external record before repeating a write.
Retry transient failures such as some 429 and 5xx responses with exponential backoff, jitter, and a maximum attempt or elapsed-time budget. Respect Retry-After when the provider sends it. Do not retry invalid credentials or malformed requests indefinitely. Send exhausted operations to a reviewable dead-letter state with tenant, operation, attempt count, and a redacted error summary.
For inbound events, assume at-least-once delivery and possible reordering. Use unique event IDs, compare source timestamps or versions, and make each state transition safe to repeat.
Common failure modes
- Treating OAuth as login without validating an identity token through an appropriate protocol.
- Giving every installation broad scopes because permission design was deferred.
- Mapping an SSO domain to a tenant without a verified administrative enrollment process.
- Verifying webhook signatures against a parsed body rather than the required raw bytes.
- Retrying a timed-out write and creating duplicate CRM records or messages.
- Ignoring pagination, rate-limit headers, token expiry, or permission changes.
- Logging authorization codes, access tokens, assertions, or entire customer payloads.
Implementation checklist
- Document the identity, authorization, provisioning, and deprovisioning flows separately.
- Use current OAuth security practices and request only necessary scopes.
- Bind each installation and external identifier to a tenant.
- Encrypt secrets, support rotation, and test revocation.
- Create typed adapters for Salesforce, Slack, HubSpot, and other providers.
- Verify webhooks before parsing or queuing their business action.
- Enforce idempotency and bounded, observable retries.
- Provide a reconnect path and an operator view of sync health.
- Test expired tokens, removed permissions, duplicate events, reordering, and rate limits.
Measurable signals
Monitor authorization completion rate, token refresh failures, installations with excessive scopes, webhook verification failures, duplicate-event suppression, API success and rate-limit rates by provider, sync lag, retry attempts, dead-letter volume, and time to reconnect a broken installation. Segment these by tenant without exposing tenant data in broadly accessible dashboards.
Further reading
Put this into practice
Discuss your integration architecture
Bring one real system or customer workflow and map the next practical decision.
Run the workflow readiness audit
Test the workflow, evidence, and control assumptions before committing to a build.
See the delivery path
See how Tier9AI scopes, controls, and delivers one production workflow.