Authentication
Secure API access and credential management for ADK-TS tools
Authenticate your ADK tools to access protected APIs and services. ADK-TS provides authentication classes for API keys, Bearer tokens, Basic auth, and OAuth 2.0 with automatic token refresh.
Supported Auth Methods
| Method | Use Case | Token Refresh |
|---|---|---|
| API Key | Simple API access with static keys | No |
| Bearer | JWT tokens, temporary access tokens | No |
| Basic | Username/password authentication | No |
| OAuth 2.0 | User authorization flows, long-lived access | Yes |
All credentials should be stored in environment variables, never hardcoded in your source code.
Quick Start
Learn how to set up authentication for your tools using ADK-TS authentication classes.
API Key Authentication
Use API keys for simple authentication. The key is sent in a custom header with each request.
import {
ApiKeyScheme,
ApiKeyCredential,
AuthConfig,
AuthHandler,
} from "@iqai/adk";
// 1. Create authentication scheme
const apiKeyScheme = new ApiKeyScheme({
in: "header",
name: "X-API-Key",
});
// 2. Create credential from environment
const apiKeyCredential = new ApiKeyCredential(process.env.API_KEY!);
// 3. Create auth handler
const authHandler = new AuthHandler({
authConfig: new AuthConfig({ authScheme: apiKeyScheme }),
credential: apiKeyCredential,
});
// 4. Use in API requests
const response = await fetch("https://api.example.com/data", {
headers: authHandler.getHeaders(),
});Bearer Token Authentication
Use Bearer tokens for JWT-based authentication. The token is sent in the Authorization header.
import {
HttpScheme,
BearerTokenCredential,
AuthConfig,
AuthHandler,
} from "@iqai/adk";
const bearerScheme = new HttpScheme({
scheme: "bearer",
bearerFormat: "JWT",
});
const bearerCredential = new BearerTokenCredential(process.env.AUTH_TOKEN!);
const authHandler = new AuthHandler({
authConfig: new AuthConfig({ authScheme: bearerScheme }),
credential: bearerCredential,
});OAuth 2.0 with Token Refresh
OAuth 2.0 credentials support automatic token refresh:
import {
OAuth2Scheme,
OAuth2Credential,
AuthConfig,
AuthHandler,
} from "@iqai/adk";
// Define OAuth2 scheme
const oauth2Scheme = new OAuth2Scheme({
flows: {
authorizationCode: {
authorizationUrl: "https://accounts.google.com/o/oauth2/auth",
tokenUrl: "https://oauth2.googleapis.com/token",
scopes: {
"https://www.googleapis.com/auth/drive.readonly": "View files",
},
},
},
});
// Create credential with refresh function
const oauth2Credential = new OAuth2Credential({
accessToken: process.env.ACCESS_TOKEN!,
refreshToken: process.env.REFRESH_TOKEN!,
expiresIn: 3600,
refreshFunction: async (refreshToken) => {
const response = await fetch("https://oauth2.googleapis.com/token", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "refresh_token",
refresh_token: refreshToken,
client_id: process.env.CLIENT_ID!,
client_secret: process.env.CLIENT_SECRET!,
}),
});
const data = await response.json();
return {
accessToken: data.access_token,
refreshToken: data.refresh_token || refreshToken,
expiresIn: data.expires_in,
};
},
});
// Create auth handler
const authHandler = new AuthHandler({
authConfig: new AuthConfig({ authScheme: oauth2Scheme }),
credential: oauth2Credential,
});
// Token automatically refreshes when expired
if (oauth2Credential.isExpired()) {
await oauth2Credential.refresh();
}Using Authentication with Tools
Integrate authentication into your custom tools by creating an AuthHandler in the constructor and using it in your tool's runAsync method.
In Custom Tools
Create a BaseTool subclass with authentication by setting up the AuthHandler as a private property in the constructor:
import {
BaseTool,
AuthConfig,
ApiKeyScheme,
ApiKeyCredential,
AuthHandler,
ToolContext,
FunctionDeclaration,
} from "@iqai/adk";
import { Type } from "@google/genai";
class WeatherTool extends BaseTool {
private authHandler: AuthHandler;
constructor() {
super({
name: "get_weather",
description: "Get weather forecast",
});
// Set up authentication manually
const apiKeyScheme = new ApiKeyScheme({
in: "header",
name: "X-API-Key",
});
const apiKeyCredential = new ApiKeyCredential(
process.env.WEATHER_API_KEY || ""
);
this.authHandler = new AuthHandler({
authConfig: new AuthConfig({ authScheme: apiKeyScheme }),
credential: apiKeyCredential,
});
}
async runAsync(
args: Record<string, any>,
context: ToolContext
): Promise<any> {
const location = args.location as string;
try {
const response = await fetch(
`https://api.weather.com/forecast?location=${location}`,
{ headers: this.authHandler.getHeaders() }
);
if (!response.ok) {
throw new Error(`API returned status ${response.status}`);
}
return await response.json();
} catch (error) {
return `Unable to fetch weather for ${location}. Please try again later.`;
}
}
getDeclaration(): FunctionDeclaration {
return {
name: this.name,
description: this.description,
parameters: {
type: Type.OBJECT,
properties: {
location: {
type: Type.STRING,
description: "City name",
},
},
required: ["location"],
},
};
}
}In Function Tools
For function-based tools created with createTool, define the AuthHandler outside the tool and reference it in the function closure:
import {
createTool,
AuthConfig,
ApiKeyScheme,
ApiKeyCredential,
AuthHandler,
} from "@iqai/adk";
import { z } from "zod";
// Create auth handler outside the tool
const apiKeyScheme = new ApiKeyScheme({
in: "header",
name: "X-API-Key",
});
const apiKeyCredential = new ApiKeyCredential(process.env.WEATHER_API_KEY!);
const authHandler = new AuthHandler({
authConfig: new AuthConfig({ authScheme: apiKeyScheme }),
credential: apiKeyCredential,
});
// Use in tool
const weatherTool = createTool({
name: "get_weather",
description: "Get weather forecast",
schema: z.object({
location: z.string().describe("City name"),
}),
fn: async ({ location }) => {
const response = await fetch(
`https://api.weather.com/forecast?location=${location}`,
{ headers: authHandler.getHeaders() }
);
return response.json();
},
});Error Handling
Properly handle authentication errors including token refresh, 401/403 responses, and network failures:
import { AuthHandler } from "@iqai/adk";
async function callAuthenticatedApi(
endpoint: string,
authHandler: AuthHandler
) {
try {
// Refresh token if expired
if (authHandler.credential?.canRefresh()) {
await authHandler.refreshToken();
}
const response = await fetch(endpoint, {
headers: authHandler.getHeaders(),
});
// Handle auth-specific errors
if (response.status === 401) {
return { success: false, error: "Authentication failed" };
}
if (response.status === 403) {
return { success: false, error: "Insufficient permissions" };
}
if (!response.ok) {
return { success: false, error: `API error: ${response.status}` };
}
const data = await response.json();
return { success: true, data };
} catch (error) {
console.error("API call failed:", error);
return { success: false, error: "Service unavailable" };
}
}Credential Management
Manage credentials securely using environment variables and implement retry logic for resilient API calls.
Environment Variables
Validate that all required environment variables are present at application startup:
import dotenv from "dotenv";
import { ApiKeyCredential } from "@iqai/adk";
dotenv.config();
// Validate required variables
const required = ["API_KEY", "CLIENT_ID", "CLIENT_SECRET"];
const missing = required.filter((key) => !process.env[key]);
if (missing.length > 0) {
throw new Error(`Missing required env vars: ${missing.join(", ")}`);
}
// Create credentials
const apiKey = new ApiKeyCredential(process.env.API_KEY!);Retry Logic
Implement retry with exponential backoff for transient failures, but skip retries for authentication errors:
import {
ApiKeyScheme,
AuthConfig,
ApiKeyCredential,
AuthHandler,
} from "@iqai/adk";
async function withRetry<T>(
fn: () => Promise<T>,
maxRetries = 3,
initialDelay = 1000
): Promise<T> {
let lastError: Error | undefined;
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
lastError = error as Error;
// Don't retry auth failures
if (
error instanceof Error &&
error.message.includes("Authentication failed")
) {
throw error;
}
// Exponential backoff
const delay = initialDelay * Math.pow(2, attempt);
await new Promise((resolve) => setTimeout(resolve, delay));
}
}
throw lastError || new Error("Operation failed after retries");
}
// Usage
const endpoint = "https://api.example.com/data";
// Create auth handler outside the tool
const apiKeyScheme = new ApiKeyScheme({
in: "header",
name: "X-API-Key",
});
const apiKeyCredential = new ApiKeyCredential(process.env.WEATHER_API_KEY!);
const authHandler = new AuthHandler({
authConfig: new AuthConfig({ authScheme: apiKeyScheme }),
credential: apiKeyCredential,
});
const result = await withRetry(async () => {
const response = await fetch(endpoint, { headers: authHandler.getHeaders() });
if (!response.ok) throw new Error(`Failed: ${response.status}`);
return response.json();
});Security Best Practices
Follow these security guidelines to protect your credentials and ensure secure authentication:
- Store in environment variables - Never hardcode credentials
- Use HTTPS only - All authenticated requests must use HTTPS
- Implement token refresh - Refresh tokens before they expire
- Never log credentials - Don't log tokens or API keys
- Validate early - Check credentials at application startup
- Minimum permissions - Request only required scopes
- Monitor failures - Track authentication errors
- Rotate regularly - Update credentials periodically in production
Related Topics
How is this guide?