How to Manage Connection Requests for Third-Party App Authorizations in Composio
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 and the ConnectionRequest model in 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.
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.
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. 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 transformedConnectedAccountRetrieveResponse(normalized viats/packages/core/src/utils/transformers/connectedAccounts.ts).FAILEDorEXPIRED— The SDK throws aConnectionRequestFailedError.- Timeout — The SDK throws a
ConnectionRequestTimeoutErrorif the polling duration exceeds the threshold.
// 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:
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 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 anACTIVEstate.
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 orConnectedAccounts.initiate()for programmatic control, both implemented ints/packages/core/src/models/ConnectedAccounts.ts. - Redirect users to the
redirectUrlproperty on the returnedConnectionRequestobject to initiate third-party authorization. - Poll for completion using
waitForConnection(timeout?), which queries the Composio API viaclient.connectedAccounts.retrieve()until the status becomesACTIVE. - Handle three specific error types defined in
ts/packages/core/src/errors/ConnectionRequestErrors.ts:ConnectionRequestFailedError,ConnectionRequestTimeoutError, andComposioConnectedAccountNotFoundError. - Enable multiple connections per auth configuration by setting
allowMultiple: truein 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.
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. 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. 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →