Asynchronous Authorization - Auth0 Docs

Documentation Index

Fetch the complete documentation index at: /llms.txt

Use this file to discover all available pages before exploring further.

AI Identity for B2B enables AI agents to asynchronously authorize users using the Client-Initiated Backchannel Authentication Flow (CIBA). AI agents can work in the background, only notifying the user when needed for critical actions. When you add secure human-in-the-loop approvals to your AI agent workflows, you can use Auth0 to request the user’s permission to complete an authorization request. The AI agent can render rich authorization data in the consent prompt so the user knows exactly what they’re authorizing. By the end of this quickstart, you should have an AI agent integrated with the Auth0 AI SDK that can request to buy products from an online shop on the user’s behalf.

Pick your tech stack

Prerequisites

Before getting started, make sure you have completed the following steps:

  1. Create an Auth0 Account

To continue with this quickstart, you need to have an Auth0 account.

  1. Create an Auth0 Application

Go to your Auth0 Dashboard to create a new Auth0 Application.

To learn more about Auth0 applications, read Applications.

  1. Create an Auth0 API

To learn more about Auth0 APIs, read APIs.

  1. Enable CIBA Grant

Enable the CIBA Grant for your Auth0 Application. Go to Applications > [Your Application] > Settings > Advanced > Grant Types and enable the Client Initiated Backchannel Authentication (CIBA) grant type.

  1. Configure Notification Channel settings

Configure the notification channels (such as email or push notifications) for your Auth0 Application. Go to Applications > [Your Application] > Settings > Client-Initiated Backchannel Authentication (CIBA) section > and enable the notification channel(s) to use with the asynchronous authorization requests for this application. To learn more about configuring notification channels and using the requested expiry setting, read the Asynchronous Authorization documentation.

  1. Enable Guardian Push

Enable Multi-factor authentication (MFA) with Guardian Push Notifications for your Auth0 tenant. To learn more about MFA with Guardian, read the Auth0 Guardian documentation.

  1. Enroll your user to use Auth0 Guardian

To initiate a CIBA push request, the authorizing user must be enrolled in MFA using push notifications. To verify if the authorizing user is enrolled for MFA push notifications in the Auth0 Dashboard, navigate to User Management > Users and click on the user. Under Multi-Factor Authentication, Auth0 lists the factors the user is enrolled in:

If the user is not enrolled, you can send an enrollment request by email:

  1. OpenAI Platform

Set up an OpenAI account and API key.

Download sample app

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

Install dependencies

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

npm install @auth0/ai-langchain@4 @langchain/core@0.3.77 @langchain/langgraph@0.4.9 @langchain/openai@0.6.13 langchain@0.3.33 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.

Set up Human-in-the-Loop approvals

Integrate the Auth0 AI SDK into your application to secure your async AI agent workflow. For this quickstart, we will use a blocking request flow. In real use cases, often an asynchronous flow is preferred.

Configure the Auth0 AI SDK

To require asynchronous authorization for your tool, the tool needs to be wrapped with the Async authorizer, withAsyncAuthorization(). Let’s create a helper function to wrap the tool with the Async authorizer. Create a file at src/lib/auth0-ai.ts and instantiate a new Auth0 AI SDK client:

import { Auth0AI } from "@auth0/ai-langchain";
import { AccessDeniedInterrupt } from "@auth0/ai/interrupts";

const auth0AI = new Auth0AI();

// Async Authorization flow for user confirmation
export const withAsyncAuthorization = auth0AI.withAsyncAuthorization({
  userID: async (_params, config) => {
    return config.configurable?.langgraph_auth_user?.sub;
  },
  bindingMessage: async ({ product, qty }) =>
    `Do you want to buy ${qty} ${product}`,
  scopes: ["openid", "product:buy"], // add any scopes you want to use with your API
  audience: process.env["SHOP_API_AUDIENCE"]!,

onAuthorizationRequest: async (authReq, creds) => {
    console.log(`An authorization request was sent to your mobile device.`);
    await creds;
    console.log(`Thanks for approving the order.`);
  },

onUnauthorized: async (e: Error) => {
    if (e instanceof AccessDeniedInterrupt) {
      return "The user has denied the request";
    }
    return e.message;
  },
});

This will intercept the tool call to initiate a Async Authorization request:

Pass credentials to the tools

Next, add the following code to src/lib/auth0.ts:

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

// Get the Access token from Auth0 session
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;
};

Update the /src/app/api/chat/[..._path]/route.ts file with the following code. The access token will be passed to your LangGraph agent so we can use it from the Auth0 AI SDK to get the current user.

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

For more information on how to add custom authentication for your LangGraph Platform application, read the Custom Auth guide.

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

{
  "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:

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;

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

const auth = new Auth();

auth.authenticate(async (request: Request) => {
  const authHeader = request.headers.get("Authorization");
  const xApiKeyHeader = request.headers.get("x-api-key");

if (!authHeader && !xApiKeyHeader) {
    throw new HTTPException(401, {
      message: "Invalid auth header provided.",
    });
  }

let token = xApiKeyHeader || authHeader;

if (token && token.startsWith("Bearer ")) {
    token = token.substring(7);
  }

if (!token) {
    throw new HTTPException(401, {
      message: "Authorization header format must be of the form: Bearer <token>",
    });
  }

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

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

return {
        identity: payload.sub!,
        email: payload.email as string,
        permissions:
          typeof payload.scope === "string" ? payload.scope.split(" ") : [],
        auth_type: "auth0",
        getRawAccessToken: () => token,
        ...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 };

Create a tool to call your API

In this example, we use a tool that buys products on the user’s behalf. When the user approves the transaction, the Auth0 AI SDK retrieves an access token to call the shop’s API. Upon completing the Async Authorization flow, the AI agent responds with a message confirming the purchase. The Auth0 AI SDK returns an error response if the user denies the transaction. Now, create a file src/lib/tools/shop-online.ts and add the following code:

import { tool } from "@langchain/core/tools";
import { z } from "zod";

import { getAsyncAuthorizationCredentials } from "@auth0/ai-langchain";

export const shopOnlineTool = tool(
  async ({ product, qty, priceLimit }) => {
    console.log(`Ordering ${qty} ${product} with price limit ${priceLimit}`);

const apiUrl = process.env["SHOP_API_URL"]!;

if (!apiUrl) {
      return `Ordered ${qty} ${product}`;
    }

const headers = {
      "Content-Type": "application/json",
      Authorization: "",
    };
    const body = {
      product,
      qty,
      priceLimit,
    };

const credentials = getAsyncAuthorizationCredentials();
    const accessToken = credentials?.accessToken;

if (accessToken) {
      headers["Authorization"] = "Bearer " + accessToken;
    }

const response = await fetch(apiUrl, {
      method: "POST",
      headers: headers,
      body: JSON.stringify(body),
    });

return response.statusText;
  },
  {
    name: "shop_online",
    description: "Tool to buy products online",
    schema: z.object({
      product: z.string(),
      qty: z.number(),
      priceLimit: z.number().optional(),
    }),
  }
);

Update environment variables

You need to obtain an API Key from OpenAI or another provider to use an LLM. If you want to use an API, it must be registered with Auth0 and have a valid audience. Update the .env.local file with the following variables:

# ... existing variables
# You can use any provider of your choice supported by Vercel AI
OPENAI_API_KEY="YOUR_API_KEY"

# API
SHOP_API_URL=<your-shop-api-url>
SHOP_API_AUDIENCE=sample-shop-api

Require async authorization for your tool

Call the tool from your AI app to make purchases. Update the src/lib/agent.ts file with the following code:

//...
import { withAsyncAuthorization } from "./auth0-ai";
import { shopOnlineTool } from "./tools/shop-online";

const tools = [withAsyncAuthorization(shopOnlineTool)];
//...

Test the application

Start the application with npm run all:dev. Then, navigate to http://localhost:3000.

This will open the LangGraph Studio in a new tab. You can close it as we won’t require it for testing the application.

You can ask the AI agent to buy a product, for example, “Buy an XYZ phone.” Now, look for a push notification from the Auth0 Guardian app or your custom app integrated with the Auth0 Guardian SDK on your mobile device. Once you approve the notification, you should see the tool being executed and a response from the agent.

Explore the example app on GitHub.

Next steps

You have successfully added an authorization step to protect tool calling in asynchronous AI agents. For next steps: