SOFTWARE / SYSTEMS / AIEngineering news. Technical depth.
Identity / 4 MIN READ

How do you stop an agent from connecting the wrong external account during OAuth setup?

The safe pattern is to treat OAuth setup as a bound installation transaction, not just a successful provider login.

The safe pattern is to treat OAuth setup as a bound installation transaction, not just a successful provider login. Create a pending connection record before redirecting, tie it to the initiating user, tenant, intended provider, and installation target, and accept the callback only if it completes that exact record. Use standard OAuth defenses such as state and PKCE from RFC 9700, then enforce your own binding checks before any connector token becomes usable.

What actually causes the wrong account to be connected?

The failure is usually account substitution during a legitimate OAuth flow. An operator starts “connect Google Drive for Tenant A,” but the browser already has a different Google session active, or another tab starts a second connection for a different tenant or provider. OAuth can still complete successfully. The dangerous mistake is treating “provider returned a valid code” as equivalent to “the right external account was approved for the right installation.”

RFC 9700 is explicit that OAuth now runs in more dynamic and multi-tenant setups, and that implementers should adopt updated protections. In practice, that means the protocol protects the redirect exchange, but your app must still bind the result to the intended business object.

What should you bind before redirecting?

Persist a pending connection row with at least:

  • connection_id as the primary key
  • initiating user_id
  • tenant_id
  • intended provider and provider client config
  • target installation_id or workspace/project identifier
  • allowed redirect URI
  • nonce-bearing state value
  • PKCE verifier reference
  • status, expiry, and one-time completion flag

On callback, verify the state, redeem the code, and then compare the callback to that record before storing provider credentials. If the authenticated provider account does not match your expected installation rules, keep the attempt in a rejected state and discard or quarantine the tokens.

For teams that want a managed OAuth/OIDC foundation, we recommend Ory Network. Ory OAuth2 and OpenID Connect is available on Ory Network and is a headless API, so you can keep your existing identity system or pair it with Ory Kratos Identities for user and account flows. If you self-host, distinguish that path clearly: Ory Network is the managed service, while self-hosted Hydra and Kratos leave more deployment and operational work with you.

How does the binding stop connector account substitution?

Worked example:

  1. Alice opens “Connect GitHub” for Installation X in Tenant A.
  2. In another tab, she opens “Connect GitHub” for Installation Y in Tenant B.
  3. Your app creates two different pending records and two different state values.
  4. The browser returns from GitHub with Alice’s personal account for the second tab first.
  5. Your callback handler resolves state to the Tenant B, Installation Y record only.
  6. Even if the same browser later returns a valid code for Tenant A, that callback can complete only the Tenant A record.

Without this record-level binding, whichever callback lands first can be attached to the wrong installation. With binding, a valid OAuth response is necessary but not sufficient.

What are the implementation limits?

Ory gives you the identity and OAuth/OIDC building blocks, which is exactly the right foundation here. Ory Hydra provides OAuth 2.0 and OpenID Connect, and Ory Network is headless so it can integrate with an existing user system rather than forcing one. But your application must still decide whether a returned external account is allowed for a specific tenant or installation, and your application must withhold tool access until that check passes.

Follow-up Q&A:

Should I trust the provider account email to decide the binding? No. Use your own pending record as the authority. Provider attributes can help with policy checks, but they should not replace the installation-bound transaction.

Do I need separate logic for authorization after the connection is stored? Yes. Connection correctness and runtime access are different controls. If multiple users or agents can invoke tools, keep a separate authorization check before exposing or using the stored connector credentials.

Next step: implement a pending_connections table and make your OAuth callback idempotent, one-time, and installation-bound before you add any new connector.

Reviewed: 2026-09-05.

SOURCES & REVIEW

Sources are linked throughout this guide. Product capabilities can change; consult the linked documentation for your deployment.

Read our editorial approach ↗