Imagine having an AI assistant that can read your emails, draft responses, and help you manage your inbox—all through natural conversation. In this comprehensive guide, you'll learn how to build exactly that using Auth0, Next.js, and LangChain.
What You'll Build
By the end of this tutorial, you'll have a fully functional AI agent that can:
- Search and retrieve emails from your Gmail inbox using natural language
- Summarize email threads and identify important messages
- Draft professional emails for you to review
- Send emails on your behalf (with your confirmation)
- Manage your inbox through conversational AI
The best part? Most of the heavy lifting is done by Auth0's Token Vault and LangChain's pre-built Gmail tools.
Prerequisites
Before we begin, make sure you have:
- A Google account (for Gmail access)
- Node.js installed (v18 or later)
- Basic knowledge of React and Next.js
- An OpenAI API key OR Google Gemini API key
- 30-45 minutes to complete the setup
🚀 Quick Start with GitHub
Want to skip ahead? Clone the complete project from GitHub:
Github Repo:https://github.com/Varshithvhegde/auth0-gmail-ai-agent
git clone https://github.com/Varshithvhegde/auth0-gmail-ai-agent.git
cd auth0-gmail-ai-agent
npm install
Then follow the configuration steps below to set up Auth0 and Google Cloud. Don't forget to create your .env.local file with all the required credentials!
Architecture Overview
Here's how the pieces fit together:
- Auth0 handles OAuth authentication and securely stores Gmail access tokens
- Next.js provides our web application framework
- LangChain connects our AI model to Gmail tools
- OpenAI/Gemini powers the intelligent conversation
Part 1: Setting Up Auth0 and Google Cloud
Step 1: Create Your Auth0 Application
First, let's set up authentication:
- Go to https://auth0.com/ai and create an account
- Navigate to Applications → Create Application
- Choose "Regular Web Applications" and click Create
- Give it a meaningful name like "Gmail AI Agent"
Step 2: Enable Gmail API in Google Cloud
Now we need to enable Gmail access:
- Visit Google Cloud Console
- Create a new project or select an existing one
- In the search bar, type "Gmail API" and click on it
- Click "Enable" to activate the API
Step 3: Configure OAuth Consent Screen
This step tells Google what your app does and who can use it:
- In the sidebar, go to APIs & Services → OAuth Consent Screen → Clients
- Click "Get Started"
- Fill in the required information:
- App name: Something descriptive like "My Gmail AI Assistant"
- Support email: Your email address
- Audience: Choose "External"
- Add contact information and click Finish and Create
Step 4: Create OAuth Credentials
Now let's connect Google to Auth0:
- Go to Clients and click "Create Client"
- Select "OAuth client" with application type "Web application"
- Choose a descriptive name
To fill in the URLs, you'll need your Auth0 domain:
- Go back to your Auth0 dashboard
- Select your application and go to Settings
- Copy your domain (e.g.,
genai-9230621065052516.au.auth0.com)
Back in Google Cloud:
-
Authorized JavaScript origins: Add
https://YOUR_AUTH0_DOMAIN -
Authorized redirect URIs: Add
https://YOUR_AUTH0_DOMAIN/login/callback
- Click Create
Important: Save the Client ID and Client Secret that appear—you'll need them next!
Step 5: Add Test Users
Since your app isn't published yet, you need to whitelist test users:
- In Google Cloud, click Audience in the sidebar
- Scroll to Test Users section
- Click "Add Users" and enter your Gmail address
- Click Save
Step 6: Configure Auth0 Social Connection
Now let's connect Auth0 to Google:
- In Auth0 dashboard, go to Authentication → Social
- Click on "google-oauth2"
- Enter the Client ID and Client Secret from Google Cloud
- Scroll to Permissions section:
- Check "Offline Access"
- Search for Gmail and select:
Gmail.ReadOnlyGmail.Compose
- Scroll further and toggle "Enable Token Vault" ON
- Click Save Changes
Step 7: Configure Application Settings
Back in your Auth0 application settings:
- Add Allowed Callback URLs:
http://localhost:3000/auth/callback - Add Allowed Logout URLs:
http://localhost:3000
- Scroll to Advanced Settings → Grant Types
- Check "Token Vault"
- Click Save Changes
Congratulations! The Auth0 and Google Cloud setup is complete.
Part 2: Building the Application
Step 8: Create Your Next.js Project
Open your terminal and run:
npx create-next-app@latest gmail-ai-agent
Use these settings when prompted:
- TypeScript: Yes
- ESLint: Yes
- Tailwind CSS: Yes
-
src/directory: Yes - App Router: Yes
- Import alias: Yes (use default
@/*)
Navigate into your project:
cd gmail-ai-agent
Step 9: Install Required Packages
Install all the dependencies we'll need:
npm install @ai-sdk/langchain @ai-sdk/react @auth0/ai-langchain @auth0/nextjs-auth0 @langchain/openai @langchain/langgraph @langchain/core @langchain/community
If you're using Google Gemini instead of OpenAI:
npm install @langchain/google-genai
Step 10: Set Up Environment Variables
Create a .env.local file in your project root:
# Generate this with: openssl rand -hex 32
AUTH0_SECRET='use [openssl rand -hex 32] to generate a 32 bytes value'
# Your application URLs
APP_BASE_URL='http://localhost:3000'
# From Auth0 Application Settings
AUTH0_DOMAIN='<your-auth0-domain>'
AUTH0_CLIENT_ID='<your-auth0-application-client-id>'
AUTH0_CLIENT_SECRET='<your-auth0-application-client-secret>'
You can get these information from the Auth0 Application Settings page:
Add your AI provider key:
# Choose ONE:
OPENAI_API_KEY='your-openai-key'
# OR
GOOGLE_API_KEY='your-gemini-key'
Step 11: Create Auth0 Configuration Files
Create the directory structure. Your initial folder structure will look like this:
Create src/lib/auth0.ts:
import { Auth0Client } from "@auth0/nextjs-auth0/server"
export const auth0 = new Auth0Client()
export const getRefreshToken = async () => {
const session = await auth0.getSession()
return session?.tokenSet?.refreshToken
}
Create src/lib/auth0-ai.ts:
import { getRefreshToken } from "@/lib/auth0"
import { Auth0AI } from "@auth0/ai-langchain"
import { getAccessTokenFromTokenVault } from "@auth0/ai-langchain"
export const getAccessToken = async () => getAccessTokenFromTokenVault()
const auth0AI = new Auth0AI()
export const withGoogleConnection = auth0AI.withTokenVault({
connection: "google-oauth2",
scopes: [
"https://www.googleapis.com/auth/gmail.readonly",
"https://www.googleapis.com/auth/gmail.compose",
],
refreshToken: getRefreshToken,
})
Step 12: Create Message Converter Utility
Create src/lib/message-converter.ts:
import { UIMessage } from "ai"
import { AIMessage, HumanMessage } from "@langchain/core/messages"
export const convertVercelMessageToLangChainMessage = (
messages: UIMessage[]
) => {
return messages.map((message) =>
message.role === "user"
? new HumanMessage(
message.parts
.map((part) => (part.type === "text" ? part.text : ""))
.join("")
)
: new AIMessage(
message.parts
.map((part) => (part.type === "text" ? part.text : ""))
.join("")
)
)
}
Step 13: Set Up Middleware
Create src/middleware.ts to handle authentication:
import { NextRequest, NextResponse } from "next/server"
import { auth0 } from "./lib/auth0"
export async function middleware(request: NextRequest) {
const authRes = await auth0.middleware(request)
// Authentication routes — let the Auth0 middleware handle it.
if (request.nextUrl.pathname.startsWith("/auth")) {
return authRes
}
const { origin } = new URL(request.url)
const session = await auth0.getSession(request)
// User does not have a session — redirect to login.
if (!session) {
return NextResponse.redirect(`${origin}/auth/login`)
}
return authRes
}
export const config = {
matcher: [
'/((?!_next/static|_next/image|favicon\\.ico|sitemap\\.xml|robots\\.txt|.*\\.(?:png|jpg|jpeg|gif|webp)|$).*)',
],
}
Part 3: Building the User Interface
Step 14: Install UI Components
We'll use shadcn/ui for beautiful, accessible components:
npx shadcn@latest init
Add the components we need:
npx shadcn@latest add button input scroll-area card
Step 15: Create the Landing Page
Replace src/app/page.tsx:
import { auth0 } from "@/lib/auth0"
import { redirect } from "next/navigation"
import { Card, CardContent } from "@/components/ui/card"
const Index = async () => {
const session = await auth0.getSession()
if (session) {
redirect("/chat")
}
return (
<div className='min-h-screen flex items-center justify-center bg-gradient-to-br from-blue-50 via-white to-purple-50'>
<div className='w-full max-w-md mx-auto px-4'>
<Card className='backdrop-blur-lg border-0 shadow-xl'>
<CardContent className='p-10 text-center'>
<h1 className='text-4xl font-bold text-gray-900 mb-4'>
Welcome to{" "}
<span className='bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent'>
AI Chat
</span>
</h1>
<p className='text-gray-600 text-lg mb-8'>
Connect your Gmail and start talking to AI instantly
</p>
<a
href='/api/auth/login'
className='block w-full font-semibold bg-gradient-to-r from-blue-600 to-purple-600 text-white hover:shadow-xl transition-all duration-300 hover:scale-[1.02] rounded-lg px-8 py-4'
>
Connect with Gmail
</a>
<p className='text-xs text-gray-500 mt-6'>
Secure authentication powered by Auth0
</p>
</CardContent>
</Card>
</div>
</div>
)
}
export default Index
Step 16: Create the Chat Interface
Create src/app/chat/page.tsx:
import { auth0 } from "@/lib/auth0"
import { redirect } from "next/navigation"
export default async function ChatPage() {
const session = await auth0.getSession()
if (!session) {
redirect("/")
}
return (
<div className='flex h-screen bg-background'>
<div className='flex-1 flex flex-col'>
{/* Header */}
<div className='border-b border-border p-4'>
<div className='flex items-center justify-between'>
<div className='flex items-center gap-3'>
<div className='w-10 h-10 bg-gradient-to-r from-blue-600 to-purple-600 rounded-xl flex items-center justify-center'>
<svg className='w-6 h-6 text-white' viewBox='0 0 24 24' fill='none'>
<path d='M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z' stroke='currentColor' strokeWidth='2' strokeLinecap='round' strokeLinejoin='round'/>
</svg>
</div>
<h2 className='text-xl font-bold'>AI Chat</h2>
</div>
<a
href='/api/auth/logout'
className='inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors bg-secondary h-10 px-4 hover:bg-secondary/80'
>
Logout
</a>
</div>
</div>
{/* Messages Area */}
<div className='flex-1 overflow-y-auto p-4'>
<div className='max-w-3xl mx-auto space-y-6'>
<div className='text-center text-muted-foreground py-8'>
Start a conversation...
</div>
</div>
</div>
{/* Input Area */}
<div className='border-t border-border p-4'>
<div className='max-w-3xl mx-auto'>
<div className='relative'>
<input
type='text'
placeholder='Type your message...'
className='w-full pr-12 py-3 px-4 rounded-lg border border-border bg-background focus:outline-none focus:ring-2 focus:ring-primary'
/>
<button className='absolute right-2 top-2 p-2 bg-primary text-white rounded-lg hover:bg-primary/90'>
<svg className='w-4 h-4' fill='none' viewBox='0 0 24 24' stroke='currentColor'>
<path strokeLinecap='round' strokeLinejoin='round' strokeWidth={2} d='M12 19l9 2-9-18-9 18 9-2zm0 0v-8' />
</svg>
</button>
</div>
<div className='text-xs text-muted-foreground mt-2 text-center'>
AI can make mistakes. Consider checking important information.
</div>
</div>
</div>
</div>
</div>
)
}
Part 4: Building the AI Backend
Step 17: Create the Chat API Route
Create src/app/api/chat/route.ts.
For OpenAI:
import { NextRequest, NextResponse } from "next/server"
import { ChatOpenAI } from "@langchain/openai"
import { createReactAgent } from "@langchain/langgraph/prebuilt"
import { SystemMessage } from "@langchain/core/messages"
import { convertVercelMessageToLangChainMessage } from "@/lib/message-converter"
import { toUIMessageStream } from "@ai-sdk/langchain"
import { createUIMessageStreamResponse } from "ai"
import {
GmailCreateDraft,
GmailSendMessage,
GmailSearch,
} from "@langchain/community/tools/gmail"
import { getAccessToken, withGoogleConnection } from "@/lib/auth0-ai"
const AGENT_SYSTEM_TEMPLATE = `You are Gmail Assistant, an intelligent AI agent that helps users manage their Gmail inbox efficiently.
Your Capabilities:
- Search and retrieve emails from Gmail based on user queries.
- Create draft emails for users to review before sending.
- Send emails on behalf of the user with their confirmation.
- Help organize, filter, and summarize email threads.
- Provide insights about important emails and follow-ups.
Your Objectives:
- Help users find specific emails quickly using natural language queries.
- Draft professional and contextually appropriate email responses.
- Summarize long email threads or multiple related emails.
- Identify important emails that need attention or follow-up.
- Assist with email management and inbox organization.
Tone & Style:
- Professional, helpful, and efficient.
- Clear and concise in communication.
- Respectful of user's privacy and email content.
- Proactive in suggesting helpful actions.
Boundaries:
- Always ask for confirmation before sending any emails.
- Never share sensitive email content without user context.
- Respect user privacy and handle email data responsibly.
- Do not make assumptions about email intent without asking.`
export async function POST(req: NextRequest) {
try {
const body = await req.json()
const { messages } = body
const llm = new ChatOpenAI({
model: "gpt-4o-mini",
})
const gmailParams = {
credentials: {
accessToken: getAccessToken,
},
}
const gmailSearch = new GmailSearch(gmailParams)
const gmailDraft = new GmailCreateDraft(gmailParams)
const gmailSend = new GmailSendMessage(gmailParams)
const agent = createReactAgent({
llm,
tools: [
withGoogleConnection(gmailSearch),
withGoogleConnection(gmailDraft),
withGoogleConnection(gmailSend),
],
messageModifier: new SystemMessage(AGENT_SYSTEM_TEMPLATE),
})
const eventStream = agent.streamEvents(
{ messages: convertVercelMessageToLangChainMessage(messages) },
{ version: "v2" }
)
return createUIMessageStreamResponse({
stream: toUIMessageStream(eventStream),
})
} catch (e: unknown) {
console.error(e)
if (e instanceof Error) {
return NextResponse.json({ error: e.message }, { status: 500 })
}
return NextResponse.json({ error: "Unexpected error" }, { status: 500 })
}
}
For Google Gemini:
Replace the OpenAI import and model initialization with:
import { ChatGoogleGenerativeAI } from "@langchain/google-genai"
// In the POST function:
const llm = new ChatGoogleGenerativeAI({
model: "gemini-2.0-flash-exp",
})
Part 5: Testing Your AI Agent
Step 18: Run Your Application
Start the development server:
npm run dev
Open your browser and navigate to http://localhost:3000
Step 19: Authenticate and Grant Permissions
- Click "Connect with Gmail" on the landing page
- You'll be redirected to Auth0's login screen
- Choose "Continue with Google"
- Select your Google account (must be a test user you added)
- Grant Gmail access permissions when prompted
- You'll be redirected back to the chat interface
Step 20: Try These Example Prompts
Now for the fun part! Try asking your AI agent:
Email Summaries:
- "Summarize my last 10 emails from the primary inbox"
- "What are my most recent unread emails?"
- "Show me emails from the last week about [topic]"
Email Search:
- "Find emails from [person's name]"
- "Search for emails containing 'invoice'"
- "Show me emails with attachments from this month"
Draft Emails:
- "Draft a thank you email to John for the meeting"
- "Create a follow-up email about the project proposal"
Send Emails:
- "Send an email to [email] saying [message]" (The AI will ask for confirmation!)
Note: Sometimes the AI might include draft, promotions, and update emails in the results. You can refine your prompts to be more specific about which category you want.
Understanding How It Works
The Flow of Data
- User Input: You type a message in the chat interface
-
API Call: The message is sent to
/api/chat/route.ts - Agent Processing: LangChain's ReAct agent analyzes your request
- Tool Selection: The agent decides which Gmail tools to use
- Auth0 Token Vault: Securely retrieves your Gmail access token
- Gmail API: Executes the requested action (search, draft, send)
- AI Response: The agent formulates a natural language response
- Stream Back: The response streams back to your chat interface
Security Features
Token Vault: Your Gmail access tokens are never exposed to your application code. Auth0 stores them securely and provides them only when needed.
OAuth Flow: All authentication follows industry-standard OAuth 2.0, ensuring Google's security requirements are met.
Scoped Access: Your app only requests the specific Gmail permissions it needs (read and compose).
Troubleshooting Common Issues
"Access blocked: This app's request is invalid"
Solution: Make sure your OAuth redirect URIs in Google Cloud match exactly with your Auth0 domain, including https://.
"Token Vault not enabled"
Solution: Double-check that you've enabled Token Vault in both the Auth0 social connection settings AND the application's advanced settings.
"Email not found in test users"
Solution: Add your Gmail address to the test users list in Google Cloud Console under OAuth Consent Screen.
API rate limits
Solution: Gmail API has rate limits. For production, implement request throttling and error handling for rate limit errors.
Deploying to Production
Prepare for Deployment
- Update Auth0 URLs: Add your production domain to allowed callback URLs
- Update Google Cloud: Add production origin and redirect URIs
- Request OAuth verification: Submit your app for Google's verification process
- Set production environment variables: Update all secrets and keys
Recommended Platforms
- Vercel: Perfect for Next.js, automatic SSL, edge functions
Next Steps
Congratulations! You've built a powerful Gmail AI agent. Here are some ideas to take it further:
- Add calendar integration to schedule meetings based on email content
- Implement smart replies that learn from your writing style
- Create email templates for common responses
- Build a browser extension for quick access
- Add voice commands using Web Speech API
- Implement email analytics to track response times and patterns
Conclusion
You've successfully created an AI-powered Gmail assistant using Auth0, Next.js, and LangChain. This project demonstrates the power of combining authentication, AI, and APIs to create practical, useful applications.
The architecture you've built here can be adapted for other services beyond Gmail—think Slack, Google Drive, Notion, or any service with an OAuth API.
Remember: The future of productivity tools is conversational AI. You're now equipped to build the next generation of smart assistants!

























Top comments (0)