DEV Community

Cover image for AgentFlow: Autonomous AI Agents with Secure OAuth Integration via Auth0 Token Vault
Abhi nandan
Abhi nandan

Posted on • Edited on

AgentFlow: Autonomous AI Agents with Secure OAuth Integration via Auth0 Token Vault

Auth0 for AI Agents Challenge Submission

This is a submission for the Auth0 for AI Agents Challenge

What I Built

AgentFlow is a comprehensive AI agent platform that enables users to create, manage, and deploy autonomous AI agents that can interact with their connected services (Gmail, Slack, Google Calendar, etc.) on their behalf. The platform solves the critical problem of secure credential management for AI agents while providing a beautiful, intuitive interface for agent creation and monitoring.

Key Features:

🤖 Multi-Template Agent Builder

  1. Pre-configured templates (Email Assistant, Calendar Manager, Social Media Manager)
  2. Custom agent creation with flexible service selection
  3. Visual workflow configuration

🔐 Secure OAuth Integration

  1. Auth0-powered authentication for users
  2. Token Vault for secure credential storage
  3. Service-specific permission scopes
  4. Encrypted token storage in DynamoDB

📊 Real-Time Agent Dashboard

  1. Live activity feed showing agent actions
  2. Performance metrics and analytics
  3. Success rate tracking
  4. Time-saving calculations

⚡ Agent Management

  1. Pause/Resume agents with one click
  2. Delete agents with confirmation
  3. View detailed activity logs
  4. Monitor connected services

🔗 Multi-Service Integration

  1. Gmail (read, send, categorize emails)
  2. Slack (post messages, notifications)
  3. Google Calendar (event management)
  4. Extensible architecture for more services

Demo

Live Demo: https://main.d13aenlm5qrdln.amplifyapp.com
GitHub Repository: https://github.com/Abhinandangithub01/AgentFlow

How I Used Auth0 for AI Agents

Auth0 was absolutely critical to solving the core security challenge of AgentFlow. Here's how I leveraged Auth0's capabilities:

  1. User Authentication (Auth0 SDK)
// Next.js App Router integration
import { handleAuth, handleLogin, handleCallback } from '@auth0/nextjs-auth0';

export const GET = handleAuth({
  login: handleLogin({
    returnTo: '/dashboard'
  }),
  callback: handleCallback({
    redirectUri: process.env.AUTH0_BASE_URL + '/api/auth/callback'
  })
});
Enter fullscreen mode Exit fullscreen mode

Why this matters: Every user action is authenticated, ensuring only authorized users can create and manage agents.

  1. Token Vault for Secure Credential Storage The game-changer was implementing Auth0's Token Vault pattern for storing OAuth tokens:
// lib/token-vault.ts
export class TokenVaultService {
  async storeOAuthToken(
    userId: string,
    service: string,
    tokens: SecureToken,
    agentId?: string
  ): Promise<TokenVaultEntry> {
    const vaultKey = this.generateVaultKey(userId, service, agentId);

    // Store in DynamoDB with encryption
    await DynamoDBService.put(TABLES.TOKENS, {
      PK: `TOKEN#${vaultKey}`,
      SK: 'METADATA',
      accessToken: tokens.accessToken,
      refreshToken: tokens.refreshToken,
      expiresIn: tokens.expiresIn,
      tokenType: tokens.tokenType,
      scope: tokens.scope,
      createdAt: new Date().toISOString(),
      updatedAt: new Date().toISOString(),
    });

    return entry;
  }

  async getOAuthToken(
    userId: string,
    service: string,
    agentId?: string
  ): Promise<SecureToken | null> {
    const vaultKey = this.generateVaultKey(userId, service, agentId);
    const item = await DynamoDBService.get(TABLES.TOKENS, {
      PK: `TOKEN#${vaultKey}`,
      SK: 'METADATA',
    });

    return item ? {
      accessToken: item.accessToken,
      refreshToken: item.refreshToken,
      expiresIn: item.expiresIn,
      tokenType: item.tokenType,
      scope: item.scope,
    } : null;
  }
}
Enter fullscreen mode Exit fullscreen mode

Security Benefits:

✅ Tokens never exposed to client-side code
✅ Encrypted at rest in DynamoDB (AWS AES-256)
✅ Scoped to specific user + service + agent combinations
✅ Automatic token refresh handling
✅ Secure revocation on agent deletion

  1. OAuth Flow for Service Connections
// app/api/auth/gmail/callback/route.ts
export async function GET(request: NextRequest) {
  const session = await getSession();
  if (!session?.user) {
    return NextResponse.redirect(new URL('/?error=no_session', request.url));
  }

  const code = searchParams.get('code');

  // Exchange code for tokens
  const oauth2Client = new google.auth.OAuth2(
    process.env.GOOGLE_CLIENT_ID,
    process.env.GOOGLE_CLIENT_SECRET,
    redirectUri
  );

  const { tokens } = await oauth2Client.getToken(code);

  // Store in Token Vault (Auth0 pattern)
  await tokenVault.storeOAuthToken(
    session.user.sub,
    'gmail',
    {
      accessToken: tokens.access_token,
      refreshToken: tokens.refresh_token,
      expiresIn: tokens.expiry_date ? 
        Math.floor((tokens.expiry_date - Date.now()) / 1000) : 3600,
      tokenType: 'Bearer',
      scope: tokens.scope || '',
    }
  );

  // Store connection record
  await DynamoDBService.put(TABLES.CONNECTIONS, {
    PK: `USER#${session.user.sub}`,
    SK: 'SERVICE#gmail',
    service: 'gmail',
    status: 'connected',
    scopes: tokens.scope?.split(' ') || [],
    connectedAt: new Date().toISOString(),
  });

  return NextResponse.redirect(new URL('/integrations', request.url));
}
Enter fullscreen mode Exit fullscreen mode
  1. Agent-Specific Token Access Each agent gets its own scoped access to tokens:
// When agent needs to access Gmail
const agent = await agentManager.getAgent(agentId, userId);
const gmailToken = await tokenVault.getOAuthToken(
  userId,
  'gmail',
  agentId  // Agent-specific token
);

// Use token to perform action
const gmail = google.gmail({ version: 'v1', auth: oauth2Client });
oauth2Client.setCredentials({
  access_token: gmailToken.accessToken,
  refresh_token: gmailToken.refreshToken
});
Enter fullscreen mode Exit fullscreen mode
  1. Session Management
// Middleware for protected routes
export async function middleware(request: NextRequest) {
  const session = await getSession();

  if (!session?.user) {
    return NextResponse.redirect(new URL('/', request.url));
  }

  return NextResponse.next();
}
Enter fullscreen mode Exit fullscreen mode
  1. Persistent Token Storage Critical Fix: Initially used in-memory storage which lost tokens on reload. Migrated to DynamoDB for persistence:
// Before: ❌ Lost on reload
global.tokenVault = new Map();
global.tokenVault.set(key, tokens);

// After: ✅ Persists forever
await DynamoDBService.put(TABLES.TOKENS, {
  PK: `TOKEN#${key}`,
  SK: 'METADATA',
  ...tokens
});
Enter fullscreen mode Exit fullscreen mode

Result: Tokens now survive:
✅ Page reloads
✅ Server restarts
✅ Deployment updates
✅ Load balancing across instances

Lessons Learned and Takeaways

🎯 1. Token Security is HARD (But Auth0 Makes It Easier)
Challenge: Initially, I stored OAuth tokens in memory, which seemed simple but caused tokens to disappear on every page reload!

Solution: Implemented Auth0's Token Vault pattern with DynamoDB persistence.

Lesson: Never underestimate the complexity of secure credential management. Auth0's patterns and documentation were invaluable in getting this right.

// The critical bug that took hours to debug:
// Storing with entry.id but retrieving with vaultKey! 🐛
await this.encryptAndStore(entry.id, tokens);  // ❌ Wrong key
const token = await this.decryptAndRetrieve(vaultKey);  // ❌ Different key

// The fix:
await this.encryptAndStore(vaultKey, tokens);  // ✅ Consistent key
const token = await this.decryptAndRetrieve(vaultKey);  // ✅ Same key
Enter fullscreen mode Exit fullscreen mode

Huge thanks to Auth0 and DEV.to for this challenge! Building AgentFlow taught me more about authentication, security, and AI agents than any tutorial could. The Auth0 SDK and Token Vault patterns were game-changers.

Special shoutout to the Auth0 documentation team - your Next.js examples saved me countless hours!

Built with ❤️ using Auth0, Next.js 14, TypeScript, DynamoDB, and AWS Amplify

Top comments (8)

Collapse
 
varshithvhegde profile image
Varshith V Hegde • Edited

UI looks awesome! 🎨🔥

I had one quick question while checking out the source code, I noticed that you’ve implemented a custom token vault using DynamoDB.

Since Auth0 already provides a built-in Token Vault feature, I was curious is there any specific reason or advantage behind creating your own custom implementation?
github.com/Abhinandangithub01/Agen...

Collapse
 
abhinandan-r profile image
Abhi nandan • Edited

Thanks, I stored the tokens temporarily in dynamoDB and i have changed to AuthO for token management

Collapse
 
aayush_bisht_4205e60d90fa profile image
Comment deleted
Collapse
 
abhinandan-r profile image
Abhi nandan

Yup, Looks like he's trying to find mistakes and pointing it out for other submissions

Thread Thread
 
varshithvhegde profile image
Varshith V Hegde

Usually, when a project looks impressive, I like to explore the source code to understand how it’s implemented. If something isn’t clear, I simply ask about it or share suggestions — that’s what constructive feedback is all about.

Collapse
 
varshithvhegde profile image
Varshith V Hegde

Wow, the hypocrisy is unreal! You’re accusing others of posting fake comments, yet you’re hiding behind a fake account yourself to spread hate.

Collapse
 
syedmuhammadaliraza profile image
Syed Muhammad Ali Raza

UI/UX looks great

Collapse
 
abhinandan-r profile image
Abhi nandan

Thanks Buddy

Some comments may only be visible to logged-in visitors. Sign in to view all comments.