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:
| Parameter | Description |
|---|---|
status | success or failed |
connected_account_id | The ID of the newly created connected account |
https://your-app.com/callback?user_id=user_123&source=onboarding&status=success&connected_account_id=ca_abc123Check 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