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 3003

Open 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 dev

Now ask: "Show me my current portfolio"

Expected response: Your agent should now fetch and display your actual portfolio data! 🎉


How token delegation works

  1. User Authentication: User logs in through Auth0 middleware
  2. Token Exchange: getAccessTokenForConnection() securely exchanges the current credential for access to an upstream API. This step ensures access is only granted when required.
  3. Scoped Access: The API receives a token with user context and appropriate scopes
  4. Secure Calls: Agent makes authenticated requests on behalf of the user

Security benefit: No root API keys, only user-scoped tokens with limited lifetime.