Skip to content

Connected accounts

Learn how to manage connected accounts in Agent Auth, including user authentication, authorization status, and account lifecycle management.

Connected accounts in Agent Auth represent individual user or organization connections to third-party providers. They contain the authentication state, tokens, and permissions needed to execute tools on behalf of a specific identifier (user_id, org_id, or custom identifier).

Connected accounts are the runtime instances that link your users to their third-party application accounts. Each connected account:

  • Links to a connection: Uses a pre-configured connection for authentication
  • Has a unique identifier: Associated with a user_id, org_id, or custom identifier
  • Maintains auth state: Tracks whether the user has completed authentication
  • Stores tokens: Securely holds access tokens and refresh tokens
  • Manages permissions: Tracks granted scopes and permissions

Connected accounts go through several states during their lifecycle:

  1. Pending: Account created but user hasn’t completed authentication
  2. Active: User has authenticated and tokens are valid
  3. Expired: Tokens have expired and need refresh
  4. Revoked: User has revoked access to the application
  5. Error: Account has authentication or configuration errors
  6. Suspended: Account temporarily disabled
PendingActiveExpiredRevokedErrorSuspended
  1. Navigate to connected accounts in your Agent Auth dashboard
  2. Click create account to start the process
  3. Select connection to use for authentication
  4. Enter identifier (user_id, email, or custom identifier)
  5. Configure settings such as scopes and permissions
  6. Generate auth URL for the user to complete authentication
  7. Monitor status until user completes the flow

Create connected accounts programmatically:

Terminal window
curl -X POST "https://api.scalekit.com/v1/connect/accounts" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"connection_id": "conn_gmail_oauth",
"identifier": "user_123",
"identifier_type": "user_id",
"scopes": ["https://www.googleapis.com/auth/gmail.send"],
"settings": {
"auto_refresh": true,
"expires_in": 3600
}
}'

For OAuth connections, connected accounts follow the standard OAuth flow:

  1. Create connected account with pending status
  2. Generate authorization URL for the user
  3. User completes OAuth flow with the third-party provider
  4. Provider redirects back with authorization code
  5. Exchange code for tokens and update account status
  6. Account becomes active and ready for tool execution

Generate URLs for users to complete authentication:

// Generate authorization URL
const authUrl = await agentConnect.accounts.getAuthUrl('account_id', {
state: 'custom_state_value',
redirect_uri: 'https://your-app.com/callback',
scopes: ['additional_scope']
});
// Example generated URL
// https://accounts.google.com/oauth/authorize?
// client_id=your_client_id&
// redirect_uri=https://your-app.com/callback&
// scope=https://www.googleapis.com/auth/gmail.send&
// response_type=code&
// state=custom_state_value

Process the OAuth callback to complete authentication:

// Handle OAuth callback
app.get('/callback', async (req, res) => {
const { code, state, error } = req.query;
if (error) {
// Handle OAuth error
return res.status(400).json({ error: error });
}
try {
// Exchange code for tokens
const result = await agentConnect.accounts.exchangeCode(
'account_id',
code,
state
);
// Account is now active
res.json({ status: 'success', account: result });
} catch (err) {
res.status(500).json({ error: err.message });
}
});

Retrieve connected account details:

const account = await agentConnect.accounts.get('account_id');
// Account object structure
{
"id": "account_123",
"connection_id": "conn_gmail_oauth",
"identifier": "user_123",
"identifier_type": "user_id",
"provider": "gmail",
"status": "active",
"scopes": ["https://www.googleapis.com/auth/gmail.send"],
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:45:00Z",
"expires_at": "2024-01-15T11:45:00Z",
"metadata": {
"user_email": "user@example.com",
"provider_account_id": "google_user_123"
}
}

Connected accounts automatically handle token lifecycle:

Automatic token refresh:

  • Tokens are refreshed automatically before expiration
  • Refresh happens transparently during tool execution
  • Failed refresh attempts update account status to expired

Manual token refresh:

// Manually refresh tokens
const refreshed = await agentConnect.accounts.refreshTokens('account_id');
// Check token status
const tokenStatus = await agentConnect.accounts.getTokenStatus('account_id');

Monitor account authentication status:

// Check account status
const status = await agentConnect.accounts.getStatus('account_id');
// Possible status values:
// - pending: Waiting for user authentication
// - active: Authenticated and ready
// - expired: Tokens expired, needs refresh
// - revoked: User revoked access
// - error: Authentication error
// - suspended: Account temporarily disabled

Connected accounts can have different scopes than their parent connection:

// Create account with custom scopes
const account = await agentConnect.accounts.create({
connection_id: 'conn_gmail_oauth',
identifier: 'user_123',
scopes: [
'https://www.googleapis.com/auth/gmail.readonly', // Read-only access
'https://www.googleapis.com/auth/gmail.send' // Send emails
]
});
// Update account scopes (requires re-authentication)
await agentConnect.accounts.updateScopes('account_id', {
scopes: ['https://www.googleapis.com/auth/gmail.modify']
});

Verify account permissions before tool execution:

// Check if account has required permissions
const hasPermission = await agentConnect.accounts.hasPermission(
'account_id',
'https://www.googleapis.com/auth/gmail.send'
);
// Get all granted permissions
const permissions = await agentConnect.accounts.getPermissions('account_id');

Store additional information with connected accounts:

// Add custom metadata
await agentConnect.accounts.updateMetadata('account_id', {
user_email: 'user@example.com',
department: 'engineering',
preferences: {
notification_settings: 'email',
timezone: 'UTC'
}
});
// Retrieve metadata
const metadata = await agentConnect.accounts.getMetadata('account_id');

Configure account-specific settings:

// Update account settings
await agentConnect.accounts.updateSettings('account_id', {
auto_refresh: true,
rate_limit: 100,
timeout: 30,
retry_attempts: 3
});

Handle multiple connected accounts efficiently:

// Create multiple accounts
const accounts = await agentConnect.accounts.createBulk([
{
connection_id: 'conn_gmail_oauth',
identifier: 'user_1',
identifier_type: 'user_id'
},
{
connection_id: 'conn_gmail_oauth',
identifier: 'user_2',
identifier_type: 'user_id'
}
]);
// Get accounts by connection
const gmailAccounts = await agentConnect.accounts.list({
connection_id: 'conn_gmail_oauth'
});
// Get accounts by status
const activeAccounts = await agentConnect.accounts.list({
status: 'active'
});

Perform operations on multiple accounts:

// Refresh tokens for multiple accounts
const refreshResults = await agentConnect.accounts.refreshTokensBulk([
'account_1',
'account_2',
'account_3'
]);
// Update settings for multiple accounts
await agentConnect.accounts.updateSettingsBulk([
'account_1',
'account_2'
], {
auto_refresh: true,
rate_limit: 150
});

Handle common connected account errors:

try {
const account = await agentConnect.accounts.get('account_id');
} catch (error) {
switch (error.code) {
case 'ACCOUNT_NOT_FOUND':
// Account doesn't exist
break;
case 'ACCOUNT_EXPIRED':
// Tokens expired, refresh needed
break;
case 'ACCOUNT_REVOKED':
// User revoked access
break;
case 'INVALID_PERMISSIONS':
// Insufficient permissions
break;
default:
// Other errors
break;
}
}

Implement error recovery strategies:

  1. Detect error - Monitor account status and API responses
  2. Classify error - Determine if error is recoverable
  3. Attempt recovery - Try token refresh or re-authentication
  4. Notify user - Inform user if manual action is required
  5. Update status - Update account status based on recovery result

Protect user tokens and credentials:

  • Encryption: All tokens are encrypted at rest and in transit
  • Token rotation: Implement regular token rotation
  • Access logging: Log all token access and usage
  • Secure storage: Use secure storage mechanisms for tokens

Follow principle of least privilege:

  • Minimal scopes: Request only necessary permissions
  • Scope validation: Verify permissions before tool execution
  • Regular audit: Review granted permissions regularly
  • User consent: Ensure users understand granted permissions

Ensure proper account isolation:

  • Tenant isolation: Separate accounts by tenant/organization
  • User isolation: Prevent cross-user data access
  • Connection isolation: Separate different connection types
  • Audit trail: Maintain detailed audit logs

Monitor connected account health:

// Get account health metrics
const health = await agentConnect.accounts.getHealth('account_id');
// Health metrics include:
// - Token expiry status
// - Authentication success rate
// - API error rates
// - Last successful authentication

Track account usage patterns:

// Get account usage statistics
const usage = await agentConnect.accounts.getUsage('account_id', {
start_date: '2024-01-01',
end_date: '2024-01-31'
});
// Usage data includes:
// - Total tool executions
// - API requests made
// - Error rates
// - Most used tools
  • Regular cleanup: Remove unused or expired accounts
  • Status monitoring: Monitor account status changes
  • Proactive refresh: Refresh tokens before expiration
  • User notifications: Notify users of authentication issues
  • Connection pooling: Reuse connections efficiently
  • Token caching: Cache tokens appropriately
  • Batch operations: Use bulk operations when possible
  • Async processing: Handle authentication flows asynchronously
  • Clear error messages: Provide helpful error messages to users
  • Seamless re-auth: Make re-authentication flows smooth
  • Status visibility: Show users their connection status
  • Easy revocation: Allow users to easily revoke access

Test connected accounts in development:

// Create test account
const testAccount = await agentConnect.accounts.create({
connection_id: 'conn_test_provider',
identifier: 'test_user',
identifier_type: 'user_id',
test_mode: true
});
// Use test tokens
const testTokens = await agentConnect.accounts.getTestTokens('account_id');

Test authentication flows:

  1. Create test connection with test credentials
  2. Create connected account with test identifier
  3. Generate auth URL and complete OAuth flow
  4. Verify account status becomes active
  5. Test tool execution with the account
  6. Test token refresh and error scenarios

Next, learn how to execute tools using your connected accounts to interact with third-party applications.