How Tambo AI Handles Authentication and API Communication in the React SDK

Tambo AI's React SDK implements a layered authentication architecture that supports both static API keys and dynamic OAuth token exchanges, ensuring secure API communication through a discriminated union auth state pattern that prevents unauthorized requests.

The Tambo AI React SDK provides a robust authentication and API communication system designed for React applications requiring secure interactions with the Tambo API. This architecture separates concerns between client configuration, session token management, and authentication state derivation to ensure every API request carries valid credentials. Whether using a static userKey for server-side scenarios or a dynamic userToken for client-side OAuth flows, the SDK guarantees type-safe authentication state management throughout the component tree.

Layered Authentication Architecture

The SDK organizes authentication into distinct layers, each with specific responsibilities and implementation files.

Configuration Layer: TamboClientProvider

The TamboClientProvider component in src/providers/tambo-client-provider.tsx constructs the ClientOptions object passed to the underlying @tambo-ai/typescript-sdk client. It creates a tamboConfig object containing the API key, optional tamboUrl, environment settings, default headers, and the userKey query parameter for static authentication scenarios.

// Conceptual implementation based on source analysis
const tamboConfig = {
  apiKey: props.apiKey,
  environment: props.environment,
  defaultHeaders: { ... },
  // userKey is injected as a default query parameter
};

Session Token Handling with useTamboSessionToken

For OAuth-based authentication, the useTamboSessionToken hook in src/providers/hooks/use-tambo-session-token.tsx manages the exchange of third-party OAuth tokens (userToken) for short-lived Tambo session tokens. This React Query-powered hook performs the token exchange via client.beta.auth.getToken, automatically refreshes the token using refetchInterval, and updates client.bearer with the new access token.

// Token exchange implementation
const { data } = useQuery({
  queryKey: ['tambo-session-token', userToken],
  queryFn: async () => {
    const response = await client.beta.auth.getToken({ userToken });
    return response.access_token;
  },
  refetchInterval: (data) => {
    // Refresh before expiration
    return data ? (expiresIn * 1000) - buffer : false;
  }
});

Auth State Derivation via useTamboAuthState

The useTamboAuthState hook in src/v1/hooks/use-tambo-v1-auth-state.ts computes the current authentication status by inspecting the client context, configuration context, and token exchange results. It returns a discriminated union (TamboAuthState defined in src/v1/types/auth.ts) with one of five statuses: identified, exchanging, error, invalid, or unauthenticated.

// TamboAuthState discriminated union
type TamboAuthState = 
  | { status: "identified"; source: "userKey" | "tokenExchange" }
  | { status: "exchanging" }
  | { status: "error"; error: Error }
  | { status: "invalid" }
  | { status: "unauthenticated" };

Authentication Flow Step-by-Step

Understanding the exact sequence of operations helps debug authentication issues and implement custom flows.

  1. Provider Mounting – The application renders <TamboProvider> with either a userKey (static) or userToken (OAuth).

  2. Client Initialization – TamboClientProvider constructs the tamboConfig object and instantiates new TamboAI(tamboConfig), establishing the base HTTP client with default headers and query parameters.

  3. Token Exchange – If userToken is provided, useTamboSessionToken executes:

    • POSTs a token-exchange request to client.beta.auth.getToken
    • Receives access_token and expires_in
    • Sets client.bearer = access_token
    • Configures automatic refresh via React Query's refetchInterval
  4. State Computation – useTamboAuthState evaluates the combined configuration and token status, returning the appropriate TamboAuthState variant.

  5. Warning Generation – TamboAuthWarnings (rendered within TamboProvider) logs console messages for unauthenticated, invalid, or error states to aid development debugging.

  6. API Request Guarding – All data-fetching hooks (such as useTamboV1Thread and useTamboV1SendMessage) check useTamboAuthState before executing, ensuring no API call proceeds without valid authentication.

Preventing Unauthorized API Calls

The SDK implements defense-in-depth to prevent unauthenticated requests. The discriminated union pattern in src/v1/types/auth.ts forces exhaustive handling of all authentication states. Downstream hooks import useTamboClient to access the configured client, but rely on useTamboAuthState to gate execution.

When the status is identified, hooks proceed with API calls using the client instance that already contains the correct bearer token (for OAuth) or userKey query parameter (for static auth). For all other states (exchanging, error, invalid, unauthenticated), hooks either return loading states or throw errors, preventing any network request to Tambo AI endpoints.

Implementation Examples

Basic Provider Setup

Configure the SDK with either static or OAuth authentication:

import { TamboProvider } from "@tambo-ai/react";

function App() {
  return (
    <TamboProvider
      apiKey={process.env.NEXT_PUBLIC_TAMBO_API_KEY!}
      // Choose one authentication method:
      userKey="user-12345"               // Static server-side key
      // userToken={oauthAccessToken}     // Client-side OAuth token
    >
      <ChatInterface />
    </TamboProvider>
  );
}

Monitoring Authentication State

Use the discriminated union to handle all auth states exhaustively:

import { useTamboAuthState } from "@tambo-ai/react/v1/hooks/use-tambo-v1-auth-state";

function AuthStatus() {
  const auth = useTamboAuthState();

  switch (auth.status) {
    case "identified":
      return <p>Authenticated via {auth.source}</p>;
    case "exchanging":
      return <p>Signing you in...</p>;
    case "error":
      return <p>Authentication failed: {auth.error.message}</p>;
    case "invalid":
      return <p>Error: Cannot use both userKey and userToken</p>;
    case "unauthenticated":
      return <p>Please configure authentication</p>;
  }
}

Making Authenticated API Calls

Access the client and guard requests based on auth state:

import { useTamboClient } from "@tambo-ai/react";
import { useTamboAuthState } from "@tambo-ai/react/v1/hooks/use-tambo-v1-auth-state";
import { useQuery } from "@tanstack/react-query";

function ThreadList() {
  const client = useTamboClient();
  const auth = useTamboAuthState();

  const { data, isLoading } = useQuery({
    queryKey: ["threads"],
    queryFn: async () => {
      const result = await client.beta.threads.list();
      return result.threads;
    },
    // Only execute when authenticated
    enabled: auth.status === "identified",
  });

  if (auth.status !== "identified") {
    return <div>Waiting for authentication...</div>;
  }

  return (
    <ul>
      {data?.map(thread => (
        <li key={thread.id}>{thread.id}</li>
      ))}
    </ul>
  );
}

Manual Session Token Refresh

Force a token refresh in rare edge cases:

import { useTamboClient, useTamboSessionToken } from "@tambo-ai/react";

function ForceRefresh() {
  const client = useTamboClient();
  const { refetch } = useTamboSessionToken(
    client, 
    client.queryClient, 
    "oauth-token"
  );

  return (
    <button onClick={() => refetch()}>
      Refresh session token
    </button>
  );
}

Key Source Files

Understanding the implementation requires familiarity with these specific files in the tambo-ai/tambo repository:

Summary

  • Tambo AI React SDK authentication operates through a layered architecture separating configuration, token exchange, and state management.
  • The TamboClientProvider in src/providers/tambo-client-provider.tsx initializes the HTTP client with API keys and optional userKey parameters.
  • OAuth flows use useTamboSessionToken in src/providers/hooks/use-tambo-session-token.tsx to exchange third-party tokens for short-lived bearer tokens with automatic refresh.
  • useTamboAuthState in src/v1/hooks/use-tambo-v1-auth-state.ts exposes a discriminated union (TamboAuthState) that forces exhaustive handling of all authentication states.
  • All API calls are gated by authentication state checks, ensuring no requests proceed without valid credentials via userKey or bearer token.

Frequently Asked Questions

What is the difference between userKey and userToken in Tambo AI React SDK?

The userKey is a static identifier passed directly to the TamboProvider that gets attached as a query parameter to all API requests, suitable for server-side or trusted client scenarios. In contrast, userToken is a third-party OAuth access token that the SDK exchanges for a short-lived Tambo session token via client.beta.auth.getToken, storing the result as a bearer token for authenticated requests.

How does Tambo AI React SDK prevent API calls without authentication?

The SDK implements a discriminated union pattern through TamboAuthState (defined in src/v1/types/auth.ts) that requires downstream hooks to handle every possible authentication status. Hooks such as useTamboV1Thread check useTamboAuthState before executing API calls, only proceeding when the status is "identified", effectively blocking all network requests when authentication is missing, invalid, or in an error state.

What happens when the Tambo session token expires?

The useTamboSessionToken hook in src/providers/hooks/use-tambo-session-token.tsx utilizes React Query's refetchInterval option to automatically refresh the token before it expires. When the token exchange response includes expires_in, the hook calculates a refresh interval that triggers a new call to client.beta.auth.getToken, updating client.bearer with the new access token seamlessly without requiring manual intervention.

Can I use both userKey and userToken simultaneously?

No, the SDK explicitly treats this configuration as invalid. The useTamboAuthState hook returns a status of "invalid" when both userKey and userToken are present simultaneously, and the TamboAuthWarnings component logs a console error to alert developers of the misconfiguration. You must choose either the static userKey approach or the dynamic OAuth userToken flow, but never both at the same time.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →