DEV Community

Cover image for Build Your Own Gmail AI Agent: A Step-by-Step Guide
Varshith V Hegde
Varshith V Hegde Subscriber

Posted on

Build Your Own Gmail AI Agent: A Step-by-Step Guide

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
Enter fullscreen mode Exit fullscreen mode

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:

  1. Auth0 handles OAuth authentication and securely stores Gmail access tokens
  2. Next.js provides our web application framework
  3. LangChain connects our AI model to Gmail tools
  4. 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:

  1. Go to https://auth0.com/ai and create an account
  2. Navigate to Applications → Create Application
  3. Choose "Regular Web Applications" and click Create
  4. Give it a meaningful name like "Gmail AI Agent"

Create Auth0 Application

Step 2: Enable Gmail API in Google Cloud

Now we need to enable Gmail access:

  1. Visit Google Cloud Console
  2. Create a new project or select an existing one

Google Cloud Project

  1. In the search bar, type "Gmail API" and click on it
  2. Click "Enable" to activate the API

Enable Gmail API

Step 3: Configure OAuth Consent Screen

This step tells Google what your app does and who can use it:

  1. In the sidebar, go to APIs & Services → OAuth Consent Screen → Clients
  2. Click "Get Started"

OAuth Consent Screen

  1. Fill in the required information:
    • App name: Something descriptive like "My Gmail AI Assistant"
    • Support email: Your email address
    • Audience: Choose "External"
  2. Add contact information and click Finish and Create

App Information

Step 4: Create OAuth Credentials

Now let's connect Google to Auth0:

  1. Go to Clients and click "Create Client"

Create Client

  1. Select "OAuth client" with application type "Web application"
  2. Choose a descriptive name

To fill in the URLs, you'll need your Auth0 domain:

  1. Go back to your Auth0 dashboard
  2. Select your application and go to Settings
  3. Copy your domain (e.g., genai-9230621065052516.au.auth0.com)

Auth0 Domain

Back in Google Cloud:

  1. Authorized JavaScript origins: Add https://YOUR_AUTH0_DOMAIN
  2. Authorized redirect URIs: Add https://YOUR_AUTH0_DOMAIN/login/callback

OAuth Client Configuration

  1. Click Create

Important: Save the Client ID and Client Secret that appear—you'll need them next!

Client Credentials

Step 5: Add Test Users

Since your app isn't published yet, you need to whitelist test users:

  1. In Google Cloud, click Audience in the sidebar
  2. Scroll to Test Users section
  3. Click "Add Users" and enter your Gmail address
  4. Click Save

Add Test Users

Step 6: Configure Auth0 Social Connection

Now let's connect Auth0 to Google:

  1. In Auth0 dashboard, go to Authentication → Social
  2. Click on "google-oauth2"

Auth0 Social Connection

  1. Enter the Client ID and Client Secret from Google Cloud

Enter Credentials

  1. Scroll to Permissions section:
    • Check "Offline Access"
    • Search for Gmail and select:
      • Gmail.ReadOnly
      • Gmail.Compose

Gmail Permissions

  1. Scroll further and toggle "Enable Token Vault" ON
  2. Click Save Changes

Enable Token Vault

Step 7: Configure Application Settings

Back in your Auth0 application settings:

  1. Add Allowed Callback URLs: http://localhost:3000/auth/callback
  2. Add Allowed Logout URLs: http://localhost:3000

Application URLs

  1. Scroll to Advanced Settings → Grant Types
  2. Check "Token Vault"
  3. Click Save Changes

Grant Types

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
Enter fullscreen mode Exit fullscreen mode

Use these settings when prompted:

Next.js Setup

  • 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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

If you're using Google Gemini instead of OpenAI:

npm install @langchain/google-genai
Enter fullscreen mode Exit fullscreen mode

Step 10: Set Up Environment Variables

Create a .env.local file in your project root:

Environment Variables

# 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>'
Enter fullscreen mode Exit fullscreen mode

You can get these information from the Auth0 Application Settings page:

Auth0 Settings

Add your AI provider key:

# Choose ONE:
OPENAI_API_KEY='your-openai-key'
# OR
GOOGLE_API_KEY='your-gemini-key'
Enter fullscreen mode Exit fullscreen mode

Step 11: Create Auth0 Configuration Files

Create the directory structure. Your initial folder structure will look like this:

Folder Structure

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
}
Enter fullscreen mode Exit fullscreen mode

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,
})
Enter fullscreen mode Exit fullscreen mode

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("")
        )
  )
}
Enter fullscreen mode Exit fullscreen mode

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)|$).*)',
  ],
}
Enter fullscreen mode Exit fullscreen mode

Part 3: Building the User Interface

Step 14: Install UI Components

We'll use shadcn/ui for beautiful, accessible components:

npx shadcn@latest init
Enter fullscreen mode Exit fullscreen mode

Add the components we need:

npx shadcn@latest add button input scroll-area card
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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>
  )
}
Enter fullscreen mode Exit fullscreen mode

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 })
  }
}
Enter fullscreen mode Exit fullscreen mode

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",
})
Enter fullscreen mode Exit fullscreen mode

Part 5: Testing Your AI Agent

Step 18: Run Your Application

Start the development server:

npm run dev
Enter fullscreen mode Exit fullscreen mode

Open your browser and navigate to http://localhost:3000

Step 19: Authenticate and Grant Permissions

  1. Click "Connect with Gmail" on the landing page

Landing Page

  1. You'll be redirected to Auth0's login screen
  2. Choose "Continue with Google"

Auth0 Login

  1. Select your Google account (must be a test user you added)
  2. Grant Gmail access permissions when prompted

Gmail Permissions

  1. You'll be redirected back to the chat interface

Chat Page

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"

Email Summary Example

  • "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

  1. User Input: You type a message in the chat interface
  2. API Call: The message is sent to /api/chat/route.ts
  3. Agent Processing: LangChain's ReAct agent analyzes your request
  4. Tool Selection: The agent decides which Gmail tools to use
  5. Auth0 Token Vault: Securely retrieves your Gmail access token
  6. Gmail API: Executes the requested action (search, draft, send)
  7. AI Response: The agent formulates a natural language response
  8. 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

  1. Update Auth0 URLs: Add your production domain to allowed callback URLs
  2. Update Google Cloud: Add production origin and redirect URIs
  3. Request OAuth verification: Submit your app for Google's verification process
  4. 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:

  1. Add calendar integration to schedule meetings based on email content
  2. Implement smart replies that learn from your writing style
  3. Create email templates for common responses
  4. Build a browser extension for quick access
  5. Add voice commands using Web Speech API
  6. 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!

Resources

Top comments (0)