Tambo Lockup

Clerk

Learn how to integrate Tambo with Clerk for user authentication.

Clerk is a complete authentication and user management solution that handles authentication through middleware without requiring specific API routes. This guide shows how to integrate it with Tambo.

Prerequisites

This guide assumes you've already set up Clerk in your Next.js application, including middleware and sign-in/sign-up pages. If you haven't, follow the Clerk Next.js Quick Start first.

Installation

Install the required packages:

npm install @clerk/nextjs @tambo-ai/react

Integration Options

Use this approach for better security and performance, especially when you don't need real-time authentication state changes.

app/layout.tsx
import { auth } from "@clerk/nextjs/server";
import ClientLayout from "./client-layout";

export default async function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  const { getToken } = await auth();
  const token = await getToken();

  return (
    <html lang="en">
      <body>
        <ClientLayout userToken={token}>{children}</ClientLayout>
      </body>
    </html>
  );
}
app/client-layout.tsx
"use client";

import { ClerkProvider } from "@clerk/nextjs";
import { TamboProvider } from "@tambo-ai/react";
import { ReactNode } from "react";

interface ClientLayoutProps {
  children: ReactNode;
  userToken?: string;
}

export default function ClientLayout({
  children,
  userToken,
}: ClientLayoutProps) {
  return (
    <ClerkProvider>
      <TamboProvider userToken={userToken}>{children}</TamboProvider>
    </ClerkProvider>
  );
}

Client-Side Token Retrieval

Use this approach when you need real-time authentication state management or client-side routing with authentication guards.

app/layout.tsx
"use client";

import { ClerkProvider } from "@clerk/nextjs";
import ClientLayout from "./client-layout";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <ClerkProvider>
          <ClientLayout>{children}</ClientLayout>
        </ClerkProvider>
      </body>
    </html>
  );
}
app/client-layout.tsx
"use client";

import { useAuth } from "@clerk/nextjs";
import { TamboProvider } from "@tambo-ai/react";
import { ReactNode, useEffect, useState } from "react";

interface ClientLayoutProps {
  children: ReactNode;
}

export default function ClientLayout({ children }: ClientLayoutProps) {
  const { getToken, isLoaded, isSignedIn } = useAuth();
  const [accessToken, setAccessToken] = useState<string | undefined>();

  useEffect(() => {
    async function fetchToken() {
      if (isLoaded && isSignedIn) {
        try {
          const token = await getToken();
          setAccessToken(token || undefined);
        } catch (error) {
          console.error("Error fetching token:", error);
        }
      }
    }

    fetchToken();
  }, [isLoaded, isSignedIn, getToken]);

  return <TamboProvider userToken={accessToken}>{children}</TamboProvider>;
}

Usage

Once configured, you can use Tambo components throughout your application:

app/dashboard/page.tsx
import { MessageThreadFull } from "@components/ui/tambo";

export default function Dashboard() {
  return (
    <div>
      <h1>Dashboard</h1>
      <MessageThreadFull />
    </div>
  );
}

Advanced Configuration

Custom JWT Templates

For advanced use cases, you can create custom JWT templates in Clerk to include specific claims:

  1. Go to your Clerk Dashboard
  2. Navigate to "JWT Templates"
  3. Create a new template with the claims you need
  4. Use the template name when calling getToken():
const token = await getToken({ template: "your-template-name" });

Token Format

Clerk provides JWT tokens that include the user's ID in the sub claim, which is exactly what Tambo needs for user identification. The token is automatically signed and verified by Clerk.