User Management

Learn how to manage users for your application

What are User IDs?

User IDs determine whose connected accounts and data you’re accessing in Composio. Every tool execution, connection authorization, and account operation requires a userId parameter that identifies which context to use.

User IDs act as containers that group connected accounts together across toolkits. Depending on your application, you can use User IDs to represent an individual user, a team, or an entire organization.

Quick Decision Guide

How do users access connected accounts in your app?

  • Each user connects their own personal accounts?
    Use User IDs
    Use your database UUID or primary key (e.g., user.id)
    Example: Users connect their personal Gmail, GitHub

  • Teams share the same connected accounts?
    Use Organization IDs
    Use your organization UUID or primary key (e.g., organization.id)
    Example: Company Slack workspace

Patterns

User IDs (Individual Accounts)

In production applications with multiple users, where each user connects and manages their own accounts.

Choosing User IDs:

  • Recommended: Database UUID or primary key (user.id)
  • Acceptable: Unique username (user.username)
  • Avoid: Email addresses (emails can change)
1// Use your database's user ID (UUID, primary key, etc.)
2const userId = user.id; // e.g., "550e8400-e29b-41d4-a716-446655440000"
3
4const tools = await composio.tools.get(userId, {
5 toolkits: ['github'],
6});
7
8const result = await composio.tools.execute('GITHUB_GET_REPO', {
9 userId: userId,
10 arguments: { owner: 'example', repo: 'repo' },
11});

Never use ‘default’ as an User ID in production with users. This could expose other users’ data

Organization IDs (Team Accounts)

For applications where teams share connections - one admin connects accounts, all team members use them.

When to use:

  • Team tools: Slack, Microsoft Teams, Jira
  • Shared accounts: support(at)company.com, company GitHub org
  • Enterprise apps: IT manages connections for all employees
1// Use the organization ID as userId
2const userId = organization.id; // e.g., "org_550e8400"
3
4// All users in the organization share the same connected accounts
5const tools = await composio.tools.get(userId, {
6 toolkits: ['slack'],
7});
8
9// Execute tools in the organization context
10const result = await composio.tools.execute('SLACK_SEND_MESSAGE', {
11 userId: userId,
12 arguments: {
13 channel: '#general',
14 text: 'Hello from the team!',
15 },
16});

Multiple Connected Accounts

A single User ID can have multiple connected accounts for the same toolkit. For example, a user might connect both their personal and work Gmail accounts.

Key concepts:

  • Each connected account gets a unique Connected Account ID
  • Multiple accounts can exist under the same User ID for any toolkit
  • You can specify which account to use when executing tools

Account selection:

  • Explicit: Specify the Connected Account ID to target a specific account
  • Default: If no Connected Account ID is provided, the most recently connected account is used

Examples

Organization-Based Application

In B2B applications, typically an admin connects accounts once and all team members share access. Here’s a complete implementation:

Key concepts:

  • Admin performs the OAuth connection using organization ID
  • All team members execute tools using the same organization ID
  • Permission checks ensure users can only access their organization’s connections
TypeScript
1import { Composio } from '@composio/core';
2const composio = new Composio({
3 apiKey: process.env.COMPOSIO_API_KEY,
4});
5
6// 1. Admin connects Slack for the entire organization
7async function connectOrganizationToSlack(organizationId: string, adminUserId: string) {
8 // Use organization ID as userId in Composio
9 const connectionRequest = await composio.toolkits.authorize(organizationId, 'slack');
10
11 // Store the connection request for the admin to complete
12 await storeConnectionRequest(organizationId, adminUserId, connectionRequest);
13
14 return connectionRequest.redirectUrl;
15}
16
17// 2. Any user in the organization can use the connected tools
18async function sendSlackMessage(organizationId: string, channel: string, message: string) {
19 return await composio.tools.execute('SLACK_SEND_MESSAGE', {
20 userId: organizationId, // organization ID, not individual user ID
21 arguments: {
22 channel: channel,
23 text: message,
24 },
25 });
26}
27
28// 3. Check if organization has required connections
29async function getOrganizationTools(organizationId: string) {
30 return await composio.tools.get(organizationId, {
31 toolkits: ['slack', 'github', 'jira'],
32 });
33}
34
35// Usage in your API endpoint
36app.post('/api/slack/message', async (req, res) => {
37 const { channel, message } = req.body;
38 const organizationId = req.user.organizationId; // Get from your auth system
39
40 // Verify user has permission to send messages for this organization
41 // The userCanSendMessages function is your responsibility - implement it based on your application's permission model (role-based, feature flags, etc.).
42 if (!(await userCanSendMessages(req.user.id, organizationId))) {
43 return res.status(403).json({ error: 'Insufficient permissions' });
44 }
45
46 try {
47 const result = await sendSlackMessage(organizationId, channel, message);
48 res.json(result.data);
49 } catch (error) {
50 res.status(500).json({ error: 'Failed to send message' });
51 }
52});

Multi-User Application

In B2C applications, each user connects and manages their own accounts. Every user goes through their own OAuth flow and their data remains completely isolated.

Key concepts:

  • Each user authorizes their own accounts using their unique user ID
  • Connections are isolated - users can only access their own connected accounts
  • No permission checks needed since users only access their own data
TypeScript
1import { Composio } from '@composio/core';
2const composio = new Composio({
3 apiKey: process.env.COMPOSIO_API_KEY,
4});
5
6// 1. User initiates GitHub connection
7async function connectUserToGitHub(userId: string) {
8 const connectionRequest = await composio.toolkits.authorize(userId, 'github');
9 return connectionRequest.redirectUrl;
10}
11
12// 2. Get user's connected GitHub tools
13async function getUserGitHubTools(userId: string) {
14 return await composio.tools.get(userId, {
15 toolkits: ['github'],
16 });
17}
18
19// 3. Execute tool for specific user
20async function getUserRepos(userId: string) {
21 return await composio.tools.execute('GITHUB_LIST_REPOS', {
22 userId: userId,
23 arguments: {
24 per_page: 10,
25 },
26 });
27}
28
29// Usage in your API endpoint
30app.get('/api/github/repos', async (req, res) => {
31 const userId = req.user.id; // Get from your auth system
32
33 try {
34 const repos = await getUserRepos(userId);
35 res.json(repos.data);
36 } catch (error) {
37 res.status(500).json({ error: 'Failed to fetch repos' });
38 }
39});

Data isolation: Composio ensures each userId’s connections and data are completely separate. User A can never access User B’s repositories.

Hybrid Pattern

Many applications need both personal and team resources. Users might connect their personal Gmail while sharing the company Slack workspace.

Common scenarios:

  • Personal calendars + shared project management
  • Individual GitHub accounts + organization repositories
1// ❌ Wrong: Using individual user ID for org-connected tool
2const userTools = await composio.tools.get(req.user.id, {
3 toolkits: ['slack'], // Fails - Slack is connected at org level
4});
5
6// ✅ Correct: Match the ID type to how the tool was connected
7const userPersonalTools = await composio.tools.get(req.user.id, {
8 toolkits: ['gmail'], // User's personal Gmail
9});
10
11const orgSharedTools = await composio.tools.get(req.user.organizationId, {
12 toolkits: ['slack', 'jira'], // Organization's shared tools
13});

Remember: The userId must match how the account was connected. If admin connected Slack with org ID, all members must use org ID to access it.

Best Practices

Your responsibilities:

  • Pass the correct User ID for each user
  • Verify user permissions before executing organization tools
  • Never use ‘default’ in production with multiple users
  • Keep User IDs consistent across your application and Composio
  • Use stable identifiers that won’t change over time

Data isolation: Composio ensures complete isolation between User IDs. Users cannot access another ID’s connections or data.