Manual auth management

Manual authentication lets you connect users to toolkits outside the chat flow. Reach for it when you want to:

  • Pre-authenticate users before they start chatting.
  • Build a custom connections UI in your app.

Authorize a toolkit

Call session.authorize() to generate a Connect Link URL, redirect the user, and wait for them to finish:

session = composio.create(user_id="user_123")

connection_request = session.authorize("gmail")

print(connection_request.redirect_url)
# https://connect.composio.dev/link/ln_abc123

connected_account = connection_request.wait_for_connection(60000)
print(f"Connected: {connected_account.id}")
const session = await composio.create("user_123");

const connectionRequest = await session.authorize("gmail");

console.log(connectionRequest.redirectUrl);
// https://connect.composio.dev/link/ln_abc123

const connectedAccount = await connectionRequest.waitForConnection(60000);
console.log(`Connected: ${connectedAccount.id}`);

Redirect the user to the redirectUrl. After they authenticate, they'll return to your callback URL. The connection request polls until the user completes authentication (default timeout: 60 seconds).

If the user closes the Connect Link without completing auth, the connection remains in INITIATED status until it expires.

Redirecting users after authentication

Pass a callbackUrl to control where users land after authenticating. You can include query parameters to carry context through the flow, for example to identify which userID or session triggered the connection.

connection_request = session.authorize(
    "gmail",
    callback_url="https://your-app.com/callback?user_id=user_123&source=onboarding"
)

print(connection_request.redirect_url)
const connectionRequest = await session.authorize("gmail", {
  callbackUrl: "https://your-app.com/callback?user_id=user_123&source=onboarding",
});

console.log(connectionRequest.redirectUrl);

After authentication, Composio redirects the user to your callback URL with the following parameters appended, while preserving your existing ones:

ParameterDescription
statussuccess or failed
connected_account_idThe ID of the newly created connected account
https://your-app.com/callback?user_id=user_123&source=onboarding&status=success&connected_account_id=ca_abc123

Check connection status

Use session.toolkits() to see all toolkits in the session and their connection status:

toolkits = session.toolkits()

for toolkit in toolkits.items:
    status = toolkit.connection.connected_account.id if toolkit.connection.is_active else "Not connected"
    print(f"{toolkit.name}: {status}")
const toolkits = await session.toolkits();

toolkits.items.forEach((toolkit) => {
  console.log(`${toolkit.name}: ${toolkit.connection?.connectedAccount?.id ?? "Not connected"}`);
});

Disabling in-chat auth

By default, sessions include the COMPOSIO_MANAGE_CONNECTIONS meta-tool that prompts users to authenticate during chat. To turn it off and handle auth entirely in your own UI, set manage_connections to False:

session = composio.create(
    user_id="user_123",
    manage_connections=False,
)
const session = await composio.create("user_123", {
  manageConnections: false,
});

Putting it together

A common pattern is to verify all required connections before starting the agent:

from composio import Composio

composio = Composio(api_key="your-api-key")

required_toolkits = ["gmail", "github"]

session = composio.create(
    user_id="user_123",
    manage_connections=False,  # Disable in-chat auth prompts
)

toolkits = session.toolkits()

connected = {t.slug for t in toolkits.items if t.connection.is_active}
pending = [slug for slug in required_toolkits if slug not in connected]

print(f"Connected: {connected}")
print(f"Pending: {pending}")

for slug in pending:
    connection_request = session.authorize(slug)
    print(f"Connect {slug}: {connection_request.redirect_url}")
    connection_request.wait_for_connection()

print("All toolkits connected!")
import { Composio } from "@composio/core";

const composio = new Composio({ apiKey: "your-api-key" });

const requiredToolkits = ["gmail", "github"];

const session = await composio.create("user_123", {
  manageConnections: false, // Disable in-chat auth prompts
});

const toolkits = await session.toolkits();

const connected = toolkits.items
  .filter((t) => t.connection?.connectedAccount)
  .map((t) => t.slug);

const pending = requiredToolkits.filter((slug) => !connected.includes(slug));

console.log("Connected:", connected);
console.log("Pending:", pending);

for (const slug of pending) {
  const connectionRequest = await session.authorize(slug);
  console.log(`Connect ${slug}: ${connectionRequest.redirectUrl}`);
  await connectionRequest.waitForConnection();
}

console.log("All toolkits connected!");

Next

Managing multiple connected accounts

Let a user connect work and personal accounts for the same toolkit, then pick which one runs