Add Authenticated Tools to Your Agent
What we're building in this step
Secure Auth0 Token Vault flow we're adding:
- ✅ Token Vault - Secure token storage + automatic refresh (
Auth0 docs)
- ✅ Root tenant protection - API secured by DemoTradePro's main tenant
- ✅ Automatic refresh - Auth0 handles token expiry transparently
- ✅ User context - Real user identity flows through to API
- ✅ Portfolio tools -
getPortfolio&getOrderHistory
Test your current agent
Your authenticated agent can fetch public stock data but not personal portfolio info:
Bash
cd apps/agent
pnpm dev # starts on port 3003Open http://localhost:3003 and ask: "Show me my portfolio"
Current response: "I don't have access to your portfolio data..." 🤷♂️
Add Auth0 Token Vault helper
Key concept: Your agent uses Auth0's Token Vault to securely access API tokens with automatic refresh.
Add this function to your existing lib/auth0.ts:
Typescript
/**
* Helper to get access token from Auth0 Token Vault
* Exchanges user's refresh token for API access token via OIDC connection
* Auth0 automatically handles token refresh and caching
*/
export async function getAccessTokenForConnection({ connection }: { connection: string }): Promise<string | undefined> {
try {
if (!auth0.getSession()) {
return undefined;
}
const token = await auth0.getAccessTokenForConnection({ connection });
if (!token.token) {
throw new Error("Access token is not available in Auth0 Token Vault");
}
return token.token;
} catch (error) {
console.error('Failed to get stored access token:', error);
throw error;
}
}What this does:
- Token Vault access - Retrieves cached/fresh tokens from Auth0's secure vault
- Automatic refresh - Auth0 handles token expiry without user intervention
- OIDC delegation - Uses enterprise connection to root DemoTradePro tenant
- Secure storage - No tokens stored in your app, only in Auth0's vault
- Error handling - Graceful fallback if vault access unavailable
Add authenticated tools
Update your app/api/chat/tools.ts to add portfolio access:
Typescript
import { createAPIClient } from "@workspace/agent-utils";
import * as GetStockPrice from "@workspace/agent-utils/tools/get-stock-price";
// Add these imports to your existing tools.ts
import * as GetPortfolio from "@workspace/agent-utils/tools/get-portfolio";
import { getAccessTokenForConnection } from "@/lib/auth0";
// Update your API client to include token provider for authenticated calls
const apiClient = createAPIClient(process.env.API_BASE_URL!, async () => {
const token = await getAccessTokenForConnection({
connection: process.env.API_OIDC_CONNECTION_NAME!,
});
return token;
});
// Update your existing public tools to use the shared API client
export const publicStockTools = {
getStockPrice: GetStockPrice.createAISDKTool(apiClient),
} as const;
// Add authenticated tools using the same API client
export const authenticatedTools = {
getPortfolio: GetPortfolio.createAISDKTool(apiClient),
} as const;
// Update your agentTools to include authenticated tools
export const agentTools = {
...publicStockTools, // your existing public tools
...authenticatedTools, // new authenticated tools
} as const;Test authorized access
Restart your agent and test the new functionality:
Bash
pnpm devNow ask: "Show me my current portfolio"
Expected response: Your agent should now fetch and display your actual portfolio data! 🎉
How token delegation works
- User Authentication: User logs in through Auth0 middleware
- Token Exchange:
getAccessTokenForConnection()securely exchanges the current credential for access to an upstream API. This step ensures access is only granted when required. - Scoped Access: The API receives a token with user context and appropriate scopes
- Secure Calls: Agent makes authenticated requests on behalf of the user
Security benefit: No root API keys, only user-scoped tokens with limited lifetime.