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

> Learn how Tambo AI secures API communication in its React SDK using layered authentication supporting API keys and OAuth tokens. Prevent unauthorized access with robust security patterns.

- Repository: [tambo ai/tambo](https://github.com/tambo-ai/tambo)
- Tags: how-to-guide
- Published: 2026-02-16

---

**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`](https://github.com/tambo-ai/tambo/blob/main/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.

```typescript
// 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`](https://github.com/tambo-ai/tambo/blob/main/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.

```typescript
// 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`](https://github.com/tambo-ai/tambo/blob/main/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`](https://github.com/tambo-ai/tambo/blob/main/src/v1/types/auth.ts)) with one of five statuses: `identified`, `exchanging`, `error`, `invalid`, or `unauthenticated`.

```typescript
// 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`](https://github.com/tambo-ai/tambo/blob/main/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:

```tsx
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:

```tsx
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:

```tsx
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:

```tsx
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:

- **[`src/v1/types/auth.ts`](https://github.com/tambo-ai/tambo/blob/main/src/v1/types/auth.ts)** – Defines the `TamboAuthState` discriminated union with statuses `identified`, `exchanging`, `error`, `invalid`, and `unauthenticated`.

- **[`src/v1/hooks/use-tambo-v1-auth-state.ts`](https://github.com/tambo-ai/tambo/blob/main/src/v1/hooks/use-tambo-v1-auth-state.ts)** – Computes the current auth state by inspecting configuration context, client context, and token exchange results.

- **[`src/providers/tambo-client-provider.tsx`](https://github.com/tambo-ai/tambo/blob/main/src/providers/tambo-client-provider.tsx)** – Initializes the `TamboAI` client with `tamboConfig`, sets up default headers, and injects the `userKey` query parameter for static authentication.

- **[`src/providers/hooks/use-tambo-session-token.tsx`](https://github.com/tambo-ai/tambo/blob/main/src/providers/hooks/use-tambo-session-token.tsx)** – Handles OAuth token exchange via `client.beta.auth.getToken`, automatic refresh via React Query's `refetchInterval`, and updates `client.bearer`.

- **[`src/v1/providers/tambo-v1-provider.tsx`](https://github.com/tambo-ai/tambo/blob/main/src/v1/providers/tambo-v1-provider.tsx)** – High-level provider composing all sub-providers and rendering `TamboAuthWarnings` for development debugging.

## 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`](https://github.com/tambo-ai/tambo/blob/main/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`](https://github.com/tambo-ai/tambo/blob/main/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`](https://github.com/tambo-ai/tambo/blob/main/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`](https://github.com/tambo-ai/tambo/blob/main/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`](https://github.com/tambo-ai/tambo/blob/main/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.