# How to Manage Connection Requests for Third-Party App Authorizations in Composio

> Learn to manage third-party app connection requests in Composio. Initiate links, redirect users, and poll for active status using Composio's powerful tools.

- Repository: [Composio/composio](https://github.com/composiohq/composio)
- Tags: how-to-guide
- Published: 2026-02-19

---

**Managing connection requests in Composio involves creating a `ConnectionRequest` object via `ConnectedAccounts.link()` or `initiate()`, redirecting users to the provided `redirectUrl`, and polling for completion using `waitForConnection()` until the account status becomes `ACTIVE` or a specific error is thrown.**

When building integrations with external services like GitHub, Google, or Snowflake, orchestrating OAuth flows reliably is essential for production applications. The Composio SDK provides a structured pattern to manage connection requests for third-party app authorizations, encapsulating the authentication handshake, state polling, and error handling. This implementation is exposed through the `ConnectedAccounts` class in [`ts/packages/core/src/models/ConnectedAccounts.ts`](https://github.com/ComposioHQ/composio/blob/main/ts/packages/core/src/models/ConnectedAccounts.ts) and the `ConnectionRequest` model in [`ts/packages/core/src/models/ConnectionRequest.ts`](https://github.com/ComposioHQ/composio/blob/main/ts/packages/core/src/models/ConnectionRequest.ts).

## Creating a Connection Request

The SDK offers two primary entry points for initiating authorizations, both of which internally invoke the `createConnectionRequest` factory function to instantiate a request state object.

### OAuth Flow with ConnectedAccounts.link()

For standard OAuth-based third-party services, use the `link()` method to generate a connection request. This method accepts your internal user identifier and the authentication configuration ID, returning a `ConnectionRequest` instance containing the `redirectUrl`.

```typescript
const connectionReq = await composio.connectedAccounts.link(
  'user_123',               // your internal user ID
  'auth_config_github'      // ID of the GitHub auth config
);
console.log('Visit this URL to authorize:', connectionReq.redirectUrl);

```

### Programmatic Flow with ConnectedAccounts.initiate()

For scenarios requiring additional control—such as allowing multiple active connections per authentication configuration—use the `initiate()` method. This approach accepts an options object where you can disable the default single-connection guard.

```typescript
const conn = await composio.connectedAccounts.initiate(
  'user_123',
  'auth_config_github',
  { allowMultiple: true }   // enables multiple active GitHub accounts
);
console.log('Redirect the user to:', conn.redirectUrl);
await conn.waitForConnection();

```

## Handling the Authorization Redirect

Once instantiated, the `ConnectionRequest` object exposes a `redirectUrl` property that directs end-users to the third-party authorization page. Your application must navigate the user to this URL so the external service can authenticate and grant access permissions.

The request lifecycle is instrumented automatically via `telemetry.instrument(state, 'ConnectionRequest')`, enabling observability for each step of the authorization process.

## Polling for Connection Completion

After the user is redirected, the SDK manages state polling through the `waitForConnection(timeout?)` method implemented in [`ts/packages/core/src/models/ConnectionRequest.ts`](https://github.com/ComposioHQ/composio/blob/main/ts/packages/core/src/models/ConnectionRequest.ts). This helper continuously calls `client.connectedAccounts.retrieve(state.id)` against the Composio REST endpoint until one of three terminal states occurs:

- **`ACTIVE`** — Connection succeeded. The method returns a transformed `ConnectedAccountRetrieveResponse` (normalized via [`ts/packages/core/src/utils/transformers/connectedAccounts.ts`](https://github.com/ComposioHQ/composio/blob/main/ts/packages/core/src/utils/transformers/connectedAccounts.ts)).
- **`FAILED`** or **`EXPIRED`** — The SDK throws a `ConnectionRequestFailedError`.
- **Timeout** — The SDK throws a `ConnectionRequestTimeoutError` if the polling duration exceeds the threshold.

```typescript
// Default 60-second timeout
try {
  const connectedAccount = await connectionReq.waitForConnection();
  console.log('Connected account is now ACTIVE:', connectedAccount.id);
} catch (err) {
  if (err instanceof ConnectionRequestFailedError) {
    console.error('Connection failed:', err.message);
  } else if (err instanceof ConnectionRequestTimeoutError) {
    console.error('Timed out waiting for user to authorize.');
  }
}

```

### Customizing Timeout Durations

By default, `waitForConnection()` polls for 60 seconds. Override this by passing a millisecond value as the first argument:

```typescript
const timeoutMs = 2 * 60 * 1000; // 2 minutes
await connectionReq.waitForConnection(timeoutMs)
  .then(acc => console.log('Connected:', acc.id))
  .catch(err => console.error('Error:', err));

```

## Error Handling and Edge Cases

The Composio SDK defines three specific error classes in [`ts/packages/core/src/errors/ConnectionRequestErrors.ts`](https://github.com/ComposioHQ/composio/blob/main/ts/packages/core/src/errors/ConnectionRequestErrors.ts) to handle distinct failure modes during the request lifecycle:

- **`ComposioConnectedAccountNotFoundError`** — Thrown when the connection request ID does not exist or has been deleted from the system.
- **`ConnectionRequestFailedError`** — Indicates terminal error states when the authorization flow fails or the request expires before completion.
- **`ConnectionRequestTimeoutError`** — Raised when polling exceeds the specified timeout threshold without reaching an `ACTIVE` state.

```typescript
try {
  await connectionReq.waitForConnection();
} catch (err) {
  if (err instanceof ConnectionRequestFailedError) {
    console.error('Connection failed:', err.message);
  } else if (err instanceof ConnectionRequestTimeoutError) {
    console.error('Timed out waiting for user to authorize.');
  } else if (err instanceof ComposioConnectedAccountNotFoundError) {
    console.error('The request ID is invalid or has been deleted.');
  } else {
    console.error('Unexpected error:', err);
  }
}

```

## Advanced Configuration

### Allowing Multiple Connected Accounts

By default, Composio restricts users to one active connection per authentication configuration. To enable users to authorize multiple accounts from the same service (e.g., two separate GitHub accounts), pass `{ allowMultiple: true }` to the `initiate()` method as demonstrated in the programmatic flow example above.

### Telemetry and Observability

Each `ConnectionRequest` is automatically instrumented with telemetry data, allowing you to monitor authorization success rates, latency, and failure states across your application.

## Summary

- Create connection requests using `ConnectedAccounts.link()` for OAuth flows or `ConnectedAccounts.initiate()` for programmatic control, both implemented in [`ts/packages/core/src/models/ConnectedAccounts.ts`](https://github.com/ComposioHQ/composio/blob/main/ts/packages/core/src/models/ConnectedAccounts.ts).
- Redirect users to the `redirectUrl` property on the returned `ConnectionRequest` object to initiate third-party authorization.
- Poll for completion using `waitForConnection(timeout?)`, which queries the Composio API via `client.connectedAccounts.retrieve()` until the status becomes `ACTIVE`.
- Handle three specific error types defined in [`ts/packages/core/src/errors/ConnectionRequestErrors.ts`](https://github.com/ComposioHQ/composio/blob/main/ts/packages/core/src/errors/ConnectionRequestErrors.ts): `ConnectionRequestFailedError`, `ConnectionRequestTimeoutError`, and `ComposioConnectedAccountNotFoundError`.
- Enable multiple connections per auth configuration by setting `allowMultiple: true` in the initiation options.
- Monitor request lifecycles through built-in telemetry instrumentation that tracks state transitions automatically.

## Frequently Asked Questions

### What is the default timeout for waitForConnection()?

The default timeout is 60 seconds (60,000 milliseconds). You can specify a custom duration by passing a millisecond value as the first argument to `waitForConnection()`, such as `waitForConnection(120000)` for two minutes, as implemented in [`ts/packages/core/src/models/ConnectionRequest.ts`](https://github.com/ComposioHQ/composio/blob/main/ts/packages/core/src/models/ConnectionRequest.ts).

### How does Composio handle expired or failed connection requests?

When polling detects a `FAILED` or `EXPIRED` status, the SDK throws a `ConnectionRequestFailedError` from [`ts/packages/core/src/errors/ConnectionRequestErrors.ts`](https://github.com/ComposioHQ/composio/blob/main/ts/packages/core/src/errors/ConnectionRequestErrors.ts). This represents a terminal state, requiring you to create a new connection request to retry the authorization flow.

### Can I allow users to connect multiple accounts from the same service?

Yes. By default, Composio restricts users to one active connection per authentication configuration. To bypass this limitation, pass `{ allowMultiple: true }` as the third argument to `ConnectedAccounts.initiate()`, which disables the single-connection guard and enables multiple active sessions.

### Where is the connection request polling logic implemented?

The polling mechanism, state management, and error throwing are implemented in the `createConnectionRequest` factory function within [`ts/packages/core/src/models/ConnectionRequest.ts`](https://github.com/ComposioHQ/composio/blob/main/ts/packages/core/src/models/ConnectionRequest.ts). This module handles the transition states and transforms the raw API response into a typed `ConnectedAccountRetrieveResponse` using utilities from [`ts/packages/core/src/utils/transformers/connectedAccounts.ts`](https://github.com/ComposioHQ/composio/blob/main/ts/packages/core/src/utils/transformers/connectedAccounts.ts).