Authentication
Authentication patterns and secure API access for ADK TypeScript tools
Tool authentication enables secure access to protected resources and APIs. While ADK TypeScript doesn't currently include built-in authentication classes, you can implement secure authentication patterns using existing tools and standard libraries.
Authentication Approach
Authentication in ADK TypeScript focuses on practical patterns and integration with existing authentication libraries rather than custom authentication frameworks.
Current Implementation Strategy
🔑 Environment Variables
Secure credential storage using environment variables
📦 Standard Libraries
Integration with established authentication libraries
🔧 Custom Integration
Manual authentication implementation in custom tools
Development Status
Comprehensive authentication classes (AuthScheme, AuthCredential) are planned for future releases. Current approach uses standard libraries and patterns.
Authentication Patterns
API Key Authentication
The most common pattern for API access using keys or tokens.
Environment Variable Pattern
import { FunctionTool } from '@iqai/adk';
async function authenticatedApiCall(endpoint: string, data?: any) {
const apiKey = process.env.API_KEY;
if (!apiKey) {
return { error: 'API key not configured' };
}
const response = await fetch(endpoint, {
method: data ? 'POST' : 'GET',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: data ? JSON.stringify(data) : undefined
});
if (!response.ok) {
return { error: `API call failed: ${response.statusText}` };
}
return await response.json();
}
const apiTool = new FunctionTool(authenticatedApiCall, {
name: 'api_call',
description: 'Make authenticated API calls'
});
Header-based API Keys
async function headerApiKeyCall(endpoint: string, params: Record<string, any>) {
const headers: Record<string, string> = {
'X-API-Key': process.env.SERVICE_API_KEY!,
'Content-Type': 'application/json'
};
const response = await fetch(endpoint, {
method: 'POST',
headers,
body: JSON.stringify(params)
});
return response.json();
}
Query Parameter API Keys
async function queryApiKeyCall(endpoint: string, query: string) {
const url = new URL(endpoint);
url.searchParams.append('api_key', process.env.SERVICE_API_KEY!);
url.searchParams.append('q', query);
const response = await fetch(url.toString());
return response.json();
}
OAuth 2.0 Integration
Using standard OAuth libraries for secure authentication flows.
Google OAuth Example
import { OAuth2Client } from 'google-auth-library';
import { BaseTool } from '@iqai/adk';
class GoogleOAuthTool extends BaseTool {
private oauth2Client: OAuth2Client;
constructor() {
super({
name: 'google_oauth_tool',
description: 'Tool with Google OAuth authentication'
});
this.oauth2Client = new OAuth2Client(
process.env.GOOGLE_CLIENT_ID,
process.env.GOOGLE_CLIENT_SECRET,
process.env.GOOGLE_REDIRECT_URI
);
}
async runAsync(args: { operation: string; accessToken?: string }) {
try {
if (!args.accessToken) {
return { error: 'Access token required' };
}
this.oauth2Client.setCredentials({ access_token: args.accessToken });
// Make authenticated request
const response = await this.oauth2Client.request({
url: `https://www.googleapis.com/oauth2/v2/userinfo`,
method: 'GET'
});
return { success: true, data: response.data };
} catch (error) {
return {
success: false,
error: `OAuth request failed: ${error instanceof Error ? error.message : String(error)}`
};
}
}
async generateAuthUrl() {
return this.oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: ['https://www.googleapis.com/auth/userinfo.profile']
});
}
getDeclaration() {
return {
name: this.name,
description: this.description,
parameters: {
type: 'object',
properties: {
operation: {
type: 'string',
description: 'Operation to perform'
},
accessToken: {
type: 'string',
description: 'OAuth access token'
}
},
required: ['operation']
}
};
}
}
Generic OAuth 2.0 Pattern
interface OAuthConfig {
clientId: string;
clientSecret: string;
tokenUrl: string;
scope?: string;
}
class OAuthAuthenticator {
constructor(private config: OAuthConfig) {}
async getAccessToken(authCode: string): Promise<string> {
const response = await fetch(this.config.tokenUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
grant_type: 'authorization_code',
client_id: this.config.clientId,
client_secret: this.config.clientSecret,
code: authCode,
scope: this.config.scope || ''
})
});
const data = await response.json();
return data.access_token;
}
async refreshToken(refreshToken: string): Promise<string> {
const response = await fetch(this.config.tokenUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
grant_type: 'refresh_token',
client_id: this.config.clientId,
client_secret: this.config.clientSecret,
refresh_token: refreshToken
})
});
const data = await response.json();
return data.access_token;
}
}
Service Account Authentication
For Google Cloud and other service account patterns.
Google Service Account
import { GoogleAuth } from 'google-auth-library';
import { BaseTool } from '@iqai/adk';
class ServiceAccountTool extends BaseTool {
private auth: GoogleAuth;
constructor() {
super({
name: 'service_account_tool',
description: 'Tool using Google service account authentication'
});
this.auth = new GoogleAuth({
scopes: ['https://www.googleapis.com/auth/cloud-platform']
});
}
async runAsync(args: { endpoint: string; data?: any }) {
try {
const authClient = await this.auth.getClient();
const response = await authClient.request({
url: args.endpoint,
method: args.data ? 'POST' : 'GET',
data: args.data
});
return { success: true, data: response.data };
} catch (error) {
return {
success: false,
error: `Service account request failed: ${error instanceof Error ? error.message : String(error)}`
};
}
}
getDeclaration() {
return {
name: this.name,
description: this.description,
parameters: {
type: 'object',
properties: {
endpoint: {
type: 'string',
description: 'API endpoint URL'
},
data: {
type: 'object',
description: 'Optional request data'
}
},
required: ['endpoint']
}
};
}
}
JWT-based Service Authentication
import jwt from 'jsonwebtoken';
async function createJWTToken(payload: any, secret: string, expiresIn: string = '1h') {
return jwt.sign(payload, secret, { expiresIn });
}
async function authenticatedServiceCall(endpoint: string, payload: any) {
const token = await createJWTToken(
{ service: 'adk-agent', ...payload },
process.env.JWT_SECRET!
);
const response = await fetch(endpoint, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
return response.json();
}
Secure Credential Management
Environment Variables
Best practices for credential storage:
// Required environment variables
const requiredEnvVars = [
'API_KEY',
'CLIENT_SECRET',
'DATABASE_URL'
];
function validateEnvironment() {
const missing = requiredEnvVars.filter(key => !process.env[key]);
if (missing.length > 0) {
throw new Error(`Missing required environment variables: ${missing.join(', ')}`);
}
}
// Call during application startup
validateEnvironment();
Credential Rotation
interface CredentialManager {
getCredential(key: string): Promise<string>;
refreshCredential(key: string): Promise<string>;
isExpired(key: string): Promise<boolean>;
}
class SimpleCredentialManager implements CredentialManager {
private credentials = new Map<string, { value: string; expires: Date }>();
async getCredential(key: string): Promise<string> {
const cred = this.credentials.get(key);
if (!cred || await this.isExpired(key)) {
return await this.refreshCredential(key);
}
return cred.value;
}
async refreshCredential(key: string): Promise<string> {
// Implement credential refresh logic
const newCredential = await this.fetchFreshCredential(key);
this.credentials.set(key, {
value: newCredential,
expires: new Date(Date.now() + 60 * 60 * 1000) // 1 hour
});
return newCredential;
}
async isExpired(key: string): Promise<boolean> {
const cred = this.credentials.get(key);
return !cred || cred.expires < new Date();
}
private async fetchFreshCredential(key: string): Promise<string> {
// Implement actual credential refresh
return 'fresh-credential';
}
}
Error Handling and Security
Secure Error Handling
async function secureApiCall(endpoint: string, credentials: any) {
try {
const response = await fetch(endpoint, {
headers: {
'Authorization': `Bearer ${credentials.token}`
}
});
if (!response.ok) {
// Don't expose sensitive credential information
return {
error: `API request failed with status ${response.status}`,
retryable: response.status >= 500
};
}
return { success: true, data: await response.json() };
} catch (error) {
// Log detailed error internally, return safe error externally
console.error('API call failed:', error);
return {
error: 'Service temporarily unavailable',
retryable: true
};
}
}
Rate Limiting and Retry Logic
async function authenticatedCallWithRetry(
endpoint: string,
credentials: any,
maxRetries: number = 3
) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await fetch(endpoint, {
headers: {
'Authorization': `Bearer ${credentials.token}`,
'User-Agent': 'ADK-Agent/1.0'
}
});
if (response.ok) {
return await response.json();
}
if (response.status === 401) {
// Credential issue - don't retry
throw new Error('Authentication failed');
}
if (response.status === 429) {
// Rate limited - wait and retry
const retryAfter = response.headers.get('Retry-After');
const waitTime = retryAfter ? parseInt(retryAfter) * 1000 : 1000 * attempt;
await new Promise(resolve => setTimeout(resolve, waitTime));
continue;
}
if (response.status >= 500 && attempt < maxRetries) {
// Server error - retry with exponential backoff
await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 1000));
continue;
}
throw new Error(`API call failed: ${response.statusText}`);
} catch (error) {
if (attempt === maxRetries) {
throw error;
}
}
}
}
Future Authentication Features
Planned Features
Future versions of ADK TypeScript will include:
- Built-in AuthScheme and AuthCredential classes
- Automatic token management and refresh
- OAuth flow helpers and utilities
- Integration with secret management services
- Enhanced security and compliance features
Expected Features
- AuthScheme Class: Define authentication requirements for tools
- AuthCredential Class: Secure credential storage and management
- OAuth Helpers: Built-in OAuth 2.0 and OpenID Connect support
- Token Management: Automatic token refresh and rotation
- Secret Integration: Integration with AWS Secrets Manager, Azure Key Vault, etc.
Best Practices
Security Guidelines
- Environment Variables: Store sensitive credentials as environment variables
- Credential Validation: Validate credentials during application startup
- Secure Transmission: Always use HTTPS for credential exchanges
- Access Logging: Log authentication attempts for security monitoring
- Credential Rotation: Implement regular credential rotation where possible
Development Practices
- Separate Environments: Use different credentials for dev/staging/production
- Testing: Use mock credentials for testing, not production credentials
- Documentation: Document authentication requirements clearly
- Error Handling: Implement secure error handling that doesn't expose credentials
Production Considerations
- Monitoring: Monitor authentication success/failure rates
- Alerting: Set up alerts for authentication failures
- Backup Credentials: Have backup authentication methods where possible
- Compliance: Ensure authentication meets regulatory requirements