Prerequisites
Before getting started, make sure you have completed the following steps:
Create an Auth0 Application
Go to your
Auth0 Dashboard to create a new Auth0 Application.
- Navigate to Applications > Applications in the left sidebar.
- Click the Create Application button in the top right.
- In the pop-up select Regular Web Applications and click Create.
- Once the Application is created, switch to the Settings tab.
- Scroll down to the Application URIs section.
- Set Allowed Callback URLs as:
http://localhost:3000/auth/callback - Set Allowed Logout URLs as:
http://localhost:3000 - Click Save in the bottom right to save your changes.
To learn more about Auth0 applications, read
Applications.
Enable Token Exchange Grant
Enable the Token Exchange Grant for your Auth0 Application. Go to Applications > [Your Application] > Settings > Advanced > Grant Types and enable the Token Exchange grant type.
Configure Google Social Integration
Set up a Google developer account that allows for third-party API calls by following the
Google Social Integration instructions.
Prepare Next.js app
Recommended: To use a starter template, clone the Auth0 AI samples repository:git clone https://github.com/auth0-samples/auth0-ai-samples.git
cd auth0-ai-samples/authenticate-users/langchain-next-js
Install dependencies
In the root directory of your project, install the following dependencies:
@auth0/ai-langchain: Auth0 AI SDK for LangChain built for GenAI applications powered by LangChain.
@langchain/langgraph: For building stateful, multi-actor applications with LLMs.
langchain: The LangChain library.
@langchain/core: LangChain core libraries.
@langchain/openai: OpenAI provider for LangChain.
@langchain/community: LangChain community integrations.
langgraph-nextjs-api-passthrough: API passthrough for LangGraph.
npm install @auth0/ai-langchain@3 @langchain/community@0.3 @langchain/core@0.3 @langchain/langgraph@0.3 @langchain/openai@0.6 langchain@0.3 langgraph-nextjs-api-passthrough@0.1
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.Get access tokens for others APIs
Use the Auth0 AI SDK for LangChain to get access tokens for third-party APIs.Set up Token Vault for Google social connection
Set up the Auth0 AI SDK for a Google Social Connection. This allows you to get access tokens for a Google social connection using Token Vault:
connection: pass in the name of the connection you want the user to sign up for/log into.
scopes: pass in the scopes for the service you want to get access to.
Create a file at src/lib/auth0-ai.ts and instantiate a new Auth0 AI SDK client:import { Auth0AI, getAccessTokenForConnection } from "@auth0/ai-langchain";
// Get the access token for a connection via Auth0
export const getAccessToken = async () => getAccessTokenForConnection();
const auth0AI = new Auth0AI();
// Connection for Google services
export const withGoogleConnection = auth0AI.withTokenForConnection({
connection: "google-oauth2",
scopes: ["https://www.googleapis.com/auth/gmail.readonly"],
});
Update the /src/lib/auth0.ts file with the following code://...
//... existing code
// Get the refresh token from Auth0 session
export const getRefreshToken = async () => {
const session = await auth0.getSession();
return session?.tokenSet?.refreshToken;
};
Update the /src/app/api/chat/[..._path]/route.ts file with the following code. The refreshToken will be passed to your LangGraph agent so we can use it from the Auth0 AI SDK to get Google access tokens from the server.src/app/api/chat/[..._path]/route.ts
import { initApiPassthrough } from "langgraph-nextjs-api-passthrough";
import { getRefreshToken } from "@/lib/auth0";
export const { GET, POST, PUT, PATCH, DELETE, OPTIONS, runtime } =
initApiPassthrough({
apiUrl: process.env.LANGGRAPH_API_URL,
baseRoute: "chat/",
bodyParameters: async (req, body) => {
if (
req.nextUrl.pathname.endsWith("/runs/stream") &&
req.method === "POST"
) {
return {
...body,
config: {
configurable: {
_credentials: {
refreshToken: await getRefreshToken(),
},
},
},
};
}
return body;
},
});
Once the user is authenticated, you can fetch an access token from the Token Vault using the Auth0 AI SDK. In this example, we fetch an access token for a Google social connection. Once you’ve obtained the access token for a connection, you can use it with an AI agent to fetch data during a tool call and provide contextual data in its response.In this example, we will use the GmailSearch from the @langchain/community tools. This tool will use the access token provided by Token Vault to query for emails.//...
import { GmailSearch } from "@langchain/community/tools/gmail";
import { getAccessToken, withGoogleConnection } from "./auth0-ai";
//... existing code
// Provide the access token to the Gmail tools
const gmailParams = {
credentials: {
accessToken: getAccessToken,
},
};
const tools = [
//... existing tools
withGoogleConnection(new GmailSearch(gmailParams)),
];
//... existing code
export const agent = createReactAgent({
llm,
tools: new ToolNode(tools, {
// Error handler must be disabled in order to trigger interruptions from within tools.
handleToolErrors: false,
}),
// Modify the stock prompt in the prebuilt agent.
prompt: AGENT_SYSTEM_TEMPLATE,
store,
checkpointer,
});
You need to obtain an API Key from OpenAI or another provider to use an LLM. Add the API key to your environment variables:# ...
# You can use any provider of your choice supported by Vercel AI
OPENAI_API_KEY="YOUR_API_KEY"
Add step-up authorization
When you try to use the tool, the application requests any additional Google scopes that are required but not yet authorized. This process is called step-up authorization.Let us implement step-up authorization.Install the Auth0 AI Components for Next.js to get the required UI components:npx @auth0/ai-components add FederatedConnections
Add a new file, src/components/auth0-ai/FederatedConnections/FederatedConnectionInterruptHandler.tsx, with the following code:src/components/auth0-ai/FederatedConnections/FederatedConnectionInterruptHandler.tsx
import { FederatedConnectionInterrupt } from "@auth0/ai/interrupts";
import type { Interrupt } from "@langchain/langgraph-sdk";
import { EnsureAPIAccess } from "@/components/auth0-ai/FederatedConnections";
interface FederatedConnectionInterruptHandlerProps {
interrupt: Interrupt | undefined | null;
onFinish: () => void;
}
export function FederatedConnectionInterruptHandler({
interrupt,
onFinish,
}: FederatedConnectionInterruptHandlerProps) {
if (
!interrupt ||
!FederatedConnectionInterrupt.isInterrupt(interrupt.value)
) {
return null;
}
return (
<div key={interrupt.ns?.join("")} className="whitespace-pre-wrap">
<EnsureAPIAccess
mode="popup"
interrupt={interrupt.value}
onFinish={onFinish}
connectWidget={{
title: "Authorization Required.",
description: interrupt.value.message,
action: { label: "Authorize" },
}}
/>
</div>
);
}
Now, update the src/components/chat-window.tsx file to include the FederatedConnectionInterruptHandler component:src/components/chat-window.tsx
//...
import { FederatedConnectionInterruptHandler } from '@/components/auth0-ai/FederatedConnections/FederatedConnectionInterruptHandler';
//... existing code
export function ChatWindow(props: {
//... existing code
}) {
const [threadId, setThreadId] = useQueryState('threadId');
const [input, setInput] = useState('');
const chat = useStream({
apiUrl: props.endpoint,
assistantId: 'agent',
threadId,
onThreadId: setThreadId,
onError: (e: any) => {
console.error('Error: ', e);
toast.error(`Error while processing your request`, { description: e.message });
},
});
//... existing code
return (
<StickToBottom>
<StickyToBottomContent
className="absolute inset-0"
contentClassName="py-8 px-2"
content={
chat.messages.length === 0 ? (
<div>{props.emptyStateComponent}</div>
) : (
<>
<ChatMessages
aiEmoji={props.emoji}
messages={chat.messages}
emptyStateComponent={props.emptyStateComponent}
/>
<div className="flex flex-col max-w-[768px] mx-auto pb-12 w-full">
<FederatedConnectionInterruptHandler interrupt={chat.interrupt} onFinish={() => chat.submit(null)} />
</div>
</>
)
}
{/* ... existing code */}
></StickyToBottomContent>
</StickToBottom>
);
}
Test your 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.
If you are already logged in, make sure to log out and log back in using Google. Then, ask your AI Agent to fetch emails from your Gmail account!That’s it! You successfully integrated integrated third-party API access using Token Vault into your project.Explore the example app on GitHub.Prerequisites
Before getting started, make sure you have completed the following steps:
Create an Auth0 Application
Go to your
Auth0 Dashboard to create a new Auth0 Application.
- Navigate to Applications > Applications in the left sidebar.
- Click the Create Application button in the top right.
- In the pop-up select Regular Web Applications and click Create.
- Once the Application is created, switch to the Settings tab.
- Scroll down to the Application URIs section.
- Set Allowed Callback URLs as:
http://localhost:8000/api/auth/callback - Set Allowed Logout URLs as:
http://localhost:5173 - Click Save in the bottom right to save your changes.
To learn more about Auth0 applications, read
Applications.
Enable Token Exchange Grant
Enable the Token Exchange Grant for your Auth0 Application. Go to Applications > [Your Application] > Settings > Advanced > Grant Types and enable the Token Exchange grant type.
Configure Google Social Integration
Set up a Google developer account that allows for third-party API calls by following the
Google Social Integration instructions.
Prepare the FastAPI app
Recommended: Use the starter template by cloning the Auth0 AI samples repository:git clone https://github.com/auth0-samples/auth0-ai-samples.git
cd auth0-ai-samples/authenticate-users/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:
auth0-ai-langchain: Auth0 AI SDK for LangChain built for GenAI applications powered by LangChain.
langgraph: 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.
google-api-python-client: Google API client library for Python.
Make sure you have uv installed and run the following command to install the dependencies:cd backend
uv sync
uv add "auth0-ai-langchain>=1.0.0b3" "langgraph>=0.5.4" langchain-openai "langgraph-cli[inmem]" google-api-python-client --prerelease=allow
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.Get access tokens for other’s APIs
Use the Auth0 AI SDK for LangChain to get access tokens for third-party APIs.Set up Token Vault for Google social connection
Set up the Auth0 AI SDK for a Google social connection. This allows you to get access tokens for a Google social connection using Token Vault:
connection: pass in the name of the connection you want the user to sign up for/log into.
scopes: pass in the scopes for the service you want to get access to.
Create a file at app/core/auth0_ai.py and instantiate a new Auth0 AI SDK client:from auth0_ai.authorizers.types import Auth0ClientParams
from auth0_ai_langchain.auth0_ai import Auth0AI
from langchain_core.runnables import ensure_config
from app.core.config import settings
auth0_ai = Auth0AI(
Auth0ClientParams(
{
"domain": settings.AUTH0_DOMAIN,
"client_id": settings.AUTH0_CLIENT_ID,
"client_secret": settings.AUTH0_CLIENT_SECRET,
}
)
)
with_calendar_access = auth0_ai.with_federated_connection(
connection="google-oauth2",
scopes=["https://www.googleapis.com/auth/calendar.events"],
)
Pass credentials to the agent
Update the API route to pass the user session data including federated tokens to the agent in app/api/routes/chat.py:# ...
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": {
"refresh_token": auth_session.get("refresh_token"),
}
}
}
body = json.dumps(content).encode("utf-8")
# ... existing code
Once the user is authenticated, you can fetch an access token from the Token Vault using the Auth0 AI SDK. In this example, we fetch an access token for a Google social connection. Once you’ve obtained the access token for a connection, you can use it with an AI agent to fetch data during a tool call and provide contextual data in its response.In this step, you’ll create a LangChain tool that uses a federated connection to access third-party APIs.Create a Google Calendar tool in app/agents/tools/google_calendar.py:app/agents/tools/google_calendar.py
from langchain_core.tools import StructuredTool
from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
from pydantic import BaseModel
from auth0_ai_langchain.federated_connections import (
get_access_token_for_connection,
)
import datetime
import json
from app.core.auth0_ai import with_calendar_access
async def list_upcoming_events_fn():
"""List upcoming events from the user's Google Calendar"""
google_access_token = get_access_token_for_connection()
if not google_access_token:
raise ValueError(
"Authorization required to access the Federated Connection API"
)
calendar_service = build(
"calendar",
"v3",
credentials=Credentials(google_access_token),
)
events = (
calendar_service.events()
.list(
calendarId="primary",
timeMin=datetime.datetime.now().isoformat() + "Z",
timeMax=(datetime.datetime.now() + datetime.timedelta(days=7)).isoformat()
+ "Z",
maxResults=5,
singleEvents=True,
orderBy="startTime",
)
.execute()
.get("items", [])
)
return json.dumps(
[
{
"summary": event["summary"],
"start": event["start"].get("dateTime", event["start"].get("date")),
}
for event in events
]
)
list_upcoming_events = with_calendar_access(
StructuredTool(
name="list_upcoming_events",
description="List upcoming events from the user's Google Calendar",
args_schema=BaseModel,
coroutine=list_upcoming_events_fn,
)
)
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.# ...
from app.agents.tools.google_calendar import list_upcoming_events
tools = [list_upcoming_events]
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 to obtain an API Key from OpenAI or another provider to use an LLM. Add the API key to your environment variables:# ...
# You can use any provider of your choice supported by Vercel AI
OPENAI_API_KEY="YOUR_API_KEY"
Add step-up authorization
When you try to use the tool, the application requests any additional Google scopes that are required but not yet authorized. This process is called step-up authorization.Let us implement step-up authorization.Install the required dependencies and the Auth0 AI Components for React to get the required UI components:cd frontend
npm install @auth0/ai @langchain/langgraph-sdk
npx @auth0/ai-components add FederatedConnections
Add a new file, src/components/auth0-ai/FederatedConnections/FederatedConnectionInterruptHandler.tsx, with the following code:src/components/auth0-ai/FederatedConnections/FederatedConnectionInterruptHandler.tsx
import { FederatedConnectionInterrupt } from "@auth0/ai/interrupts";
import type { Interrupt } from "@langchain/langgraph-sdk";
import { EnsureAPIAccess } from "@/components/auth0-ai/FederatedConnections";
interface FederatedConnectionInterruptHandlerProps {
interrupt: Interrupt | undefined | null;
onFinish: () => void;
auth?: {
authorizePath?: string;
returnTo?: string;
};
}
export function FederatedConnectionInterruptHandler({
interrupt,
onFinish,
auth,
}: FederatedConnectionInterruptHandlerProps) {
if (
!interrupt ||
!FederatedConnectionInterrupt.isInterrupt(interrupt.value)
) {
return null;
}
return (
<div key={interrupt.ns?.join("")} className="whitespace-pre-wrap">
<EnsureAPIAccess
mode="popup"
interrupt={interrupt.value}
onFinish={onFinish}
auth={auth}
connectWidget={{
title: "Authorization Required.",
description: interrupt.value.message,
action: { label: "Authorize" },
}}
/>
</div>
);
}
Now, update the src/components/chat-window.tsx file to include the FederatedConnectionInterruptHandler component:src/components/chat-window.tsx
//...
import { FederatedConnectionInterruptHandler } from '@/components/auth0-ai/FederatedConnections/FederatedConnectionInterruptHandler';
import { getLoginUrl } from "@/lib/use-auth";
//... existing code
export function ChatWindow(props: {
//... existing code
}) {
//... existing code
return (
<StickToBottom>
<StickyToBottomContent
className="absolute inset-0"
contentClassName="py-8 px-2"
content={
chat.messages.length === 0 ? (
<div>{props.emptyStateComponent}</div>
) : (
<>
<ChatMessages
aiEmoji={props.emoji}
messages={chat.messages}
emptyStateComponent={props.emptyStateComponent}
/>
<div className="flex flex-col max-w-[768px] mx-auto pb-12 w-full">
{!!chat.interrupt?.value && (
<FederatedConnectionInterruptHandler
auth={{
authorizePath: getLoginUrl(),
returnTo: new URL(
"/close",
window.location.origin
).toString(),
}}
interrupt={{
...chat.interrupt,
value: {
...chat.interrupt.value,
requiredScopes:
(
chat.interrupt.value as {
required_scopes: [string];
}
).required_scopes || [],
},
}}
onFinish={() => chat.submit(null)}
/>
)}
</div>
</>
)
}
{/* ... existing code */}
></StickyToBottomContent>
</StickToBottom>
);
}
Test your application
To test the application, start the FastAPI backend, LangGraph server, and the frontend:
- In a new terminal, start the FastAPI backend:
cd backend
source .venv/bin/activate
fastapi dev app/main.py
- In another terminal, start the LangGraph server:
cd backend
source .venv/bin/activate
uv pip install -U langgraph-api
langgraph dev --port 54367 --allow-blocking
This will open the LangGraph Studio in a new tab. You can close it as we won’t
require it for testing the application.
- In another terminal, start the frontend:
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. If you are already logged in, make sure to log out and log back in using Google. Then, ask your AI Agent to list the upcoming events in your Google Calendar!That’s it! You’ve successfully integrated third-party API access using Token Vault into your LangGraph FastAPI project.Explore the example app on GitHub.