Authentication

Composio organizes everything around your users. A user is whoever your agent acts on behalf of: a person in your app, identified by a userID you choose. Authentication is always per user. Each user connects their own accounts, their Gmail, their GitHub, their Slack, and Composio stores and refreshes those credentials against that userID.

This is the core idea: your agent runs the same tools for many people, and every tool call runs as a specific user against that user's connected accounts. User A's agent never touches user B's data. You pass the userID when you create a session, and Composio handles the auth from there.

Because connections are stored under the userID, use a stable identifier, like your database ID, never one that can change.

Your users connect their accounts through a secure Connect Link, and Composio manages their tokens for you.

Already have your own tools or agent framework? Follow Managed authentication for your own tools to connect users and call provider APIs without handling their tokens. You don't need predefined Composio tools, MCP, or an LLM.

~/projects/composio
active connections
ops@acme.comwork

Where credentials live

When users connect through a Connect Link and your agent acts through tools, your application never handles their OAuth tokens. Composio stores each connected account's credentials encrypted at rest and refreshes OAuth tokens before they expire. When your agent calls a tool, your backend sends a user ID or connected account ID plus the tool arguments. Composio adds the credential to the provider request server-side and returns the provider's response. Your application and the model receive tool results, not tokens.

  • No token export. Connected-account API responses redact credentials by default, for both Composio-managed and custom auth configs. Reading account state isn't a supported way to retrieve tokens.
  • Raw API access without the token. For endpoints a tool doesn't cover, Proxy Execute sends an authenticated request to the provider and returns the response. It requires its own API key permission.
  • Least-privilege keys and sessions. Scoped API keys separate session management from tool execution, and session configuration limits which toolkits and tools an agent can call.
  • Custody you choose. In the default Composio Cloud deployment, Composio holds the encrypted credentials. Private VPC, self-hosted, and customer-managed key deployments change that boundary. With customer-managed keys, a proxy in your cloud decrypts credentials under your KMS keys, and Composio doesn't hold the key material.

If you import existing credentials, your application handles those tokens once before sending them to Composio. See Token custody architecture for the full request flow, redaction scope, and deployment options.

How Composio handles authentication

Every session includes the COMPOSIO_MANAGE_CONNECTIONS meta tool. When a tool needs an account, it reads the toolkit's auth config (how that toolkit authenticates: method, scopes, credentials), creates a connection, and returns a secure Connect Link. This works for all Composio managed connections, so you don't have to set up any OAuth credentials yourself.

The user signs in on the hosted link and Composio stores the resulting connected account. Credentials never pass through your app or the model, so it's safe to surface the link right in the chat.

You only need a custom auth config to bring your own OAuth app, request specific scopes, or use a toolkit without managed auth.

In-chat authentication

The agent posts the Connect Link straight into the conversation. The user clicks it, signs in, and the agent retries the tool and continues. No auth UI for you to build.

agent
❯Summarize my emails from today
⏺COMPOSIO_MANAGE_CONNECTIONS
⎿Gmail not connected — sent Connect Link
Connect your Gmail account to continue:
⏺COMPOSIO_WAIT_FOR_CONNECTIONS
⎿✓ Gmail connected
⏺GMAIL_FETCH_EMAILS
⎿12 emails
Here's a summary of your emails from today...

You can also call COMPOSIO_MANAGE_CONNECTIONS yourself, intercept the Connect Link, and surface it wherever you need: DM it to the user, render it in your own UI, or email it. See redirect auth links for a worked example.

Custom callback URL

To send users back to your app after they connect, pass a callback_url:

session = composio.create(
    user_id="user_123",
    manage_connections={"callback_url": "https://yourapp.com/chat"},
)

Manually triggering authentication

Don't want to wait for the agent? Call session.authorize() to generate a Connect Link on demand, for onboarding, a settings page, or a pre-flight check before a task.

Manual auth management

session.authorize(), callback URLs, connection status, and disabling in-chat prompts

Behind the scenes

Composio manages authentication with auth configs. An auth config is a blueprint for how a toolkit authenticates across all your users. It defines three things:

  • Authentication method: OAuth2, Bearer token, API key, or Basic Auth
  • Scopes: what actions your tools can perform
  • Credentials: your own app credentials, or Composio's managed auth

Composio creates one auth config per toolkit and applies it to every user who connects that toolkit. Most toolkits use Composio managed auth, so you don't create or configure anything. You only need a custom auth config to use your own OAuth app or customize scopes.

ac_gmail_oauth2

One OAuth2 blueprint: auth method, scopes, and credentials. Reused for every user who connects Gmail.

Uuser_1
  • Work Gmailca_1a2b3c
  • Personal Gmailca_4d5e6f
Uuser_2
  • Gmailca_7g8h9i

one auth config a connected account per user, fully isolated

When a user authenticates, Composio creates a connected account: their credentials (OAuth tokens or API keys) linked to your userID. Each user can have multiple, even for the same toolkit (e.g. work and personal Gmail).

Connection lifecycle

For OAuth, Composio refreshes access tokens automatically before they expire, so connections stay ACTIVE with no work from you. If a refresh token is revoked or expires, the connection moves to EXPIRED and the user has to reconnect.

Composio
every 30 min
Gmailwork@acme.com
ACTIVEoauth · ••••9f3a
Notionacme-workspace
ACTIVEoauth · ••••2c7d
GitHubacme-bot
ACTIVEoauth · ••••b18e

Composio rotates every connection’s token on a schedule connections stay ACTIVE with no work from you

Catch this before a tool call fails by subscribing to the composio.connected_account.expired event on a webhook subscription. When it fires, send the user a fresh Connect Link to re-authenticate:

session = composio.create(user_id="user_123")
connection_request = session.authorize("gmail")

# Send this URL to the user (email, in-app notification, etc.)
print(connection_request.redirect_url)

Authentication guides