Skip to content

Commit ed47b50

Browse files
authored
Merge pull request #100 from PavelKorobchuk/update-passthrough-quick-start-examples
fix: updated quick-start examples with updated langgraph-nextjs-api-passthrough usage
2 parents 1e5763c + 2c00e6e commit ed47b50

File tree

10 files changed

+701
-130
lines changed

10 files changed

+701
-130
lines changed

auth4genai/snippets/get-started/langchain-next-js/async-auth.mdx

Lines changed: 131 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Prerequisites } from "/snippets/get-started/prerequisites/async-auth.jsx";
22
import { AccountAndAppSteps } from "/snippets/get-started/prerequisites/account-app-steps.jsx";
33

4-
<Prerequisites />
4+
<Prerequisites createAuth0ApiStep={{}} />
55

66
### Prepare Next.js app
77

@@ -24,7 +24,7 @@ In the root directory of your project, install the following dependencies:
2424
- `langgraph-nextjs-api-passthrough`: API passthrough for LangGraph.
2525

2626
```bash wrap lines
27-
npm install @auth0/ai-langchain@3 @langchain/core@0.3 @langchain/langgraph@0.3 @langchain/openai@0.6 langchain@0.3 langgraph-nextjs-api-passthrough@0.1
27+
npm install @auth0/ai-langchain@3.5.0 @langchain/core@0.3.77 @langchain/langgraph@0.4.4 @langchain/openai@0.6.13 langchain@0.3.12 langgraph-nextjs-api-passthrough@0.1.4
2828
```
2929
### Update the environment file
3030

@@ -49,7 +49,7 @@ const auth0AI = new Auth0AI();
4949
// CIBA flow for user confirmation
5050
export const withAsyncAuthorization = auth0AI.withAsyncUserConfirmation({
5151
userID: async (_params, config) => {
52-
return config?.configurable?._credentials?.user?.sub;
52+
return config.configurable?.langgraph_auth_user?.sub;
5353
},
5454
bindingMessage: async ({ product, qty }) =>
5555
`Do you want to buy ${qty} ${product}`,
@@ -93,45 +93,150 @@ This will intercept the tool call to initiate a CIBA request:
9393

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

96-
```tsx src/lib/auth0.ts wrap lines highlight={2-5}
96+
```tsx src/lib/auth0.ts wrap lines highlight={12-20}
9797
//... existing code
98-
export const getUser = async () => {
99-
const session = await auth0.getSession();
100-
return session?.user;
98+
export const auth0 = new Auth0Client({
99+
authorizationParameters: {
100+
// In v4, the AUTH0_SCOPE and AUTH0_AUDIENCE environment variables are no longer automatically picked up by the SDK.
101+
// Instead, we need to provide the values explicitly.
102+
scope: process.env.AUTH0_SCOPE,
103+
audience: process.env.AUTH0_AUDIENCE,
104+
},
105+
});
106+
107+
// Get the Access token from Auth0 session
108+
export const getAccessToken = async () => {
109+
const tokenResult = await auth0.getAccessToken();
110+
111+
if(!tokenResult || !tokenResult.token) {
112+
throw new Error("No access token found in Auth0 session");
113+
}
114+
115+
return tokenResult.token;
101116
};
102117
```
103118

104-
Update the `/src/app/api/chat/[..._path]/route.ts` file with the following code. The `user` will be passed to your LangGraph agent so we can use it from the Auth0 AI SDK to get the current user.
119+
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.
105120

106-
```ts src/app/api/chat/[..._path]/route.ts wrap lines highlight={3,19}
121+
```ts src/app/api/chat/[..._path]/route.ts wrap lines highlight={3,9-13}
107122
import { initApiPassthrough } from "langgraph-nextjs-api-passthrough";
108123

109-
import { getUser } from "@/lib/auth0";
124+
import { getAccessToken } from "@/lib/auth0";
110125

111126
export const { GET, POST, PUT, PATCH, DELETE, OPTIONS, runtime } =
112127
initApiPassthrough({
113128
apiUrl: process.env.LANGGRAPH_API_URL,
114129
baseRoute: "chat/",
115-
bodyParameters: async (req, body) => {
116-
if (
117-
req.nextUrl.pathname.endsWith("/runs/stream") &&
118-
req.method === "POST"
119-
) {
130+
headers: async () => {
131+
const accessToken = await getAccessToken();
132+
return {
133+
Authorization: `Bearer ${accessToken}`,
134+
};
135+
});
136+
```
137+
138+
### Add Custom Authentication
139+
<Info>
140+
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.
141+
</Info>
142+
In your `langgraph.json`, add the path to your auth file:
143+
```typescript langgraph.json wrap lines highlight={8}
144+
{
145+
"node_version": "20",
146+
"graphs": {
147+
"agent": "./src/lib/agent.ts:agent"
148+
},
149+
"env": ".env",
150+
"auth": {
151+
"path": "./src/lib/auth.ts:authHandler"
152+
}
153+
}
154+
```
155+
Then, in your auth.ts file, add your auth logic:
156+
```typescript src/lib/auth.ts wrap lines
157+
import { createRemoteJWKSet, jwtVerify } from "jose";
158+
159+
const { Auth, HTTPException } = require("@langchain/langgraph-sdk/auth");
160+
161+
const AUTH0_DOMAIN = process.env.AUTH0_DOMAIN;
162+
const AUTH0_AUDIENCE = process.env.AUTH0_AUDIENCE;
163+
164+
// JWKS endpoint for Auth0
165+
const JWKS = createRemoteJWKSet(
166+
new URL(`https://${AUTH0_DOMAIN}/.well-known/jwks.json`)
167+
);
168+
169+
// Create the Auth instance
170+
const auth = new Auth();
171+
// Register the authentication handler
172+
auth.authenticate(async (request: Request) => {
173+
const authHeader = request.headers.get("Authorization");
174+
const xApiKeyHeader = request.headers.get("x-api-key");
175+
/**
176+
* LangGraph Platform will convert the `Authorization` header from the client to an `x-api-key` header automatically
177+
* as of now: https://docs.langchain.com/langgraph-platform/custom-auth
178+
*
179+
* We can still leverage the `Authorization` header when served in other infrastructure w/ langgraph-cli
180+
* or when running locally.
181+
*/
182+
// This header is required in Langgraph Cloud.
183+
if (!authHeader && !xApiKeyHeader) {
184+
throw new HTTPException(401, {
185+
message: "Invalid auth header provided.",
186+
});
187+
}
188+
189+
// prefer the xApiKeyHeader first
190+
let token = xApiKeyHeader || authHeader;
191+
192+
// Remove "Bearer " prefix if present
193+
if (token && token.startsWith("Bearer ")) {
194+
token = token.substring(7);
195+
}
196+
197+
// Validate Auth0 Access Token using common JWKS endpoint
198+
if (!token) {
199+
throw new HTTPException(401, {
200+
message:
201+
"Authorization header format must be of the form: Bearer <token>",
202+
});
203+
}
204+
205+
if (token) {
206+
try {
207+
// Verify the JWT using Auth0 JWKS
208+
const { payload } = await jwtVerify(token, JWKS, {
209+
issuer: `https://${AUTH0_DOMAIN}/`,
210+
audience: AUTH0_AUDIENCE,
211+
});
212+
213+
console.log("✅ Auth0 JWT payload resolved!", payload);
214+
215+
// Return the verified payload - this becomes available in graph nodes
120216
return {
121-
...body,
122-
config: {
123-
configurable: {
124-
_credentials: {
125-
user: await getUser(),
126-
},
127-
},
128-
},
217+
identity: payload.sub!,
218+
email: payload.email as string,
219+
permissions:
220+
typeof payload.scope === "string" ? payload.scope.split(" ") : [],
221+
auth_type: "auth0",
222+
// include the access token for use with Auth0 Token Vault exchanges by tools
223+
getRawAccessToken: () => token,
224+
// Add any other claims you need
225+
...payload,
129226
};
227+
} catch (jwtError) {
228+
console.log(
229+
"Auth0 JWT validation failed:",
230+
jwtError instanceof Error ? jwtError.message : "Unknown error"
231+
);
232+
throw new HTTPException(401, {
233+
message: "Invalid Authorization token provided.",
234+
});
130235
}
236+
}
237+
});
131238

132-
return body;
133-
},
134-
});
239+
export { auth as authHandler };
135240
```
136241
137242
#### Create a tool to call your API

auth4genai/snippets/get-started/langchain-next-js/auth-for-rag.mdx

Lines changed: 138 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Prerequisites } from "/snippets/get-started/prerequisites/auth-for-rag.jsx";
22
import { AccountAndAppSteps } from "/snippets/get-started/prerequisites/account-app-steps.jsx";
33

4-
<Prerequisites />
4+
<Prerequisites createAuth0ApiStep={{}} />
55

66
### Prepare Next.js app
77

@@ -25,7 +25,7 @@ In the root directory of your project, install the following dependencies:
2525
- `langgraph-nextjs-api-passthrough`: API passthrough for LangGraph.
2626

2727
```bash wrap lines
28-
npm install @auth0/ai-langchain@3 @langchain/core@0.3 @langchain/langgraph@0.3 @langchain/openai@0.6 langchain@0.3 langgraph-nextjs-api-passthrough@0.1
28+
npm install @auth0/ai-langchain@3.5.0 @langchain/core@0.3.77 @langchain/langgraph@0.4.4 @langchain/openai@0.6.13 langchain@0.3.12 langgraph-nextjs-api-passthrough@0.1.4
2929
```
3030

3131
### Update the environment file
@@ -112,10 +112,10 @@ export const getContextDocumentsTool = tool(
112112

113113
Call the tool from your AI agent to get data from documents. First, update the `/src/app/api/chat/[..._path]/route.ts` file with the following code to pass the user credentials to your agent:
114114

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

118-
import { getUser } from "@/lib/auth0";
118+
import { getUser, getAccessToken } from "@/lib/auth0";
119119

120120
export const { GET, POST, PUT, PATCH, DELETE, OPTIONS, runtime } =
121121
initApiPassthrough({
@@ -140,20 +140,151 @@ export const { GET, POST, PUT, PATCH, DELETE, OPTIONS, runtime } =
140140

141141
return body;
142142
},
143+
headers: async () => {
144+
const accessToken = await getAccessToken();
145+
return {
146+
Authorization: `Bearer ${accessToken}`,
147+
};
148+
},
143149
});
144150
```
145151

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

148-
```tsx src/lib/auth0.ts wrap lines highlight={2-5}
149-
//... existing code
154+
```tsx src/lib/auth0.ts wrap lines highlight={13-21,23-26}
155+
import { Auth0Client } from '@auth0/nextjs-auth0/server';
156+
157+
export const auth0 = new Auth0Client({
158+
authorizationParameters: {
159+
// In v4, the AUTH0_SCOPE and AUTH0_AUDIENCE environment variables are no longer automatically picked up by the SDK.
160+
// Instead, we need to provide the values explicitly.
161+
scope: process.env.AUTH0_SCOPE,
162+
audience: process.env.AUTH0_AUDIENCE,
163+
},
164+
});
165+
166+
// Get the Access token from Auth0 session
167+
export const getAccessToken = async () => {
168+
const tokenResult = await auth0.getAccessToken();
169+
170+
if(!tokenResult || !tokenResult.token) {
171+
throw new Error("No access token found in Auth0 session");
172+
}
173+
174+
return tokenResult.token;
175+
};
176+
150177
export const getUser = async () => {
151178
const session = await auth0.getSession();
152179
return session?.user;
153180
};
154181
```
155182

156-
Now, update the `/src/lib/agent.ts` file with the following code to add the tool to your agent:
183+
### Add Custom Authentication
184+
<Info>
185+
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.
186+
</Info>
187+
In your `langgraph.json`, add the path to your auth file:
188+
```typescript langgraph.json wrap lines highlight={8}
189+
{
190+
"node_version": "20",
191+
"graphs": {
192+
"agent": "./src/lib/agent.ts:agent"
193+
},
194+
"env": ".env",
195+
"auth": {
196+
"path": "./src/lib/auth.ts:authHandler"
197+
}
198+
}
199+
```
200+
Then, in your `auth.ts` file, add your auth logic:
201+
```typescript src/lib/auth.ts wrap lines
202+
import { createRemoteJWKSet, jwtVerify } from "jose";
203+
204+
const { Auth, HTTPException } = require("@langchain/langgraph-sdk/auth");
205+
206+
const AUTH0_DOMAIN = process.env.AUTH0_DOMAIN;
207+
const AUTH0_AUDIENCE = process.env.AUTH0_AUDIENCE;
208+
209+
// JWKS endpoint for Auth0
210+
const JWKS = createRemoteJWKSet(
211+
new URL(`https://${AUTH0_DOMAIN}/.well-known/jwks.json`)
212+
);
213+
214+
// Create the Auth instance
215+
const auth = new Auth();
216+
// Register the authentication handler
217+
auth.authenticate(async (request: Request) => {
218+
const authHeader = request.headers.get("Authorization");
219+
const xApiKeyHeader = request.headers.get("x-api-key");
220+
/**
221+
* LangGraph Platform will convert the `Authorization` header from the client to an `x-api-key` header automatically
222+
* as of now: https://docs.langchain.com/langgraph-platform/custom-auth
223+
*
224+
* We can still leverage the `Authorization` header when served in other infrastructure w/ langgraph-cli
225+
* or when running locally.
226+
*/
227+
// This header is required in Langgraph Cloud.
228+
if (!authHeader && !xApiKeyHeader) {
229+
throw new HTTPException(401, {
230+
message: "Invalid auth header provided.",
231+
});
232+
}
233+
234+
// prefer the xApiKeyHeader first
235+
let token = xApiKeyHeader || authHeader;
236+
237+
// Remove "Bearer " prefix if present
238+
if (token && token.startsWith("Bearer ")) {
239+
token = token.substring(7);
240+
}
241+
242+
// Validate Auth0 Access Token using common JWKS endpoint
243+
if (!token) {
244+
throw new HTTPException(401, {
245+
message:
246+
"Authorization header format must be of the form: Bearer <token>",
247+
});
248+
}
249+
250+
if (token) {
251+
try {
252+
// Verify the JWT using Auth0 JWKS
253+
const { payload } = await jwtVerify(token, JWKS, {
254+
issuer: `https://${AUTH0_DOMAIN}/`,
255+
audience: AUTH0_AUDIENCE,
256+
});
257+
258+
console.log("✅ Auth0 JWT payload resolved!", payload);
259+
260+
// Return the verified payload - this becomes available in graph nodes
261+
return {
262+
identity: payload.sub!,
263+
email: payload.email as string,
264+
permissions:
265+
typeof payload.scope === "string" ? payload.scope.split(" ") : [],
266+
auth_type: "auth0",
267+
// include the access token for use with Auth0 Token Vault exchanges by tools
268+
getRawAccessToken: () => token,
269+
// Add any other claims you need
270+
...payload,
271+
};
272+
} catch (jwtError) {
273+
console.log(
274+
"Auth0 JWT validation failed:",
275+
jwtError instanceof Error ? jwtError.message : "Unknown error"
276+
);
277+
throw new HTTPException(401, {
278+
message: "Invalid Authorization token provided.",
279+
});
280+
}
281+
}
282+
});
283+
284+
export { auth as authHandler };
285+
```
286+
287+
Now, update the `src/lib/agent.ts` file with the following code to add the tool to your agent:
157288

158289
```ts src/lib/agent.ts wrap lines highlight={1,7}
159290
import { getContextDocumentsTool } from "./tools/context-docs";

0 commit comments

Comments
 (0)