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

# Cross-Tenant Identity

> One user, one wallet, multiple apps. How cross-tenant identity works in Steward.

# Cross-Tenant Identity

Steward supports **multi-tenant authentication**. A single user identity can belong to multiple apps (tenants), each with its own agents, policies, and configuration. The user keeps the same wallet and credentials across all apps.

## How It Works

When a user signs up through any auth method, Steward creates a **user record** tied to their email or wallet address. This user can then join additional tenants without creating new accounts.

```
User (user@example.com)
├── Tenant: "trading-app"    → role: admin
├── Tenant: "nft-gallery"    → role: member
└── Tenant: "defi-dashboard" → role: member
```

The JWT access token includes a `tenantId` claim that scopes all API operations. Switching tenants refreshes the JWT with a new tenant context.

## Join Modes

Each tenant controls how new users can join:

| Mode     | Description                                 |
| -------- | ------------------------------------------- |
| `open`   | Anyone can join by calling `joinTenant(id)` |
| `invite` | Users must be invited by a tenant admin     |
| `closed` | No new members allowed                      |

## SDK Usage

### List Tenants

```typescript theme={null}
const auth = new StewardAuth({
  baseUrl: "https://api.steward.fi",
  storage: localStorage,
});

// After signing in...
const tenants = await auth.listTenants();
console.log(tenants);
// [
//   { tenantId: "trading-app", tenantName: "Trading App", role: "admin", joinedAt: "..." },
//   { tenantId: "nft-gallery", tenantName: "NFT Gallery", role: "member", joinedAt: "..." },
// ]
```

### Switch Tenant

Switching tenants refreshes the session JWT with a new `tenantId` claim:

```typescript theme={null}
const session = await auth.switchTenant("nft-gallery");
if (session) {
  console.log("Now in:", session.tenantId); // "nft-gallery"
} else {
  console.log("Switch failed, user may need to re-authenticate");
}
```

### Join a Tenant

```typescript theme={null}
const membership = await auth.joinTenant("defi-dashboard");
console.log(membership);
// { tenantId: "defi-dashboard", tenantName: "DeFi Dashboard", role: "member", joinedAt: "..." }
```

### Leave a Tenant

```typescript theme={null}
await auth.leaveTenant("defi-dashboard");
```

<Note>
  Users cannot leave their personal/default tenant. Attempting to leave the tenant they signed up with will throw an error.
</Note>

## React Usage

### Tenant Picker

The `<StewardTenantPicker>` component renders a dropdown or list for switching between apps:

```tsx theme={null}
import { StewardTenantPicker } from "@stwd/react";

// Dropdown variant (compact, click to expand)
<StewardTenantPicker
  variant="dropdown"
  onSwitch={(tenantId) => console.log("Switched to:", tenantId)}
/>

// List variant (always visible, good for settings pages)
<StewardTenantPicker variant="list" />
```

The component shows the active tenant, lists all memberships, and handles switching via `auth.switchTenant()`. It auto-fetches tenant memberships when the user signs in.

### User Button with Tenant Switcher

The `<StewardUserButton>` can include an inline tenant switcher:

```tsx theme={null}
import { StewardUserButton } from "@stwd/react";

<StewardUserButton
  showTenantSwitcher  // adds tenant switching inside the dropdown
  showWallet          // show wallet address
  onSignOut={() => router.push("/login")}
/>
```

### Login with Tenant Context

Pass a `tenantId` to `<StewardLogin>` to scope authentication to a specific app:

```tsx theme={null}
<StewardLogin
  tenantId="trading-app"
  showGoogle
  showPasskey
  title="Sign in to Trading App"
/>
```

## API Endpoints

| Endpoint                            | Method | Description                                                |
| ----------------------------------- | ------ | ---------------------------------------------------------- |
| `/user/me/tenants`                  | GET    | List all tenants the current user belongs to               |
| `/user/me/tenants/{tenantId}/join`  | POST   | Join an open tenant                                        |
| `/user/me/tenants/{tenantId}/leave` | DELETE | Leave a tenant                                             |
| `/auth/refresh`                     | POST   | Refresh with `{ refreshToken, tenantId }` to switch tenant |

## Data Isolation

Each tenant is a fully isolated environment:

* **Agents** are scoped to a tenant. Agent IDs are unique within a tenant.
* **Policies** are set per-agent, per-tenant.
* **Secrets** and **routes** are tenant-scoped.
* **Transaction history** is per-tenant.

The user's wallet address is shared across tenants, but all operational data is isolated.

## Related

* [Auth Overview](/auth/overview) — Authentication flow and session management
* [React Components](/sdk/react-components) — `<StewardTenantPicker>` and `<StewardUserButton>`
* [Tenants API](/api-reference/tenants) — REST API for tenant management
