# @hiyve/react-identity

React components and hooks for Hiyve Identity authentication — login, registration, two-factor authentication, password management, email verification, OAuth 2.1/PKCE clients, MCP tokens, and trusted device management.

## Installation

```bash
npm install @hiyve/react-identity @hiyve/identity-client
```

### Peer Dependencies

```bash
npm install react @mui/material @mui/icons-material @emotion/react @emotion/styled @hiyve/utilities
```

## Quick Start

### Zero-Config with Server Proxy (Recommended)

When your Express server uses `@hiyve/admin` middleware (`mountHiyveRoutes`), the API key stays server-side and `IdentityProvider` needs no props:

```tsx
import { IdentityProvider, AuthFlow } from '@hiyve/react-identity';

function App() {
  return (
    <IdentityProvider>
      <AuthFlow
        onAuthenticated={(user) => console.log('Logged in:', user)}
        onRegistered={(user) => console.log('Registered:', user)}
      />
    </IdentityProvider>
  );
}
```

Requests are proxied through your server at `/api/hiyve/identity/*`, which injects the API key and forwards to Hiyve Cloud.

### Direct Mode (API Key in Client)

If you prefer to connect directly to Hiyve Cloud without a server proxy:

```tsx
<IdentityProvider apiKey="pk_live_xxx">
  <AuthFlow onAuthenticated={handleAuth} />
</IdentityProvider>
```

### Handle Password Reset and Email Verification

Pass tokens from your URL to `AuthFlow` to show the correct view automatically:

```tsx
const params = new URLSearchParams(location.search);

<AuthFlow
  resetToken={params.get('reset_token') || undefined}
  verificationToken={params.get('verify_token') || undefined}
  onAuthenticated={handleAuth}
/>
```

> **Note:** Email verification and TFA are independently configurable per-organization on the server. When email verification is disabled, users are created with `emailVerified: true` and no verification email is sent. When TFA is disabled, login always returns tokens directly. See the [Server Integration Guide](https://sdk.hiyve.dev/guides/server-integration#email-verification-and-tfa-configuration) for configuration details.

### Individual Forms

Use forms directly with your own routing:

```tsx
import { IdentityProvider, LoginForm } from '@hiyve/react-identity';

function LoginPage() {
  return (
    <LoginForm
      onSuccess={() => navigate('/dashboard')}
      onTfaRequired={() => navigate('/verify')}
      onForgotPassword={() => navigate('/forgot-password')}
      onRegister={() => navigate('/register')}
    />
  );
}
```

## Provider

### IdentityProvider

Wrap your application (or the authenticated portion) with `IdentityProvider` to enable all hooks and components.

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `apiKey` | `string` | — | API key (`pk_live_*` or `pk_test_*`). Required unless `baseUrl` is set |
| `baseUrl` | `string` | — | Full base URL for proxy mode. When set, requests bypass Hiyve Cloud and go to your server |
| `environment` | `'production' \| 'development'` | `'production'` | API environment |
| `basePath` | `string` | `'/identity/auth'` | Custom API base path (ignored when `baseUrl` is set) |
| `tokenStorage` | `'localStorage' \| 'memory'` | `'localStorage'` | Token persistence strategy |
| `autoRefresh` | `boolean` | `true` | Refresh tokens before expiry |
| `refreshBuffer` | `number` | `300` | Seconds before expiry to trigger refresh |
| `timeout` | `number` | `30000` | Request timeout in milliseconds |

```tsx
<IdentityProvider
  apiKey="pk_test_xxx"
  environment="development"
  tokenStorage="memory"
>
  <App />
</IdentityProvider>
```

## Hooks

| Hook | Returns | Description |
|------|---------|-------------|
| `useIdentity()` | `IdentityContextValue` | Full context — throws outside provider |
| `useUser()` | `{ user, isAuthenticated, isLoading, status, refreshUser }` | User data and auth status |
| `useAuthState()` | `{ status, isAuthenticated, isLoading, error, tfaRequired, tfaEvent, clearError }` | Auth lifecycle state |
| `useAuthActions()` | `{ login, register, logout, verifyTfa, resendOtp, ... }` | Auth action methods |
| `useIdentitySafe()` | `IdentityContextValue \| null` | Returns `null` outside provider |
| `useAuthClient()` | `HiyveAuth` | Raw `@hiyve/identity-client` instance for advanced use |
| `useProfile()` | `{ profile, isLoading, error, updateProfile }` | Authenticated user profile with update capability |

```tsx
function Profile() {
  const { user, isAuthenticated } = useUser();
  const { logout } = useAuthActions();

  if (!isAuthenticated) return <p>Not logged in</p>;
  return <button onClick={logout}>Logout {user?.email}</button>;
}
```

```tsx
function Header() {
  const identity = useIdentitySafe();
  return (
    <header>
      {identity?.isAuthenticated
        ? <span>{identity.user?.email}</span>
        : <a href="/login">Sign In</a>}
    </header>
  );
}
```

```tsx
function ProfilePage() {
  const { profile, isLoading, error, updateProfile } = useProfile();

  if (isLoading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  return (
    <div>
      <p>Hello, {profile?.name}</p>
      <button onClick={() => updateProfile({ name: 'New Name' })}>
        Update Name
      </button>
    </div>
  );
}
```

## Auth Form Components

| Component | Description | Key Props |
|-----------|-------------|-----------|
| `LoginForm` | Email/password login with password visibility toggle | `onSuccess`, `onTfaRequired`, `onForgotPassword`, `onRegister` |
| `RegisterForm` | Registration with password strength indicator | `onSuccess`, `onLogin`, `requireName` |
| `TfaVerification` | 6-digit OTP input with countdown resend timer | `onSuccess`, `onBack`, `resendCooldown` |
| `PasswordResetRequest` | Request a password reset email | `onSuccess`, `onBack` |
| `PasswordResetForm` | Set new password with reset token | `token`, `onSuccess`, `onBack` |
| `EmailVerification` | Auto-verify email token on mount | `token`, `email`, `onSuccess`, `onContinue` |

## Management Panel Components

| Component | Description | Key Props |
|-----------|-------------|-----------|
| `UserProfile` | Avatar, name, email, verification badge, logout | `onLogout`, `showLogout` |
| `DeviceManagement` | List and revoke trusted devices | `onError` |
| `McpTokenManagement` | Create, list, and revoke MCP tokens | `availablePermissions`, `expiryOptions` |
| `OAuthClientManagement` | Create, list, and delete OAuth clients | `availableScopes` |

## AuthFlow

State machine that composes all auth forms with automatic transitions between login, register, forgot password, TFA, reset password, and email verification.

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `initialView` | `AuthFlowView` | `'login'` | Starting view |
| `onAuthenticated` | `(user) => void` | — | Called on login or TFA success |
| `onRegistered` | `(user) => void` | — | Called on registration success |
| `resetToken` | `string` | — | Auto-navigates to reset password view |
| `verificationToken` | `string` | — | Auto-navigates to email verification view |
| `showRegisterLink` | `boolean` | `true` | Show registration option on login |

## Customization

All components accept `labels`, `colors`, `styles`, and `icons` props. Override individual values — unspecified values use defaults.

```tsx
<LoginForm
  labels={{ title: 'Welcome Back', submitButton: 'Log In' }}
  colors={{ submitButton: '#6200ea', linkText: '#6200ea' }}
  styles={{ borderRadius: 12, maxWidth: 360 }}
  icons={{ email: <MyEmailIcon /> }}
/>
```

Use the exported `default*` objects to see all available keys:

```tsx
import { defaultLoginFormLabels, defaultLoginFormColors } from '@hiyve/react-identity';
```

Use `merge*` functions for programmatic overrides:

```tsx
import { mergeLoginFormLabels } from '@hiyve/react-identity';

const labels = mergeLoginFormLabels({ title: 'Welcome' });
```

### Available Defaults & Merge Functions

| Component | Default | Merge Function |
|-----------|---------|---------------|
| **LoginForm** | `defaultLoginFormLabels` | `mergeLoginFormLabels` |
| | `defaultLoginFormColors` | `mergeLoginFormColors` |
| | `defaultLoginFormStyles` | `mergeLoginFormStyles` |
| | `defaultLoginFormIcons` | `mergeLoginFormIcons` |
| **RegisterForm** | `defaultRegisterFormLabels` | `mergeRegisterFormLabels` |
| | `defaultRegisterFormColors` | `mergeRegisterFormColors` |
| | `defaultRegisterFormStyles` | `mergeRegisterFormStyles` |
| | `defaultRegisterFormIcons` | `mergeRegisterFormIcons` |
| **TfaVerification** | `defaultTfaVerificationLabels` | `mergeTfaVerificationLabels` |
| | `defaultTfaVerificationColors` | `mergeTfaVerificationColors` |
| | `defaultTfaVerificationStyles` | `mergeTfaVerificationStyles` |
| | `defaultTfaVerificationIcons` | `mergeTfaVerificationIcons` |
| **PasswordResetRequest** | `defaultPasswordResetRequestLabels` | `mergePasswordResetRequestLabels` |
| | `defaultPasswordResetRequestColors` | `mergePasswordResetRequestColors` |
| | `defaultPasswordResetRequestStyles` | `mergePasswordResetRequestStyles` |
| | `defaultPasswordResetRequestIcons` | `mergePasswordResetRequestIcons` |
| **PasswordResetForm** | `defaultPasswordResetFormLabels` | `mergePasswordResetFormLabels` |
| | `defaultPasswordResetFormColors` | `mergePasswordResetFormColors` |
| | `defaultPasswordResetFormStyles` | `mergePasswordResetFormStyles` |
| | `defaultPasswordResetFormIcons` | `mergePasswordResetFormIcons` |
| **EmailVerification** | `defaultEmailVerificationLabels` | `mergeEmailVerificationLabels` |
| | `defaultEmailVerificationColors` | `mergeEmailVerificationColors` |
| | `defaultEmailVerificationStyles` | `mergeEmailVerificationStyles` |
| | `defaultEmailVerificationIcons` | `mergeEmailVerificationIcons` |
| **UserProfile** | `defaultUserProfileLabels` | `mergeUserProfileLabels` |
| | `defaultUserProfileColors` | `mergeUserProfileColors` |
| | `defaultUserProfileStyles` | `mergeUserProfileStyles` |
| | `defaultUserProfileIcons` | `mergeUserProfileIcons` |
| **DeviceManagement** | `defaultDeviceManagementLabels` | `mergeDeviceManagementLabels` |
| | `defaultDeviceManagementColors` | `mergeDeviceManagementColors` |
| | `defaultDeviceManagementStyles` | `mergeDeviceManagementStyles` |
| | `defaultDeviceManagementIcons` | `mergeDeviceManagementIcons` |
| **McpTokenManagement** | `defaultMcpTokenManagementLabels` | `mergeMcpTokenManagementLabels` |
| | `defaultMcpTokenManagementColors` | `mergeMcpTokenManagementColors` |
| | `defaultMcpTokenManagementStyles` | `mergeMcpTokenManagementStyles` |
| | `defaultMcpTokenManagementIcons` | `mergeMcpTokenManagementIcons` |
| **OAuthClientManagement** | `defaultOAuthClientManagementLabels` | `mergeOAuthClientManagementLabels` |
| | `defaultOAuthClientManagementColors` | `mergeOAuthClientManagementColors` |
| | `defaultOAuthClientManagementStyles` | `mergeOAuthClientManagementStyles` |
| | `defaultOAuthClientManagementIcons` | `mergeOAuthClientManagementIcons` |
| **AuthFlow** | `defaultAuthFlowLabels` | `mergeAuthFlowLabels` |
| | `defaultAuthFlowColors` | `mergeAuthFlowColors` |
| | `defaultAuthFlowStyles` | `mergeAuthFlowStyles` |

### Error Handling

All components accept an `onError` callback and also display errors inline with dismissible alerts:

```tsx
<LoginForm onError={(err) => analytics.track('login_error', { message: err.message })} />
```

### MUI sx Prop

All components accept the MUI `sx` prop for additional styling:

```tsx
<LoginForm sx={{ p: 4, border: '1px solid #e0e0e0' }} />
```

## Identity Bridge (CloudProvider Integration)

When `IdentityProvider` is mounted above `CloudProvider` (from `@hiyve/react-intelligence`) or `HiyveProvider` (from `@hiyve/react`), the authenticated user's email is automatically available to those providers. This allows cloud tokens to be generated for the correct user without passing `userId` manually.

```tsx
import { IdentityProvider } from '@hiyve/react-identity';
import { CloudProvider } from '@hiyve/react-intelligence';
import { HiyveProvider } from '@hiyve/react';

// Zero-config: IdentityProvider shares the user email,
// CloudProvider and HiyveProvider auto-generate cloud tokens.
function App() {
  return (
    <IdentityProvider>
      <CloudProvider>
        <HiyveProvider generateRoomToken={generateRoomToken}>
          <MyApp />
        </HiyveProvider>
      </CloudProvider>
    </IdentityProvider>
  );
}
```

## Requirements

- `IdentityProvider` must wrap all identity components and hooks
- `@hiyve/identity-client` must be installed as a peer dependency
- `@hiyve/react` must be installed as a peer dependency (for identity bridge context)
- MUI v5 or v6 with Emotion for component rendering
- `@hiyve/utilities` for avatar helpers in `UserProfile`
