Authenticating Tools

Learn how to authenticate tools

Different apps (like Slack, Notion, Shopify) have their own authentication flows that users must complete to grant access to their accounts. Agents need authenticated access to these tools to perform actions on behalf of users.

Creating an auth config

Each toolkit comes with it’s own auth config. This configuration is used to authenticate the users to the tools.

The first step is to create an auth config for any toolkit that you want to use.

Auth configs are reusable

The appropriate developer credentials and app level configurations like scopes, API endpoints, etc. are scoped to an auth config.

Once created, it’s reusable across multiple users.

The dashboard offers a guided process for all app types.

1

Select App

Navigate to the Apps page and choose the app you want to integrate (for example, Google Sheets).

2

Initiate Setup

Click the “Setup Integration” button.

3

Configure Auth Config Settings

Select between the supported auth schemes of OAuth2, API Key, Bearer Token, Basic Auth, depending on the toolkit. Switch between the auth schemes and configure the scopes, developer credentials, etc here.

Composio Managed Auth

You may also choose to use Composio’s managed auth for certain toolkits or use your own auth credentials. It is recommended to use specify your own credentials for production workloads and ability to control scopes, etc.

4

Create and Get ID

Click “Create Integration”. After creation, copy the displayed starting with ac_. You’ll need this ID in your application code.

Connecting to an OAuth toolkit

Here’s how to authenticate a toolkit for a given user using the OAuth flow.

1import { Composio } from "@composio/core";
2
3const composio = new Composio();
4const linearAuthConfigId = "ac_1234";
5const userId = "your@email.com";
6
7// Initiate the OAuth connection request
8const connRequest = await composio.connectedAccounts.initiate(userId, linearAuthConfigId);
9
10// Destructure redirectUrl for easier access
11const { redirectUrl, id } = connRequest;
12console.log(redirectUrl);
13
14// Wait for the connection to be established
15await connRequest.waitForConnection();
16
17// If you only have the connection request ID, you can also wait using:
18await composio.connectedAccounts.waitForConnection(id);

Connecting to an API Key toolkit

For API key based toolkits, you can either request the user to provide the API key or provide your own!

Creating the connection

If you know the required authentication fields for your toolkit (like apiKey for most API-based services), you can directly create the connection:

1const authConfigId = "ac_1234"; // For example, auth config id of Serp API
2
3const connectionRequest = await composio.connectedAccounts.initiate(
4 userId,
5 authConfigId,
6 {
7 data: {
8 apiKey: "sk_1234567890", // The field name for the API key/token
9 },
10 }
11);

Fetching the field name

For more complex cases where you want to dynamically discover the exact field names and handle different auth schemes programmatically, you can fetch the auth field details first.

Here’s how to fetch the auth field names for a toolkit:

1import { Composio } from "@composio/core";
2
3const composio = new Composio();
4
5const userId = "your@email.com";
6const toolkits = await composio.toolkits.get("SERPAPI");
7
8// Destructure for easier access to authConfigDetails
9const { authConfigDetails = [] } = toolkits;
10
11// Extract required and optional field names using destructuring
12const fieldNames = authConfigDetails.flatMap(({ fields }) => {
13 const { connectedAccountInitiation } = fields;
14 return [
15 ...(connectedAccountInitiation.required?.map(({ name }) => name) || []),
16 ...(connectedAccountInitiation.optional?.map(({ name }) => name) || [])
17 ];
18});
19
20console.log(fieldNames); // e.g. ["apiKey"]

It might be useful to read all the optional and required auth config fields for a toolkit and optionally prompt the user for the values.

Below is a sample script that request the user or uses environment variables to read all the required fields for a token based toolkit.

1import { Composio } from "@composio/core";
2import * as readline from "readline";
3
4const composio = new Composio({
5 apiKey: process.env.COMPOSIO_API_KEY,
6});
7
8const userId = "your@email.com";
9const authConfigId = "ac_k_py8Qbd17_d"; // For example, auth config id of Serp API
10
11// Flag to control whether to prompt user for input or use environment variables
12const REQUEST_USER_INPUT = true; // Set to false to use environment variables
13
14const toolkits = await composio.toolkits.get("SERPAPI");
15
16// Destructure for easier access to authConfigDetails
17const { authConfigDetails = [] } = toolkits;
18
19// Extract required and optional field names using destructuring
20const authFields = authConfigDetails.flatMap(({ fields }) => {
21 const { connectedAccountInitiation } = fields;
22 return [
23 ...(connectedAccountInitiation.required?.map(({ name }) => name) || []),
24 ...(connectedAccountInitiation.optional?.map(({ name }) => name) || []),
25 ];
26});
27
28console.log("Required authentication fields:", authFields);
29
30// Function to prompt user for input
31async function promptUser(fieldName: string): Promise<string> {
32 const rl = readline.createInterface({
33 input: process.stdin,
34 output: process.stdout,
35 });
36
37 return new Promise((resolve) => {
38 rl.question(`Please enter value for ${fieldName}: `, (answer) => {
39 rl.close();
40 resolve(answer);
41 });
42 });
43}
44
45// Collect authentication data
46const authData: Record<string, string> = {};
47
48if (REQUEST_USER_INPUT) {
49 // Request user input for each required field
50 for (const fieldName of authFields) {
51 authData[fieldName] = await promptUser(fieldName);
52 }
53} else {
54 // Read values from environment variables
55 console.log("Reading values from environment variables...");
56 for (const fieldName of authFields) {
57 const envValue = process.env[fieldName.toUpperCase()];
58 if (envValue) {
59 authData[fieldName] = envValue;
60 console.log(`Found ${fieldName} in environment variables`);
61 } else {
62 console.warn(
63 `Warning: Environment variable ${fieldName.toUpperCase()} not found`
64 );
65 authData[fieldName] = ""; // Set empty string as fallback
66 }
67 }
68}
69
70console.log("Using authentication data:", authData);
71
72const connectionRequest = await composio.connectedAccounts.initiate(
73 userId,
74 authConfigId,
75 {
76 data: authData,
77 }
78);
79
80console.log("Connection request ID:", connectionRequest.id);

Redirecting users

To control where the users are redirected after they have authenticated, you can use the redirectUrl parameter in the initiate method. In this case, the user will be redirected to https://www.yourapp.com/callback after they have authenticated.

1const connectionRequest = await composio.connectedAccounts.initiate(
2 userId,
3 authConfigId,
4 {
5 callbackUrl: "https://www.yourapp.com/callback",
6 }
7);