> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tesouro.com/llms.txt
> Use this file to discover all available pages before exploring further.

# React

> Integrate Tesouro's embedded components into your React or Next.js application.

<Warning>
  `@tesouro/embedded-components-react` is currently in beta and not yet publicly available on npm.
  Contact your Tesouro representative to request early access.
</Warning>

## Overview

The `@tesouro/embedded-components-react` package provides a set of React components that embed Tesouro functionality directly into your application. Wrap your app in `EmbeddedProvider`, then render any combination of components — no Next.js required.

## Before you begin

You will need:

* A Tesouro **client ID** and **client secret** (provided during onboarding)
* A **widget secret** (`TESOURO_WIDGET_SECRET`) — a separate credential used to mint user-scoped widget tokens, also provided during onboarding

## 1. Install

```sh lines theme={null}
npm install @tesouro/embedded-components-react
```

## 2. Set up a widget token endpoint

Embedded components authenticate users via short-lived, user-scoped widget tokens — not your API access token. Your backend is responsible for minting these tokens and exposing them via an endpoint.

<Note>
  Widget tokens are user-scoped JWE tokens encrypted with your `TESOURO_WIDGET_SECRET`. They must
  be generated server-side to keep your credentials secure.
</Note>

The endpoint should accept `{ userId, userEmail }` and return `{ widgetToken }`:

<CodeGroup>
  ```ts Next.js (App Router) lines theme={null}
  // app/api/widget-token/route.ts
  import { EncryptJWT } from 'jose';

  export async function POST(req: Request) {
    const { userId, userEmail } = await req.json();
    // Resolve the applicant's organization from your own data — never accept it from the client.
    const organizationReference = await getOrganizationReference(userId);

    const widgetToken = await new EncryptJWT({
      sub: userId,
      email: userEmail,
      organization_reference: organizationReference,
      aud: 'tesouro',
      iss: process.env.TESOURO_CLIENT_ID,
    })
      .setProtectedHeader({ alg: 'A256KW', enc: 'A256GCM' })
      .setExpirationTime('8m')
      .encrypt(Buffer.from(process.env.TESOURO_WIDGET_SECRET!, 'hex'));

    return Response.json({ widgetToken });
  }
  ```

  ```ts Express lines theme={null}
  // routes/widget-token.ts
  import { EncryptJWT } from 'jose';
  import { Router } from 'express';

  const router = Router();

  router.post('/api/widget-token', async (req, res) => {
    const { userId, userEmail } = req.body;
    // Resolve the applicant's organization from your own data — never accept it from the client.
    const organizationReference = await getOrganizationReference(userId);

    const widgetToken = await new EncryptJWT({
      sub: userId,
      email: userEmail,
      organization_reference: organizationReference,
      aud: 'tesouro',
      iss: process.env.TESOURO_CLIENT_ID,
    })
      .setProtectedHeader({ alg: 'A256KW', enc: 'A256GCM' })
      .setExpirationTime('8m')
      .encrypt(Buffer.from(process.env.TESOURO_WIDGET_SECRET!, 'hex'));

    res.json({ widgetToken });
  });

  export default router;
  ```
</CodeGroup>

<Note>
  The widget token must include a required `organization_reference` claim — your opaque, stable
  identifier for the business the applicant belongs to. Resolve it on your backend from your own
  data; never accept it from the client.
</Note>

The required environment variables:

| Variable                | Description                                         |
| :---------------------- | :-------------------------------------------------- |
| `TESOURO_WIDGET_SECRET` | Hex-encoded secret key for encrypting widget tokens |
| `TESOURO_CLIENT_ID`     | Your Tesouro client ID                              |
| `TESOURO_CLIENT_SECRET` | Your Tesouro client secret                          |

## 3. Wrap your app with `EmbeddedProvider`

Import `EmbeddedProvider` and configure it with the current user's identity and your token endpoint:

```tsx lines theme={null}
import { EmbeddedProvider } from '@tesouro/embedded-components-react';

export default function Layout({ children }: { children: React.ReactNode }) {
  return (
    <EmbeddedProvider
      userId={currentUser.id}
      userEmail={currentUser.email}
      widgetTokenRefreshUrl="/api/widget-token"
      env="sandbox"
    >
      {children}
    </EmbeddedProvider>
  );
}
```

| Prop                         | Required | Description                                            |
| :--------------------------- | :------- | :----------------------------------------------------- |
| `userId`                     | Yes      | Your platform's unique identifier for the current user |
| `userEmail`                  | Yes      | The current user's email address                       |
| `widgetTokenRefreshUrl`      | Yes      | URL of your widget token endpoint                      |
| `env`                        | No       | `"sandbox"` or `"production"` (default: `"sandbox"`)   |
| `widgetTokenRefreshInterval` | No       | Token refresh interval in ms (default: `300000`)       |
| `styleOverrides`             | No       | Theme customizations (see below)                       |
| `navigationAdapter`          | No       | Custom navigation adapter (see below)                  |

## (Optional) Navigation adapter

By default, `EmbeddedProvider` uses browser-native navigation (`window.history`). Pass a `navigationAdapter` to integrate with your router:

<CodeGroup>
  ```tsx Next.js (App Router) lines theme={null}
  'use client';

  import { useRouter, usePathname, useSearchParams } from 'next/navigation';
  import { EmbeddedProvider } from '@tesouro/embedded-components-react';

  export function Providers({ children }: { children: React.ReactNode }) {
    const router = useRouter();
    const pathname = usePathname();
    const searchParams = useSearchParams();

    return (
      <EmbeddedProvider
        userId={currentUser.id}
        userEmail={currentUser.email}
        widgetTokenRefreshUrl="/api/widget-token"
        navigationAdapter={{
          push: (url) => router.push(url),
          replace: (url) => router.replace(url),
          pathname,
          searchParams: new URLSearchParams(searchParams.toString()),
        }}
      >
        {children}
      </EmbeddedProvider>
    );
  }
  ```

  ```tsx React Router v6 lines theme={null}
  import { useNavigate, useLocation } from 'react-router-dom';
  import { EmbeddedProvider } from '@tesouro/embedded-components-react';

  export function Providers({ children }: { children: React.ReactNode }) {
    const navigate = useNavigate();
    const location = useLocation();

    return (
      <EmbeddedProvider
        userId={currentUser.id}
        userEmail={currentUser.email}
        widgetTokenRefreshUrl="/api/widget-token"
        navigationAdapter={{
          push: (url) => navigate(url),
          replace: (url) => navigate(url, { replace: true }),
          pathname: location.pathname,
          searchParams: new URLSearchParams(location.search),
        }}
      >
        {children}
      </EmbeddedProvider>
    );
  }
  ```
</CodeGroup>

## (Optional) Style overrides

Customize the look and feel to match your platform:

```tsx lines theme={null}
<EmbeddedProvider
  userId={currentUser.id}
  userEmail={currentUser.email}
  widgetTokenRefreshUrl="/api/widget-token"
  styleOverrides={{
    primaryColor: '#1a5eea',
    fontFamily: 'Inter, sans-serif',
  }}
>
  {children}
</EmbeddedProvider>
```

## Next steps

* [Embedded Banking components](/embedded-banking/guides/embedded-components/onboarding) — onboarding, balances, transfers, and more
* [FinOps components](/finops/guides/embedded-components/invoicing) — invoicing, expense management, and bill pay
