Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 131 additions & 26 deletions auth4genai/snippets/get-started/langchain-next-js/async-auth.mdx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Prerequisites } from "/snippets/get-started/prerequisites/async-auth.jsx";
import { AccountAndAppSteps } from "/snippets/get-started/prerequisites/account-app-steps.jsx";

<Prerequisites />
<Prerequisites createAuth0ApiStep={{}} />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is API needed? I thought its only required for the calling other API one. @priley86 can you confirm?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from my standpoint, yes... we are passing user information potentially across the network, and referencing it with regards to buying a product. We should try to validate the source of the requestor and that proper authorization is in place for the API.


### Prepare Next.js app

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

```bash wrap lines
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
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
```
### Update the environment file

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

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

```tsx src/lib/auth0.ts wrap lines highlight={2-5}
```tsx src/lib/auth0.ts wrap lines highlight={12-20}
//... existing code
export const getUser = async () => {
const session = await auth0.getSession();
return session?.user;
export const auth0 = new Auth0Client({
authorizationParameters: {
// In v4, the AUTH0_SCOPE and AUTH0_AUDIENCE environment variables are no longer automatically picked up by the SDK.
// Instead, we need to provide the values explicitly.
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 `user` will be passed to your LangGraph agent so we can use it from the Auth0 AI SDK to get the current user.
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.

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

import { getUser } from "@/lib/auth0";
import { getAccessToken } 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"
) {
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}
{
"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
import { createRemoteJWKSet, jwtVerify } from "jose";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are the dependencoes needed for this available in a new app (try deleting node_modules, install again and test)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added these packages in this PR


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 {
...body,
config: {
configurable: {
_credentials: {
user: await getUser(),
},
},
},
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.",
});
}
}
});

return body;
},
});
export { auth as authHandler };
```

#### Create a tool to call your API
Expand Down
145 changes: 138 additions & 7 deletions auth4genai/snippets/get-started/langchain-next-js/auth-for-rag.mdx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Prerequisites } from "/snippets/get-started/prerequisites/auth-for-rag.jsx";
import { AccountAndAppSteps } from "/snippets/get-started/prerequisites/account-app-steps.jsx";

<Prerequisites />
<Prerequisites createAuth0ApiStep={{}} />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this needed??


### Prepare Next.js app

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

```bash wrap lines
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
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
```

### Update the environment file
Expand Down Expand Up @@ -112,10 +112,10 @@ export const getContextDocumentsTool = tool(

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:

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

import { getUser } from "@/lib/auth0";
import { getUser, getAccessToken } from "@/lib/auth0";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i dont see a point of updating the rag quickstart as this change is not required for this quiclkstart to work at all. Its ok to update the sample app as good practice but I think the quickstart need not be updated. I'll leave the decision to you @KarimTantawy5

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As in access token is not used in the RAG tool so adding all this in this quickstart doesnt serve any purpose.


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

return body;
},
headers: async () => {
const accessToken = await getAccessToken();
return {
Authorization: `Bearer ${accessToken}`,
};
},
});
```

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

```tsx src/lib/auth0.ts wrap lines highlight={2-5}
//... existing code
```tsx src/lib/auth0.ts wrap lines highlight={13-21,23-26}
import { Auth0Client } from '@auth0/nextjs-auth0/server';

export const auth0 = new Auth0Client({
authorizationParameters: {
// In v4, the AUTH0_SCOPE and AUTH0_AUDIENCE environment variables are no longer automatically picked up by the SDK.
// Instead, we need to provide the values explicitly.
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;
};

export const getUser = async () => {
const session = await auth0.getSession();
return session?.user;
};
```

Now, update the `/src/lib/agent.ts` file with the following code to add the tool to your agent:
### 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}
{
"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
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 };
```

Now, update the `src/lib/agent.ts` file with the following code to add the tool to your agent:

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