> ## Documentation Index
> Fetch the complete documentation index at: https://auth0.com/ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Call Your APIs on Users' Behalf

> Learn how Auth0 for AI Agents enables AI agents to call first-party APIs on the user's behalf.

export const DownloadQuickstartButton = ({category, framework, label = "Download Sample"}) => {
  const [isDownloading, setIsDownloading] = useState(false);
  const githubRepo = 'auth0-samples/auth0-ai-samples';
  const filename = `${category}-${framework}-sample.zip`;
  const downloadSample = () => {
    setIsDownloading(true);
    const downloadUrl = `https://github.com/${githubRepo}/releases/latest/download/${filename}`;
    window.open(downloadUrl, '_blank');
    setTimeout(() => setIsDownloading(false), 1000);
  };
  return <div className="download-button-container">
      <button onClick={downloadSample} disabled={isDownloading} className={`download-button ${isDownloading ? 'downloading' : ''}`} aria-label={`Download ${category} ${framework} sample code`}>
        {isDownloading ? <>
            <svg className="download-spinner" width="16" height="16" viewBox="0 0 24 24" fill="none">
              <circle cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="2" fill="none" strokeDasharray="31.416" strokeDashoffset="31.416">
                <animate attributeName="stroke-dasharray" dur="2s" values="0 31.416;15.708 15.708;0 31.416" repeatCount="indefinite" />
                <animate attributeName="stroke-dashoffset" dur="2s" values="0;-15.708;-31.416" repeatCount="indefinite" />
              </circle>
            </svg>
            Downloading...
          </> : <>
            <Icon icon="download" color="white" />
            {label}
          </>}
      </button>
    </div>;
};

export const AccountAndAppSteps = ({applicationType = "Regular Web Applications", callbackUrl = "http://localhost:3000/auth/callback", logoutUrl = "http://localhost:3000", appCreation = true, allowedWebOrigins, copyDomain, enableTokenVaultGrant = false, enableRefreshTokenGrant = false, enableAllowRefreshTokenRotation = undefined}) => {
  const steps = [<Step title="Create an Auth0 Account">
      To continue with this quickstart, you need to have an{" "}
      <a href="https://auth0.com/signup?onboard_app=auth_for_aa&amp;ocid=701KZ000000cXXxYAM-aPA4z0000008OZeGAM" target="_blank">
        Auth0 account.
      </a>
    </Step>];
  if (appCreation) {
    steps.push(<Step title="Create an Auth0 Application">
        Go to your{" "}
        <a href="https://manage.auth0.com/dashboard" target="_blank">
          Auth0 Dashboard
        </a>{" "}
        to create a new Auth0 Application.
        <ul>
          <li>
            Navigate to <a href="https://manage.auth0.com/#/applications" target="_blank"><strong>Applications {">"} Applications</strong></a> in the
            left sidebar.
          </li>
          <li>
            Click the <strong>Create Application</strong> button in the top
            right.
          </li>
          <li>
            In the pop-up select <strong>{applicationType}</strong> and click{" "}
            <strong>Create</strong>.
          </li>
          <li>
            Once the Application is created, switch to the{" "}
            <strong>Settings</strong> tab.
          </li>
          {copyDomain && <li>
              Copy the <strong>Domain</strong> from the{" "}
              <strong>Basic Information</strong> section to your clipboard.
            </li>}
          <li>
            Scroll down to the <strong>Application URIs</strong> section.
          </li>
          <li>
            Set Allowed Callback URLs as: <code>{callbackUrl}</code>
          </li>
          {logoutUrl && <li>
              Set Allowed Logout URLs as: <code>{logoutUrl}</code>
            </li>}
          {allowedWebOrigins && <li>
              Set Allowed Web Origins as: <code>{allowedWebOrigins}</code>
            </li>}
          {enableAllowRefreshTokenRotation !== undefined && <li>
              Scroll down to the <strong>Refresh Token Rotation</strong> section and {enableAllowRefreshTokenRotation === true ? "enable" : "disable"} the <strong>Allow Refresh Token Rotation</strong> option.
            </li>}
          {enableTokenVaultGrant && !enableRefreshTokenGrant && <li>
              Scroll down and expand the <strong>Advanced</strong> section. Switch to the <strong>Grant Types</strong> tab and enable the <strong>Token Vault</strong> grant type.
            </li>}
          {enableTokenVaultGrant && enableRefreshTokenGrant && <li>
              Scroll down and expand the <strong>Advanced</strong> section. Switch to the <strong>Grant Types</strong> tab and enable the <strong>Token Vault</strong> and <strong>Refresh Token</strong> grant types.
            </li>}
          <li>
            Click <strong>Save</strong> in the bottom right to save your
            changes.
          </li>
        </ul>
        To learn more about Auth0 applications, read{" "}
        <a href="https://auth0.com/docs/get-started/applications" target="_blank">
          Applications
        </a>
        .
      </Step>);
  }
  return steps;
};

export const Prerequisites = ({callbackUrl = "http://localhost:3000/auth/callback", logoutUrl = "http://localhost:3000", createAuth0ApiStep = undefined}) => {
  const steps = AccountAndAppSteps({
    callbackUrl,
    logoutUrl
  });
  if (createAuth0ApiStep) {
    steps.push(<Step key="auth0-api" title="Create an Auth0 API">
        <ul>
          <li>
            In your Auth0 Dashboard, go to{" "}
            <strong>Applications &gt; APIs</strong>.
          </li>
          <li>Create a new API with an identifier (audience).</li>
          <li>
            Once API is created, go to the APIs{" "}
            <strong>Settings &gt; Access Settings</strong> and enable{" "}
            <strong>Allow Offline Access</strong>.
          </li>
          <li>Note down the API identifier for your environment variables.</li>
        </ul>
        To learn more about Auth0 APIs, read{" "}
        <a href="https://auth0.com/docs/get-started/auth0-overview/set-up-apis" target="_blank">
          APIs
        </a>
        .
      </Step>);
  }
  steps.push(<Step title="OpenAI Platform">
      Set up an{" "}
      <a href="https://platform.openai.com/docs/libraries#create-and-export-an-api-key" target="_blank">
        OpenAI account and API key
      </a>
      .
    </Step>);
  return <>
      <Heading level={3} id="prerequisites">
        Prerequisites
      </Heading>
      Before getting started, make sure you have completed the following steps:
      <Steps>{steps}</Steps>
    </>;
};

Let your AI agent call your APIs on behalf of the authenticated user using access tokens securely issued by Auth0. Your API can be any [API that you have configured in Auth0](https://auth0.com/docs/get-started/apis).

By the end of this quickstart, you should have an AI application integrated with Auth0 that can:

* Get an Auth0 access token.
* Use the Auth0 access token to make a tool call to your API endpoint, in this case, Auth0's `/userinfo` endpoint.
* Return the data to the user via an AI agent.

## Pick your tech stack

<Tabs>
  <Tab title="LangGraph.js + Next.js" icon="https://mintlify-assets.b-cdn.net/auth0/langchain.svg">
    <Prerequisites createAuth0ApiStep={{}} />

    ### Download sample app

    Start by downloading and extracting the sample app. Then open in your preferred IDE.

    <DownloadQuickstartButton category="authenticate-users" framework="langchain-next-js" />

    ### Install dependencies

    In the root directory of your project, install the following dependencies:

    * `@langchain/langgraph`: The core [LangGraph](https://js.langchain.com/docs/langgraph) module.
    * `@langchain/openai`: [OpenAI](https://js.langchain.com/docs/integrations/chat/openai) provider for LangChain.
    * `langchain`: The core [LangChain](https://js.langchain.com) module.
    * `zod`: TypeScript-first schema validation library.
    * `langgraph-nextjs-api-passthrough`: API passthrough for LangGraph.

    ```bash wrap lines theme={null}
    npm install @langchain/langgraph@0.4.4 @langchain/openai@0.6 langchain@0.3 zod@3 langgraph-nextjs-api-passthrough@0.1.4
    ```

    ### Update the environment file

    Copy the `.env.example` file to `.env.local` and update the variables with your Auth0 credentials. You can find your Auth0 domain, client ID, and client secret in the application you created in the Auth0 Dashboard.

    ### Pass credentials to the agent

    You have to pass the access token from the user's session to the agent. First, create a helper function to get the access token from the session. Add the following function to `src/lib/auth0.ts`:

    ```ts src/lib/auth0.ts wrap lines highlight={11} theme={null}
    import { Auth0Client } from '@auth0/nextjs-auth0/server';

    export const auth0 = new Auth0Client({
      authorizationParameters: {
        scope: process.env.AUTH0_SCOPE,
        audience: process.env.AUTH0_AUDIENCE,
      },
    });

    export const getAccessToken = async () => {
      const tokenResult = await auth0.getAccessToken();

      if(!tokenResult || !tokenResult.token) {
        throw new Error("No access token found in Auth0 session");
      }

      return tokenResult.token;
    };
    ```

    Now, update the `/src/app/api/chat/[..._path]/route.ts` file to pass the access token to the agent:

    ```ts src/app/api/chat/[..._path]/route.ts wrap lines highlight={3,19} theme={null}
    import { initApiPassthrough } from "langgraph-nextjs-api-passthrough";

    import { getAccessToken } from "@/lib/auth0";

    export const { GET, POST, PUT, PATCH, DELETE, OPTIONS, runtime } =
      initApiPassthrough({
        apiUrl: process.env.LANGGRAPH_API_URL,
        baseRoute: "chat/",
        headers: async () => {
          const accessToken = await getAccessToken();
          return {
            Authorization: `Bearer ${accessToken}`,
          };
      });
    ```

    ### Add Custom Authentication

    <Info>
      For more information on how to add custom authentication for your LangGraph Platform application, read the [Custom Auth](https://langchain-ai.github.io/langgraphjs/how-tos/auth/custom_auth/) guide.
    </Info>

    In your `langgraph.json`, add the path to your auth file:

    ```typescript langgraph.json wrap lines highlight={8} theme={null}
    {
      "node_version": "20",
      "graphs": {
        "agent": "./src/lib/agent.ts:agent"
      },
      "env": ".env",
      "auth": {
        "path": "./src/lib/auth.ts:authHandler"
      }
    }
    ```

    Then, in your `auth.ts` file, add your auth logic:

    ```typescript src/lib/auth.ts wrap lines theme={null}
    import { createRemoteJWKSet, jwtVerify } from "jose";

    const { Auth, HTTPException } = require("@langchain/langgraph-sdk/auth");

    const AUTH0_DOMAIN = process.env.AUTH0_DOMAIN;
    const AUTH0_AUDIENCE = process.env.AUTH0_AUDIENCE;

    // JWKS endpoint for Auth0
    const JWKS = createRemoteJWKSet(
      new URL(`https://${AUTH0_DOMAIN}/.well-known/jwks.json`)
    );

    // Create the Auth instance
    const auth = new Auth();
    // Register the authentication handler
    auth.authenticate(async (request: Request) => {
      const authHeader = request.headers.get("Authorization");
      const xApiKeyHeader = request.headers.get("x-api-key");
        /**
         * LangGraph Platform will convert the `Authorization` header from the client to an `x-api-key` header automatically
         * as of now: https://docs.langchain.com/langgraph-platform/custom-auth
         *
         * We can still leverage the `Authorization` header when served in other infrastructure w/ langgraph-cli
         * or when running locally.
         */
        // This header is required in Langgraph Cloud.
        if (!authHeader && !xApiKeyHeader) {
          throw new HTTPException(401, {
            message: "Invalid auth header provided.",
          });
        }

        // prefer the xApiKeyHeader first
        let token = xApiKeyHeader || authHeader;

        // Remove "Bearer " prefix if present
        if (token && token.startsWith("Bearer ")) {
          token = token.substring(7);
        }

        // Validate Auth0 Access Token using common JWKS endpoint
        if (!token) {
          throw new HTTPException(401, {
            message:
              "Authorization header format must be of the form: Bearer <token>",
          });
        }

        if (token) {
          try {
            // Verify the JWT using Auth0 JWKS
            const { payload } = await jwtVerify(token, JWKS, {
              issuer: `https://${AUTH0_DOMAIN}/`,
              audience: AUTH0_AUDIENCE,
            });

            console.log("✅ Auth0 JWT payload resolved!", payload);

            // Return the verified payload - this becomes available in graph nodes
            return {
              identity: payload.sub!,
              email: payload.email as string,
              permissions:
                typeof payload.scope === "string" ? payload.scope.split(" ") : [],
              auth_type: "auth0",
              // include the access token for use with Auth0 Token Vault exchanges by tools
              getRawAccessToken: () => token,
              // Add any other claims you need
              ...payload,
            };
          } catch (jwtError) {
            console.log(
              "Auth0 JWT validation failed:",
              jwtError instanceof Error ? jwtError.message : "Unknown error"
            );
            throw new HTTPException(401, {
              message: "Invalid Authorization token provided.",
            });
          }
        }
    });

    export { auth as authHandler };
    ```

    ### Define a tool to call your API

    In this step, you'll create a LangChain tool to make the first-party API call. The tool fetches an access token to call the API.

    In this example, after taking in an Auth0 access token during user login, the tool returns the user profile of the currently logged-in user by calling the [/userinfo](https://auth0.com/docs/api/authentication/user-profile/get-user-info) endpoint.

    ```ts src/lib/tools/user-info.ts wrap lines highlight={6} theme={null}
    import { tool } from "@langchain/core/tools";

    export const getUserInfoTool = tool(
      async (_input, config?) => {
        // Access credentials from config
        const accessToken = config?.configurable?.langgraph_auth_user?.getRawAccessToken();
        if (!accessToken) {
          return "There is no user logged in.";
        }

        const response = await fetch(
          `https://${process.env.AUTH0_DOMAIN}/userinfo`,
          {
            headers: {
              Authorization: `Bearer ${accessToken}`,
            },
          }
        );

        if (response.ok) {
          return { result: await response.json() };
        }

        return "I couldn't verify your identity";
      },
      {
        name: "get_user_info",
        description: "Get information about the current logged in user.",
      }
    );
    ```

    ### Add the tool to the AI agent

    The AI agent processes and runs the user's request through the AI pipeline, including the tool call. Update the `src/lib/agent.ts` file to add the tool to the agent.

    ```ts src/lib/agent.ts wrap lines highlight={2,8} theme={null}
    //...
    import { getUserInfoTool } from "./tools/user-info";

    //... existing code

    const tools = [
      //... existing tools
      getUserInfoTool,
    ];

    //... existing code
    ```

    You need an API Key from OpenAI or another provider to use an LLM. Add that API key to your `.env.local` file:

    ```bash .env.local wrap lines theme={null}
    # ...
    # You can use any provider of your choice supported by Vercel AI
    OPENAI_API_KEY="YOUR_API_KEY"
    ```

    If you use another provider for your LLM, adjust the variable name in `.env.local` accordingly.

    ### Test your application

    To test the application, run `npm run all:dev` and navigate to `http://localhost:3000`.

    <Note>
      This will open the LangGraph Studio in a new tab. You can close it as we won't
      require it for testing the application.
    </Note>

    To interact with the AI agent, you can ask questions like `"who am I?"` to trigger the tool call and test whether it successfully retrieves information about the logged-in user.

    ```bash wrap lines theme={null}
    User: who am I?
    AI: It seems that there is no user currently logged in. If you need assistance with anything else, feel free to ask!

    User: who am I?
    AI: You are Deepu Sasidharan. Here are your details: - .........
    ```

    That's it! You've successfully integrated first-party tool-calling into your project.

    Explore [the example app on GitHub](https://github.com/auth0-samples/auth0-ai-samples/tree/main/call-apis-on-users-behalf/your-api/langchain-next-js).
  </Tab>

  <Tab title="Vercel AI + Next.js" icon="https://mintlify-assets.b-cdn.net/auth0/vercel.svg">
    <Prerequisites />

    ### Download sample app

    Start by downloading and extracting the sample app. Then open in your preferred IDE.

    <DownloadQuickstartButton category="authenticate-users" framework="vercel-ai-next-js" />

    ### Install dependencies

    In the root directory of your project, install the following dependencies:

    * `ai`: Core [Vercel AI SDK](https://sdk.vercel.ai/docs) module that interacts with various AI model providers.
    * `@ai-sdk/openai`: [OpenAI](https://sdk.vercel.ai/providers/ai-sdk-providers/openai) provider for the Vercel AI SDK.
    * `@ai-sdk/react`: [React](https://react.dev/) UI components for the Vercel AI SDK.
    * `zod`: TypeScript-first schema validation library.

    ```bash wrap lines theme={null}
    npm install ai@6 @ai-sdk/openai@3 @ai-sdk/react@3 zod@3.25.76
    ```

    ### Update the environment file

    Copy the `.env.example` file to `.env.local` and update the variables with your Auth0 credentials. You can find your Auth0 domain, client ID, and client secret in the application you created in the Auth0 Dashboard.

    ### Define a tool to call your API

    In this step, you'll create a Vercel AI tool to make the first-party API call. The tool fetches an access token to call the API.

    In this example, after taking in an Auth0 access token during user login, the tool returns the user profile of the currently logged-in user by calling the [/userinfo](https://auth0.com/docs/api/authentication/user-profile/get-user-info) endpoint.

    ```ts src/lib/tools/user-info.ts wrap lines theme={null}
    import { tool } from "ai";
    import { z } from "zod";

    import { auth0 } from "../auth0";

    export const getUserInfoTool = tool({
      description: "Get information about the current logged in user.",
      inputSchema: z.object({}),
      execute: async () => {
        const session = await auth0.getSession();
        if (!session) {
          return "There is no user logged in.";
        }

        const response = await fetch(
          `https://${process.env.AUTH0_DOMAIN}/userinfo`,
          {
            headers: {
              Authorization: `Bearer ${session.tokenSet.accessToken}`,
            },
          }
        );

        if (response.ok) {
          return { result: await response.json() };
        }

        return "I couldn't verify your identity";
      },
    });
    ```

    ### Add the tool to the AI agent

    The AI agent processes and runs the user's request through the AI pipeline, including the tool call. Vercel AI simplifies this task with the `streamText()` method. Update the `/src/app/api/chat/route.ts` file with the following code:

    ```ts src/app/api/chat/route.ts wrap lines highlight={2,11-13,23} theme={null}
    //...
    import { getUserInfoTool } from "@/lib/tools/user-info";

    //... existing code

    export async function POST(req: NextRequest) {
      const { id, messages }: { id: string; messages: Array<UIMessage> } = await req.json();

      setAIContext({ threadID: id });

      const tools = {
        getUserInfoTool,
      };

      const stream = createUIMessageStream({
        originalMessages: messages,
        execute: async ({ writer }) => {
          const result = streamText({
            model: openai('gpt-4o-mini'),
            system: AGENT_SYSTEM_TEMPLATE,
            messages: await convertToModelMessages(messages),
            stopWhen: stepCountIs(5),
            tools,
          });

          writer.merge(
            result.toUIMessageStream({
              sendReasoning: true,
            })
          );
        },
        onError: (err: any) => {
          console.log(err);
          return `An error occurred! ${err.message}`;
        },
      });

      return createUIMessageStreamResponse({ stream });
    }
    //... existing code
    ```

    You need an API Key from OpenAI or another provider to use an LLM. Add that API key to your `.env.local` file:

    ```bash .env.local wrap lines theme={null}
    # ...
    # You can use any provider of your choice supported by Vercel AI
    OPENAI_API_KEY="YOUR_API_KEY"
    ```

    If you use another provider for your LLM, adjust the variable name in `.env.local` accordingly.

    ### Test your application

    To test the application, run `npm run dev` and navigate to `http://localhost:3000`. To interact with the AI agent, you can ask questions like `"who am I?"` to trigger the tool call and test whether it successfully retrieves information about the logged-in user.

    ```bash wrap lines theme={null}
    User: who am I?
    AI: It seems that there is no user currently logged in. If you need assistance with anything else, feel free to ask!

    User: who am I?
    AI: You are Deepu Sasidharan. Here are your details: - .........
    ```

    That's it! You've successfully integrated first-party tool-calling into your project.

    Explore [the example app on GitHub](https://github.com/auth0-samples/auth0-ai-samples/tree/main/call-apis-on-users-behalf/your-api/vercel-ai-next-js).
  </Tab>

  <Tab title="LangGraph + FastAPI" icon="https://mintlify-assets.b-cdn.net/auth0/langchain.svg">
    <Prerequisites callbackUrl="http://localhost:8000/api/auth/callback" logoutUrl="http://localhost:5173" />

    ### Download sample app

    Start by downloading and extracting the sample app. Then open in your preferred IDE.

    <DownloadQuickstartButton category="authenticate-users" framework="langchain-fastapi-py" />

    The project is divided into two parts:

    * `backend/`: contains the backend code for the Web app and API written in Python using FastAPI and the LangGraph agent.
    * `frontend/`: contains the frontend code for the Web app written in React as a Vite SPA.

    ### Install dependencies

    In the `backend` directory of your project, install the following dependencies:

    * `langgraph`: [LangGraph](https://pypi.org/project/langgraph/) for building stateful, multi-actor applications with LLMs.
    * `langchain-openai`: LangChain integrations for OpenAI.
    * `langgraph-cli`: LangGraph CLI for running a local LangGraph server.

    Make sure you have [uv](https://docs.astral.sh/uv/) installed and run the following command to install the dependencies:

    ```bash wrap lines theme={null}
    cd backend
    uv sync
    uv add langgraph langchain-openai "langgraph-cli[inmem]"
    ```

    ### Update the environment file

    Copy the `.env.example` file to `.env` and update the variables with your Auth0 credentials. You can find your Auth0 domain, client ID, and client secret in the application you created in the Auth0 Dashboard.

    ### Pass credentials to the agent

    First, you have to pass the access token from the user's session to the agent. The FastAPI backend will proxy requests to the LangGraph server with the user's credentials.

    Update the API route to pass the access token to the agent in `app/api/routes/chat.py`:

    ```python app/api/routes/chat.py wrap lines highlight={2,9,21-23} theme={null}
    # ...
    from app.core.auth import auth_client
    # ...

    @agent_router.api_route(
        "/{full_path:path}", methods=["GET", "POST", "DELETE", "PATCH", "PUT", "OPTIONS"]
    )
    async def api_route(
        request: Request, full_path: str, auth_session=Depends(auth_client.require_session)
    ):
        try:
            # ... existing code

            # Prepare body
            body = await request.body()
            if request.method in ("POST", "PUT", "PATCH") and body:
                content = await request.json()
                content["config"] = {
                    "configurable": {
                        "_credentials": {
                            "access_token": auth_session.get("token_sets")[0].get(
                                "access_token"
                            ),
                        }
                    }
                }
                body = json.dumps(content).encode("utf-8")

                # ... existing code
    ```

    ### Define a tool to call your API

    In this step, you'll create a LangChain tool to make the first-party API call. The tool fetches an access token to call the API.

    In this example, after taking in an Auth0 access token during user login, the tool returns the user profile of the currently logged-in user by calling the [/userinfo](https://auth0.com/docs/api/authentication/user-profile/get-user-info) endpoint.

    Create a user info tool in `app/agents/tools/user_info.py`:

    ```python app/agents/tools/user_info.py wrap lines theme={null}
    import httpx
    from langchain_core.tools import StructuredTool
    from langchain_core.runnables.config import RunnableConfig
    from pydantic import BaseModel

    from app.core.config import settings


    class UserInfoSchema(BaseModel):
        pass


    async def get_user_info_fn(config: RunnableConfig):
        """Get information about the current logged in user from Auth0 /userinfo endpoint."""

        # Access credentials from config
        if "configurable" not in config or "_credentials" not in config["configurable"]:
            return "There is no user logged in."

        credentials = config["configurable"]["_credentials"]
        access_token = credentials.get("access_token")

        if not access_token:
            return "There is no user logged in."

        try:
            async with httpx.AsyncClient() as client:
                response = await client.get(
                    f"https://{settings.AUTH0_DOMAIN}/userinfo",
                    headers={
                        "Authorization": f"Bearer {access_token}",
                    },
                )

                if response.status_code == 200:
                    user_info = response.json()
                    return f"User information: {user_info}"
                else:
                    return "I couldn't verify your identity"

        except Exception as e:
            return f"Error getting user info: {str(e)}"


    get_user_info = StructuredTool(
        name="get_user_info",
        description="Get information about the current logged in user.",
        args_schema=UserInfoSchema,
        coroutine=get_user_info_fn,
    )
    ```

    ### Add the tool to the AI agent

    The AI agent processes and runs the user's request through the AI pipeline, including the tool call. Update the `app/agents/assistant0.py` file to add the tool to the agent:

    ```python app/agents/assistant0.py wrap lines highlight={2,4} theme={null}
    # ...
    from app.agents.tools.user_info import get_user_info

    tools = [get_user_info]

    llm = ChatOpenAI(model="gpt-4.1-mini")

    # ... existing code
    agent = create_react_agent(
        llm,
        tools=ToolNode(tools, handle_tool_errors=False),
        prompt=get_prompt(),
    )
    ```

    You need an API Key from OpenAI to use the LLM. Add that API key to your `.env` file:

    ```bash .env wrap lines theme={null}
    # ...
    OPENAI_API_KEY="YOUR_API_KEY"
    ```

    If you use another provider for your LLM, adjust the variable name in `.env` accordingly.

    ### Test your application

    To test the application, start the FastAPI backend, LangGraph server, and the frontend:

    1. In a new terminal, start the FastAPI backend:

    ```bash wrap lines theme={null}
    cd backend
    source .venv/bin/activate
    fastapi dev app/main.py
    ```

    2. In another terminal, start the LangGraph server:

    ```bash wrap lines theme={null}
    cd backend
    source .venv/bin/activate
    uv pip install -U langgraph-api
    langgraph dev --port 54367 --allow-blocking
    ```

    <Note>
      This will open the LangGraph Studio in a new tab. You can close it as we won't
      require it for testing the application.
    </Note>

    3. In another terminal, start the frontend:

    ```bash wrap lines theme={null}
    cd frontend
    cp .env.example .env # Copy the `.env.example` file to `.env`.
    npm install
    npm run dev
    ```

    Visit the URL `http://localhost:5173` in your browser and interact with the AI agent. You can ask questions like `"who am I?"` to trigger the tool call and test whether it successfully retrieves information about the logged-in user.

    ```bash wrap lines theme={null}
    User: who am I?
    AI: It seems that there is no user currently logged in. If you need assistance with anything else, feel free to ask!

    User: who am I?
    AI: You are Deepu Sasidharan. Here are your details: - .........
    ```

    That's it! You've successfully integrated first-party tool-calling into your LangGraph FastAPI project.

    Explore [the example app on GitHub](https://github.com/auth0-samples/auth0-ai-samples/tree/main/call-apis-on-users-behalf/your-api/langchain-fastapi-py).
  </Tab>

  <Tab title="Cloudflare Agents" icon="cloudflare">
    <Prerequisites />

    ### Start from our Cloudflare Agents template

    Our [Auth0 Cloudflare Agents Starter Kit](https://github.com/auth0-lab/cloudflare-agents-starter) provides a starter project that includes the necessary dependencies and configuration to get you up and running quickly.

    To create a new Cloudflare Agents project using the template, run the following command in your terminal:

    ```bash wrap lines theme={null}
    npx create-cloudflare@latest --template auth0-lab/cloudflare-agents-starter
    ```

    ### About the dependencies

    The start kit is similar to the [Cloudflare Agents starter kit](https://github.com/cloudflare/agents-starter) but includes the following dependencies to integrate with Auth0 and Vercel AI:

    * `hono`: [Hono](https://hono.dev/) Web Application framework.
    * `@auth0/auth0-hono`: [Auth0 SDK](https://github.com/auth0-lab/auth0-hono) for the Hono web framework.
    * `hono-agents`: [Hono Agents](https://github.com/cloudflare/agents/tree/main/packages/hono-agents) to add intelligent, stateful AI agents to your Hono app.
    * `@auth0/auth0-cloudflare-agents-api`: [Auth0 Cloudflare Agents API SDK](https://github.com/auth0-lab/auth0-cloudflare-agents-api) to secure Cloudflare Agents using bearer tokens from Auth0.
    * `@auth0/ai`: [Auth0 AI SDK](https://github.com/auth0/auth0-ai-js) to provide base abstractions for authentication and authorization in AI applications.
    * `@auth0/ai-vercel`: [Auth0 Vercel AI SDK](https://github.com/auth0/auth0-ai-js/tree/main/packages/ai-vercel) to provide building blocks for using Auth0 for AI Agents with the Vercel AI SDK.
    * `@auth0/ai-cloudflare`: [Auth0 Cloudflare AI SDK](https://github.com/auth0/auth0-ai-js/tree/main/packages/ai-cloudflare) to provide building blocks for using Auth0 for AI Agents with the Cloudflare Agents API.

    **You don't need to install these dependencies manually**; they are already included in the starter kit.

    ```bash wrap lines theme={null}
    npm remove agents
    npm install hono \
      @auth0/auth0-hono \
      hono-agents \
      @auth0/auth0-cloudflare-agents-api \
      @auth0/ai-cloudflare \
      @auth0/ai-vercel \
      @auth0/ai
    ```

    ### Set up environment variables

    In the root directory of your project, copy the `.dev.vars.example` into `.dev.vars` file and configure the Auth0 and OpenAI variables.

    ```bash .dev.vars wrap lines theme={null}
    # ...
    # You can use any provider of your choice supported by Vercel AI
    OPENAI_API_KEY="OPENAI API KEY"

    #auth0
    AUTH0_DOMAIN="YOUR-ACCOUNT.us.auth0.com"
    AUTH0_CLIENT_ID="YOUR CLIENT ID"
    AUTH0_CLIENT_SECRET="YOUR CLIENT SECRET"
    AUTH0_SESSION_ENCRYPTION_KEY="RANDOM 32 CHARS"
    AUTH0_AUDIENCE="YOUR AUDIENCE"

    BASE_URL="http://localhost:3000"
    ```

    If you use another provider for your LLM, adjust the variable name in `.dev.vars` accordingly.

    #### Configure a persistent store

    For persisting Auth0 session data and other key-value pairs, you need to configure a persistent store with your Cloudflare agent worker. When constructing the `CloudflareKVStore` instance with your Cloudflare agent worker, you can use Workers KV and a [KV namespace](https://developers.cloudflare.com/kv/get-started/) as the persistent store. This enables you to store Auth0 session data and other key-value pairs with easy access from your Cloudflare agent workers.

    ```ts theme={null}
    import { CloudflareKVStore } from '@auth0/ai-cloudflare';
    ...

    return new CloudflareKVStore({ kv: this.env.YOUR_KV_NAMESPACE });
    ```

    **Note:** the `kv` prop accepts any store which implements the [`KVNamespace` interface](https://github.com/auth0/auth0-ai-js/blob/%40auth0/ai-cloudflare-v2.0.0/packages/ai-cloudflare/src/CloudflareKVStore.ts#L3-L14), so any persistent store which implements this interface will work.

    ### Define a tool to call your API

    In this step, you'll create a Vercel AI tool to make the first-party API call to the Auth0 API. You will do the same for third-party APIs.

    After taking in an Auth0 access token during user login, the Cloudflare Worker sends the token to the Cloudflare Agent using the Authorization header in every web request or WebSocket connection.

    Since the Agent defined in the class Chat in `src/agent/chat.ts` uses the **AuthAgent** trait from the `@auth0/auth0-cloudflare-agents-api` it validates the signature of the token and that it matches the audience of the Agent.

    The tool we are defining here uses the same access token to call Auth0's [`/userinfo`](https://auth0.com/docs/api/authentication/user-profile/get-user-info) endpoint.

    ```tsx src/agent/tools.ts wrap lines theme={null}
    /**
     * Tool definitions for the AI chat agent
     * Tools can either require human confirmation or execute automatically
     */
    import { tool } from "ai";
    import { z } from "zod";

    import { getCurrentAgent } from "agents";
    import { unstable_scheduleSchema } from "agents/schedule";
    import { format, toZonedTime } from "date-fns-tz";
    import { buyStock } from "./auth0-ai-sample-tools/buy-stock";
    import { checkUsersCalendar } from "./auth0-ai-sample-tools/check-user-calendar";

    /**
     * Weather information tool that requires human confirmation
     * When invoked, this will present a confirmation dialog to the user
     * The actual implementation is in the executions object below
     */
    const getWeatherInformation = tool({
      description: "show the weather in a given city to the user",
      inputSchema: z.object({ city: z.string() }),
    });

    /**
     * Local time tool that executes automatically
     * Since it includes an execute function, it will run without user confirmation
     * This is suitable for low-risk operations that don't need oversight
     */
    const getLocalTime = tool({
      description: "get the local time for a specified location",
      inputSchema: z.object({
        timeZone: z.string().describe("IANA time zone name"),
      }),
      execute: async ({ timeZone: location }) => {
        const now = new Date();
        const zonedDate = toZonedTime(now, location);
        const output = format(zonedDate, "yyyy-MM-dd HH:mm:ssXXX", {
          timeZone: location,
        });
        return output;
      },
    });

    const scheduleTask = tool({
      description: "A tool to schedule a task to be executed at a later time",
      inputSchema: unstable_scheduleSchema,
      execute: async ({ when, description }) => {
        const { agent } = getCurrentAgent();

        function throwError(msg: string): string {
          throw new Error(msg);
        }
        if (when.type === "no-schedule") {
          return "Not a valid schedule input";
        }
        const input =
          when.type === "scheduled"
            ? when.date // scheduled
            : when.type === "delayed"
              ? when.delayInSeconds // delayed
              : when.type === "cron"
                ? when.cron // cron
                : throwError("not a valid schedule input");
        try {
          agent!.schedule(input!, "executeTask" as keyof typeof agent, description);
        } catch (error) {
          console.error("error scheduling task", error);
          return `Error scheduling task: ${error}`;
        }
        return `Task scheduled for type "${when.type}" : ${input}`;
      },
    });

    /**
     * Tool to list all scheduled tasks
     * This executes automatically without requiring human confirmation
     */
    const getScheduledTasks = tool({
      description: "List all tasks that have been scheduled",
      inputSchema: z.object({}),
      execute: async () => {
        const { agent } = getCurrentAgent();

        try {
          const tasks = agent!.getSchedules();
          if (!tasks || tasks.length === 0) {
            return "No scheduled tasks found.";
          }
          return tasks;
        } catch (error) {
          console.error("Error listing scheduled tasks", error);
          return `Error listing scheduled tasks: ${error}`;
        }
      },
    });

    /**
     * Tool to cancel a scheduled task by its ID
     * This executes automatically without requiring human confirmation
     */
    const cancelScheduledTask = tool({
      description: "Cancel a scheduled task using its ID",
      inputSchema: z.object({
        taskId: z.string().describe("The ID of the task to cancel"),
      }),
      execute: async ({ taskId }) => {
        const { agent } = getCurrentAgent();
        try {
          await agent!.cancelSchedule(taskId);
          return `Task ${taskId} has been successfully canceled.`;
        } catch (error) {
          console.error("Error canceling scheduled task", error);
          return `Error canceling task ${taskId}: ${error}`;
        }
      },
    });

    /**
     * Export all available tools
     * These will be provided to the AI model to describe available capabilities
     */
    export const tools = {
      getWeatherInformation,
      getLocalTime,
      scheduleTask,
      getScheduledTasks,
      cancelScheduledTask,
      checkUsersCalendar,
      buyStock,
    };

    /**
     * Implementation of confirmation-required tools
     * This object contains the actual logic for tools that need human approval
     * Each function here corresponds to a tool above that doesn't have an execute function
     */
    export const executions = {
      getWeatherInformation: async ({ city }: { city: string }) => {
        console.log(`Getting weather information for ${city}`);
        return `The weather in ${city} is sunny`;
      },
    };
    ```

    Then in the `tools` export of the `src/agent/chat.ts` file, add the `tools` to the `allTools` array:

    ```tsx src/agent/chat.ts wrap lines theme={null}
    async onChatMessage() {
        const allTools = {
          ...tools,
          ...(this.mcp?.getAITools?.() ?? {}),
        };
        ... // The rest of the code
    ```

    ### Test your application

    To test the application, run `npm run start` and navigate to `http://localhost:3000/` and interact with the AI agent. You can ask questions like `“who am I?”` to trigger the tool call and test whether it successfully retrieves information about the logged-in user.

    ```bash wrap lines theme={null}
    User: who am I?
    AI: It seems that there is no user currently logged in. If you need assistance with anything else, feel free to ask!

    User: who am I?
    AI: You are Juan Martinez. Here are your details: - .........
    ```

    That's it! You've successfully integrated first-party tool-calling into your project.

    Explore [the starter kit on GitHub](https://github.com/auth0-lab/cloudflare-agents-starter).
  </Tab>
</Tabs>

## Next steps

* [Call your APIs on user's behalf docs](/intro/call-your-apis-on-users-behalf).
* To set up third-party tool calling, complete the
  [Call other's APIs on user's behalf](../get-started/call-others-apis-on-users-behalf) quickstart.
* To explore the Auth0 Next.js SDK, see the
  [GitHub repo](https://github.com/auth0/nextjs-auth0).
