Files
composio-skills-reference/composio-sdk/rules/app-connected-accounts.md
sohamganatra b8b711dff6 Add Composio SDK skill with rules and agent config
Adds composio-sdk/ with SKILL.md, AGENTS.md, and 18 rule files
covering Tool Router, direct execution, triggers, and auth patterns.

Source: composiohq/skills

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-05 22:54:21 -08:00

235 lines
6.3 KiB
Markdown

---
title: Connected Accounts Management
impact: HIGH
description: Comprehensive guide to CRUD operations on connected accounts with emphasis on secure authentication flows
tags: [connected-accounts, authentication, oauth, crud, security]
---
# Connected Accounts Management
> **Using Tool Router?** If you're using Tool Router, you can use `session.toolkits()` to view the auth configs and connected accounts being used by the Tool Router. You only need to use the methods below if you're managing connected accounts outside of Tool Router.
Connected accounts store authentication tokens for external services. Use the `connectedAccounts` API for CRUD operations.
## Create Connected Accounts
### Recommended: link() - Composio-Hosted Authentication
Use `link()` for most flows. Composio handles security, OAuth, and form rendering.
```typescript
const connectionRequest = await composio.connectedAccounts.link(
'user_123',
'auth_config_123',
{ callbackUrl: 'https://your-app.com/callback' }
);
// Redirect user to authentication page
window.location.href = connectionRequest.redirectUrl;
// Wait for completion
const account = await connectionRequest.waitForConnection();
```
**Why use link():**
- Handles OAuth security and form UI
- Works with 200+ services
- Whitelabel with your app name/logo (Project Settings on dashboard)
- No custom UI needed
### Advanced: initiate() - Custom Authentication UI
Only use when building custom auth interfaces:
```typescript
// API Key (custom form)
const connection = await composio.connectedAccounts.initiate(
'user_123',
'auth_config_456',
{
config: AuthScheme.ApiKey({ api_key: apiKey }),
}
);
// OAuth with extra params (Zendesk, PostHog, etc.)
const connection = await composio.connectedAccounts.initiate(
'user_123',
'zendesk_config',
{
config: AuthScheme.OAuth2({ subdomain: "your_subdomain" })
}
);
window.location.href = connection.redirectUrl;
```
**AuthScheme helpers:**
- `AuthScheme.OAuth2({ subdomain: 'example' })`
- `AuthScheme.ApiKey({ api_key: 'key123' })`
- `AuthScheme.Basic({ username: 'user', password: 'pass' })`
- `AuthScheme.BearerToken({ token: 'token123' })`
**Use initiate() only when:**
- Building custom authentication UI
- Handling credentials directly in backend
- OAuth requires extra parameters before redirect
## Read Connected Accounts
```typescript
// List all
const allAccounts = await composio.connectedAccounts.list();
// Filter by user
const userAccounts = await composio.connectedAccounts.list({
userIds: ['user_123'],
});
// Filter by toolkit
const githubAccounts = await composio.connectedAccounts.list({
toolkitSlugs: ['github'],
});
// Filter by status
const activeAccounts = await composio.connectedAccounts.list({
statuses: ['ACTIVE']
});
// Filter by auth config
const configAccounts = await composio.connectedAccounts.list({
authConfigIds: ['auth_config_123']
});
// Combine filters
const filtered = await composio.connectedAccounts.list({
userIds: ['user_123'],
toolkitSlugs: ['github', 'slack'],
statuses: ['ACTIVE']
});
// Get specific account
const account = await composio.connectedAccounts.get('conn_abc123');
```
**Available filters:**
- `userIds` - Filter by user IDs
- `toolkitSlugs` - Filter by toolkit slugs
- `statuses` - Filter by connection statuses (see below for values)
- `authConfigIds` - Filter by auth config IDs
- `limit` - Results per page
- `cursor` - Pagination cursor
- `orderBy` - 'created_at' or 'updated_at'
## Update Connected Accounts
```typescript
// Enable/disable
await composio.connectedAccounts.enable('conn_abc123');
await composio.connectedAccounts.disable('conn_abc123');
// Refresh credentials (expired OAuth tokens)
await composio.connectedAccounts.refresh('conn_abc123');
```
## Delete Connected Accounts
```typescript
await composio.connectedAccounts.delete('conn_abc123');
```
**Warning:** Permanent deletion. User must re-authenticate.
## Wait for Connection Completion
For async OAuth flows:
```typescript
// Default timeout (60 seconds)
const account = await composio.connectedAccounts.waitForConnection('conn_123');
// Custom timeout (2 minutes)
const account = await composio.connectedAccounts.waitForConnection('conn_123', 120000);
```
**Errors:**
- `ComposioConnectedAccountNotFoundError` - Account doesn't exist
- `ConnectionRequestFailedError` - Connection failed/expired
- `ConnectionRequestTimeoutError` - Timeout exceeded
## Common Patterns
### OAuth Flow
```typescript
// Create connection
async function connectUser(userId, authConfigId) {
const request = await composio.connectedAccounts.link(
userId,
authConfigId,
{ callbackUrl: 'https://app.com/callback' }
);
return { redirectUrl: request.redirectUrl };
}
// Handle callback
async function handleCallback(connectionId) {
try {
const account = await composio.connectedAccounts.waitForConnection(
connectionId,
180000
);
return { success: true, account };
} catch (error) {
if (error.name === 'ConnectionRequestTimeoutError') {
return { error: 'Timeout. Please try again.' };
}
throw error;
}
}
```
### Check Active Connections
```typescript
// Filter by status using statuses parameter
async function getUserActiveConnections(userId) {
const accounts = await composio.connectedAccounts.list({
userIds: [userId],
statuses: ['ACTIVE']
});
return accounts.items;
}
// Check multiple statuses
async function getUserConnectionsByStatus(userId) {
const accounts = await composio.connectedAccounts.list({
userIds: [userId],
statuses: ['ACTIVE', 'EXPIRED', 'FAILED']
});
return accounts.items;
}
async function isToolkitConnected(userId, toolkit) {
const accounts = await composio.connectedAccounts.list({
userIds: [userId],
toolkitSlugs: [toolkit],
statuses: ['ACTIVE']
});
return accounts.items.length > 0;
}
```
**Available statuses:**
- `INITIALIZING` - Connection being set up
- `INITIATED` - Connection initiated, awaiting completion
- `ACTIVE` - Connection active and ready to use
- `FAILED` - Connection failed
- `EXPIRED` - Credentials expired
- `INACTIVE` - Connection disabled
## Key Points
- **Prefer link()** - Security, UI, and whitelabeling handled
- **Store account IDs** - Save in your database, associate with users
- **Check status** - Verify ACTIVE before use, refresh on errors
- **Handle lifecycle** - Disable instead of delete when possible