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).
What are connected accounts?
Section titled “What are connected accounts?”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 account lifecycle
Section titled “Connected account lifecycle”Connected accounts go through several states during their lifecycle:
Account states
Section titled “Account states”- Pending: Account created but user hasn’t completed authentication
- Active: User has authenticated and tokens are valid
- Expired: Tokens have expired and need refresh
- Revoked: User has revoked access to the application
- Error: Account has authentication or configuration errors
- Suspended: Account temporarily disabled
State transitions
Section titled “State transitions”Creating connected accounts
Section titled “Creating connected accounts”Using the dashboard
Section titled “Using the dashboard”- Navigate to connected accounts in your Agent Auth dashboard
- Click create account to start the process
- Select connection to use for authentication
- Enter identifier (user_id, email, or custom identifier)
- Configure settings such as scopes and permissions
- Generate auth URL for the user to complete authentication
- Monitor status until user completes the flow
Using the API
Section titled “Using the API”Create connected accounts programmatically:
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 } }'const connectedAccount = await agentConnect.accounts.create({ 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 }});
// Generate authorization URL for userconst authUrl = await agentConnect.accounts.getAuthUrl(connectedAccount.id);connected_account = agent_connect.accounts.create( 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 })
# Generate authorization URL for userauth_url = agent_connect.accounts.get_auth_url(connected_account.id)Authentication flow
Section titled “Authentication flow”OAuth 2.0 flow
Section titled “OAuth 2.0 flow”For OAuth connections, connected accounts follow the standard OAuth flow:
- Create connected account with pending status
- Generate authorization URL for the user
- User completes OAuth flow with the third-party provider
- Provider redirects back with authorization code
- Exchange code for tokens and update account status
- Account becomes active and ready for tool execution
Authorization URL generation
Section titled “Authorization URL generation”Generate URLs for users to complete authentication:
// Generate authorization URLconst 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_valueHandling callbacks
Section titled “Handling callbacks”Process the OAuth callback to complete authentication:
// Handle OAuth callbackapp.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 }); }});@app.route('/callback')def handle_callback(): code = request.args.get('code') state = request.args.get('state') error = request.args.get('error')
if error: return jsonify({'error': error}), 400
try: # Exchange code for tokens result = agent_connect.accounts.exchange_code( 'account_id', code, state )
# Account is now active return jsonify({'status': 'success', 'account': result}) except Exception as e: return jsonify({'error': str(e)}), 500Managing connected accounts
Section titled “Managing connected accounts”Account information
Section titled “Account information”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" }}Token management
Section titled “Token management”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 tokensconst refreshed = await agentConnect.accounts.refreshTokens('account_id');
// Check token statusconst tokenStatus = await agentConnect.accounts.getTokenStatus('account_id');Account status monitoring
Section titled “Account status monitoring”Monitor account authentication status:
// Check account statusconst 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 disabledAccount permissions and scopes
Section titled “Account permissions and scopes”Scope management
Section titled “Scope management”Connected accounts can have different scopes than their parent connection:
// Create account with custom scopesconst 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']});Permission validation
Section titled “Permission validation”Verify account permissions before tool execution:
// Check if account has required permissionsconst hasPermission = await agentConnect.accounts.hasPermission( 'account_id', 'https://www.googleapis.com/auth/gmail.send');
// Get all granted permissionsconst permissions = await agentConnect.accounts.getPermissions('account_id');Account metadata and settings
Section titled “Account metadata and settings”Custom metadata
Section titled “Custom metadata”Store additional information with connected accounts:
// Add custom metadataawait agentConnect.accounts.updateMetadata('account_id', { user_email: 'user@example.com', department: 'engineering', preferences: { notification_settings: 'email', timezone: 'UTC' }});
// Retrieve metadataconst metadata = await agentConnect.accounts.getMetadata('account_id');Account settings
Section titled “Account settings”Configure account-specific settings:
// Update account settingsawait agentConnect.accounts.updateSettings('account_id', { auto_refresh: true, rate_limit: 100, timeout: 30, retry_attempts: 3});Bulk operations
Section titled “Bulk operations”Managing multiple accounts
Section titled “Managing multiple accounts”Handle multiple connected accounts efficiently:
// Create multiple accountsconst 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 connectionconst gmailAccounts = await agentConnect.accounts.list({ connection_id: 'conn_gmail_oauth'});
// Get accounts by statusconst activeAccounts = await agentConnect.accounts.list({ status: 'active'});Batch operations
Section titled “Batch operations”Perform operations on multiple accounts:
// Refresh tokens for multiple accountsconst refreshResults = await agentConnect.accounts.refreshTokensBulk([ 'account_1', 'account_2', 'account_3']);
// Update settings for multiple accountsawait agentConnect.accounts.updateSettingsBulk([ 'account_1', 'account_2'], { auto_refresh: true, rate_limit: 150});Error handling
Section titled “Error handling”Common errors
Section titled “Common errors”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; }}Error recovery
Section titled “Error recovery”Implement error recovery strategies:
- Detect error - Monitor account status and API responses
- Classify error - Determine if error is recoverable
- Attempt recovery - Try token refresh or re-authentication
- Notify user - Inform user if manual action is required
- Update status - Update account status based on recovery result
Security considerations
Section titled “Security considerations”Token security
Section titled “Token security”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
Permission management
Section titled “Permission management”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
Account isolation
Section titled “Account isolation”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
Monitoring and analytics
Section titled “Monitoring and analytics”Account health monitoring
Section titled “Account health monitoring”Monitor connected account health:
// Get account health metricsconst health = await agentConnect.accounts.getHealth('account_id');
// Health metrics include:// - Token expiry status// - Authentication success rate// - API error rates// - Last successful authenticationUsage analytics
Section titled “Usage analytics”Track account usage patterns:
// Get account usage statisticsconst 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 toolsBest practices
Section titled “Best practices”Account lifecycle management
Section titled “Account lifecycle management”- 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
Performance optimization
Section titled “Performance optimization”- Connection pooling: Reuse connections efficiently
- Token caching: Cache tokens appropriately
- Batch operations: Use bulk operations when possible
- Async processing: Handle authentication flows asynchronously
User experience
Section titled “User experience”- 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
Testing connected accounts
Section titled “Testing connected accounts”Development testing
Section titled “Development testing”Test connected accounts in development:
// Create test accountconst testAccount = await agentConnect.accounts.create({ connection_id: 'conn_test_provider', identifier: 'test_user', identifier_type: 'user_id', test_mode: true});
// Use test tokensconst testTokens = await agentConnect.accounts.getTestTokens('account_id');Integration testing
Section titled “Integration testing”Test authentication flows:
- Create test connection with test credentials
- Create connected account with test identifier
- Generate auth URL and complete OAuth flow
- Verify account status becomes active
- Test tool execution with the account
- Test token refresh and error scenarios
Next, learn how to execute tools using your connected accounts to interact with third-party applications.