Build/Frontend

Adding Authentication

Add user authentication with Clerk, Auth0, or other identity providers

Protect your agents and routes with user authentication. The @agentuity/auth package provides integrations for identity providers.

Quick Start

A Clerk template is available for new projects:

bunx agentuity create my-app --template clerk
cd my-app
cp .env.example .env
# Add your Clerk keys from https://dashboard.clerk.com
bun run dev

For Auth0 or other providers, follow the manual setup guides below.

Clerk

Installation

bun add @agentuity/auth @clerk/clerk-react @clerk/backend

Client Setup

Wrap your app with the Clerk and Agentuity providers:

import React from 'react';
import { createRoot } from 'react-dom/client';
import { ClerkProvider, useAuth } from '@clerk/clerk-react';
import { AgentuityProvider } from '@agentuity/react';
import { AgentuityClerk } from '@agentuity/auth/clerk';
import { App } from './App';
 
const CLERK_KEY = process.env.AGENTUITY_PUBLIC_CLERK_PUBLISHABLE_KEY;
 
createRoot(document.getElementById('root')!).render(
  <ClerkProvider publishableKey={CLERK_KEY!}>
    <AgentuityProvider>
      <AgentuityClerk useAuth={useAuth}>
        <App />
      </AgentuityClerk>
    </AgentuityProvider>
  </ClerkProvider>
);

Provider Order

AgentuityClerk must be inside both ClerkProvider and AgentuityProvider. The order matters.

Server Middleware

Protect routes with createMiddleware():

import { createRouter } from '@agentuity/runtime';
import { createMiddleware } from '@agentuity/auth/clerk';
 
const router = createRouter();
 
// Protected route - requires authentication
router.get('/profile', createMiddleware(), async (c) => {
  const user = await c.var.auth.requireUser();
  return c.json({
    id: user.id,
    name: user.name,
    email: user.email,
  });
});
 
// Public route - no auth required
router.get('/public', (c) => {
  return c.json({ message: 'Anyone can access this' });
});
 
export default router;

Environment Variables

VariableSideDescription
AGENTUITY_PUBLIC_CLERK_PUBLISHABLE_KEYClientClerk publishable key (bundled into frontend)
CLERK_SECRET_KEYServerClerk secret key (never exposed to client)

AGENTUITY_PUBLIC_ Prefix

Environment variables prefixed with AGENTUITY_PUBLIC_ are bundled into the frontend build and accessible via process.env. Keep secrets (like CLERK_SECRET_KEY) without this prefix.

Clerk-Specific Data

Access Clerk-specific fields via user.raw:

router.get('/profile', createMiddleware(), async (c) => {
  const user = await c.var.auth.requireUser();
 
  // Clerk-specific fields (fully typed)
  const imageUrl = user.raw.imageUrl;
  const metadata = user.raw.publicMetadata;
  const createdAt = user.raw.createdAt;
 
  // Access JWT payload
  const payload = c.var.auth.raw;
  c.var.logger.debug('JWT payload', { sub: payload.sub });
 
  return c.json({ user, imageUrl });
});

Auth0

Installation

bun add @agentuity/auth @auth0/auth0-react

Client Setup

Wrap your app with the Auth0 and Agentuity providers:

import React from 'react';
import { createRoot } from 'react-dom/client';
import { Auth0Provider, useAuth0 } from '@auth0/auth0-react';
import { AgentuityProvider } from '@agentuity/react';
import { AgentuityAuth0 } from '@agentuity/auth/auth0';
import { App } from './App';
 
const domain = process.env.AGENTUITY_PUBLIC_AUTH0_DOMAIN;
const clientId = process.env.AGENTUITY_PUBLIC_AUTH0_CLIENT_ID;
 
createRoot(document.getElementById('root')!).render(
  <Auth0Provider
    domain={domain!}
    clientId={clientId!}
    authorizationParams={{ redirect_uri: window.location.origin }}
  >
    <AgentuityProvider>
      <AgentuityAuth0 useAuth0={useAuth0}>
        <App />
      </AgentuityAuth0>
    </AgentuityProvider>
  </Auth0Provider>
);

Server Middleware

Protect routes with Auth0's createMiddleware():

import { createRouter } from '@agentuity/runtime';
import { createMiddleware } from '@agentuity/auth/auth0/server';
 
const router = createRouter();
 
router.get('/profile', createMiddleware(), async (c) => {
  const user = await c.var.auth.getUser();
  return c.json({
    id: user.id,
    name: user.name,
    email: user.email,
  });
});
 
export default router;

Environment Variables

VariableSideDescription
AGENTUITY_PUBLIC_AUTH0_DOMAINClientAuth0 domain (e.g., your-tenant.auth0.com)
AGENTUITY_PUBLIC_AUTH0_CLIENT_IDClientAuth0 application client ID
AGENTUITY_PUBLIC_AUTH0_AUDIENCEClientAuth0 API audience (optional)
AUTH0_DOMAINServerAuth0 domain (server-side)
AUTH0_AUDIENCEServerAuth0 API audience (optional)

User Profile

By default, user info is fetched from Auth0's /userinfo endpoint. For richer profile data, set fetchUserProfile: true in the middleware options and configure AUTH0_M2M_CLIENT_ID and AUTH0_M2M_CLIENT_SECRET for Management API access.

Common Patterns

These patterns work with any supported provider.

Using Auth State in Components

The useAgentuity hook provides authentication state:

import { useAPI, useAgentuity } from '@agentuity/react';
 
function Dashboard() {
  const { isAuthenticated, authLoading } = useAgentuity();
  const { data, refetch } = useAPI('GET /api/profile');
 
  if (authLoading) {
    return <div>Loading...</div>;
  }
 
  if (!isAuthenticated) {
    return <div>Please sign in to continue</div>;
  }
 
  return (
    <div>
      <h1>Welcome, {data?.name}</h1>
      <button onClick={() => refetch()}>Refresh Profile</button>
    </div>
  );
}

Once your auth provider is set up, useAPI and useWebsocket automatically include the auth token in requests.

Accessing User Data

All providers expose a common interface:

router.get('/profile', createMiddleware(), async (c) => {
  const user = await c.var.auth.requireUser();
 
  // Available on all providers
  c.var.logger.info('User authenticated', {
    id: user.id,
    name: user.name,
    email: user.email,
  });
 
  return c.json(user);
});

Global Middleware

Protect all routes under a path prefix:

import { createRouter } from '@agentuity/runtime';
import { createMiddleware } from '@agentuity/auth/clerk';
 
const router = createRouter();
 
// Protect all /api/* routes
router.use('/api/*', createMiddleware());
 
router.get('/api/profile', async (c) => {
  const user = await c.var.auth.requireUser();
  return c.json({ email: user.email });
});
 
router.get('/api/settings', async (c) => {
  const user = await c.var.auth.requireUser();
  return c.json({ userId: user.id });
});
 
export default router;

Other Providers

For identity providers not yet supported by @agentuity/auth, use JWT middleware to validate tokens from your provider.

Next Steps

Need Help?

Join our DiscordCommunity for assistance or just to hang with other humans building agents.

Send us an email at hi@agentuity.com if you'd like to get in touch.

Please Follow us on

If you haven't already, please Signup for your free account now and start building your first agent!