# Server Integration

Your server is the secure bridge between the Hiyve SDK running in the browser and the Hiyve platform. It generates tokens, proxies identity requests, and keeps your API credentials out of client-side code.

This guide covers everything you need to connect your backend to Hiyve.

---

## Credential Types

Hiyve uses two credential types, each with a different purpose:

| Credential | Prefix | Purpose | Where to use |
|-----------|--------|---------|--------------|
| **API Key** | `pk_live_*` / `pk_test_*` | Identifies your app. Used for cloud token generation and identity proxy. | Server-side (always). Client-side only for identity-only apps via `@hiyve/identity-client`. |
| **Client Secret** | `sk_live_*` / `sk_test_*` | Generates room tokens for WebRTC connections. | Server-side only. **Never expose in client code.** |

**When do you need each?**

- **All apps** need an API key (`pk_*`).
- **Video conferencing apps** also need a client secret (`sk_*`) to generate room tokens.
- **Identity-only apps** (login, register, profile management) only need the API key. No backend server or client secret is required — use `@hiyve/identity-client` or `@hiyve/react-identity` directly in the browser.

---

## What the Server Does

The Hiyve SDK needs three types of tokens, all of which must be generated server-side:

| Token | Purpose | Endpoint |
|-------|---------|----------|
| **Room token** | Authenticates WebRTC connections to the signaling server | `POST /generate-room-token` |
| **Cloud token** | Authenticates AI and cloud service requests | `POST /generate-cloud-token` |
| **Join token** | Creates shareable invite links for rooms | `POST /create-join-token` |

Your API key (`APIKEY`) and client secret (`CLIENT_SECRET`) are used to generate these tokens. They must never appear in browser code.

> **Identity-only apps** don't need a server or these token endpoints. If your app only uses identity authentication (login/register), you can use `@hiyve/identity-client` directly in the browser with just your API key. See [Credential Types](#credential-types) above.

---

## Quick Setup

Install the server package:

```bash
npm install @hiyve/admin express cors dotenv
```

Create a `.env` file:

```env
# API Key (required — identifies your app)
APIKEY=pk_live_xxx

# Client Secret (required for video conferencing — generates room tokens)
CLIENT_SECRET=sk_live_xxx

# Server Configuration (optional — defaults shown)
SERVER_REGION=us-west-2
SERVER_REGION_URL=.rtc.muziemedia.com
ENVIRONMENT=development
```

Replace `pk_live_xxx` and `sk_live_xxx` with the values from your [developer console](https://console.hiyve.dev).

Create `server.js`:

```javascript
import 'dotenv/config';
import express from 'express';
import cors from 'cors';
import { mountHiyveRoutes, loadHiyveConfig } from '@hiyve/admin';

const app = express();
app.use(cors({ origin: ['http://localhost:5173'] }));
app.use(express.json());

const apiRouter = express.Router();
mountHiyveRoutes(apiRouter, loadHiyveConfig());
app.use('/api', apiRouter);

app.listen(3001, () => console.log('Server running on http://localhost:3001'));
```

`mountHiyveRoutes` registers the following endpoints on your router:

| Method | Path | Description |
|--------|------|-------------|
| POST | `/generate-room-token` | Generate a token for joining a WebRTC room |
| POST | `/generate-cloud-token` | Generate a token for AI cloud services |
| POST | `/generate-note` | Generate AI-powered meeting notes |
| POST | `/create-join-token` | Create a shareable invite token |
| GET | `/health` | Health check (returns config status, region, uptime) |
| ALL | `/hiyve/identity/*` | Identity proxy (forwards to Hiyve Cloud) |

Since the router is mounted at `/api`, the full paths become `/api/generate-room-token`, `/api/generate-cloud-token`, and so on.

---

## Environment Variables

| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `APIKEY` | Yes | -- | API key from [console.hiyve.dev](https://console.hiyve.dev) (starts with `pk_live_` or `pk_test_`) |
| `CLIENT_SECRET` | For video | -- | Client secret (starts with `sk_live_` or `sk_test_`). Required for room token generation. Not needed for identity-only apps. |
| `SERVER_REGION` | No | `us-west-2` | Region identifier for the signaling server |
| `SERVER_REGION_URL` | No | `.rtc.muziemedia.com` | Region URL suffix |
| `ENVIRONMENT` | No | `development` | `'production'` or `'development'` |

`loadHiyveConfig()` reads these from `process.env` and returns a `HiyveServerConfig` object.

---

## Token Flow

### Room Tokens (WebRTC)

Room tokens authenticate the client with the Hiyve signaling server for WebRTC connections.

```
Browser                         Your Server                    Hiyve Platform
  |                                |                                |
  |  createRoom('room', 'user')   |                                |
  | -----------------------------> |                                |
  |  POST /api/generate-room-token|                                |
  |                                |  POST /room-token              |
  |                                |  { apiKey, secret }            |
  |                                | -----------------------------> |
  |                                |                                |
  |                                |  { roomToken, region, ... }    |
  |                                | <----------------------------- |
  |  { roomToken, region,          |                                |
  |    serverRegionUrl }           |                                |
  | <----------------------------- |                                |
  |                                                                 |
  |  Connect WebSocket with token                                   |
  | --------------------------------------------------------------> |
```

By default, `HiyveStore` (and therefore `HiyveProvider`) POSTs to `/api/generate-room-token` when you call `createRoom()`. If your server mounts the Hiyve routes at `/api`, this works with zero configuration on the client side.

### Cloud Tokens (AI Features)

Cloud tokens authenticate requests to the Hiyve Cloud API for AI intelligence, meeting summaries, alerts, and other cloud features.

```
Browser                         Your Server                    Hiyve Cloud
  |                                |                                |
  |  POST /api/generate-cloud-token|                               |
  |  { userId }                    |                                |
  | -----------------------------> |                                |
  |                                |  POST /cloud-token             |
  |                                |  X-Hiyve-Api-Key: pk_live_xxx  |
  |                                |  { expiresIn, userId }         |
  |                                | -----------------------------> |
  |                                |                                |
  |                                |  { cloudToken }                |
  |                                | <----------------------------- |
  |  { cloudToken, environment }   |                                |
  | <----------------------------- |                                |
```

`HiyveProvider` configures a default cloud token generator that POSTs to `/api/generate-cloud-token`. The token is requested automatically the first time a cloud API call is made (e.g., when using AI features or when the presence heartbeat starts). No client configuration is needed if your server uses the default route paths.

### Join Tokens (Invite Links)

Join tokens create shareable links that allow others to join a room without needing credentials.

The client sends `{ userId, roomName }` (and optionally `type` and `expiresIn`) to `POST /api/create-join-token`. The server first obtains a room token, then requests a join token from the signaling server, returning `{ joinToken, roomRegion }`.

---

## Custom Token Endpoints

If your server uses different paths than the defaults, override the token generation functions on the client.

### React

```tsx
<HiyveProvider
  generateRoomToken={async () => {
    const res = await fetch('/my-api/room-token', { method: 'POST' });
    const data = await res.json();
    return data.roomToken;
  }}
  generateCloudToken={async ({ userId }) => {
    const res = await fetch('/my-api/cloud-token', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ userId }),
    });
    const data = await res.json();
    return { cloudToken: data.cloudToken, environment: data.environment };
  }}
>
  <App />
</HiyveProvider>
```

`generateRoomToken` must return a string (the room token). `generateCloudToken` must return either a string or an object with `{ cloudToken, environment }`.

### Framework-Agnostic (HiyveStore)

```typescript
import { HiyveStore } from '@hiyve/core';

const store = new HiyveStore({
  generateRoomToken: async () => {
    const res = await fetch('/my-api/room-token', { method: 'POST' });
    const data = await res.json();
    return data.roomToken;
  },
});
```

---

## Individual Handlers

If you need to mount handlers on custom paths or mix them with your own routes, use `createHiyveHandlers` instead of `mountHiyveRoutes`:

```typescript
import express from 'express';
import { createHiyveHandlers, loadHiyveConfig } from '@hiyve/admin';

const app = express();
app.use(express.json());

const handlers = createHiyveHandlers(loadHiyveConfig());

app.post('/api/room-token', handlers.roomToken);
app.post('/api/cloud-token', handlers.cloudToken);
app.post('/api/join-token', handlers.joinToken);
app.post('/api/note', handlers.generateNote);
app.get('/api/health', handlers.health);
app.all('/api/identity/*', handlers.identityProxy);
```

When using custom paths, remember to update the client-side `generateRoomToken` and `generateCloudToken` callbacks to match (see [Custom Token Endpoints](#custom-token-endpoints)).

You can also create handlers individually with the factory functions:

```typescript
import {
  createRoomTokenHandler,
  createCloudTokenHandler,
  createNoteHandler,
  createHealthHandler,
  loadHiyveConfig,
} from '@hiyve/admin';

const config = loadHiyveConfig();
app.post('/api/room-token', createRoomTokenHandler(config));
app.post('/api/cloud-token', createCloudTokenHandler(config));
app.post('/api/note', createNoteHandler(config));
app.get('/api/health', createHealthHandler(config));
```

Note: `createJoinTokenHandler` and `createIdentityProxyHandler` are not available as individual factory functions. They are only accessible through `createHiyveHandlers()` or `mountHiyveRoutes()`.

---

## Authentication Middleware

`createAuthMiddleware` verifies end-user access tokens (issued by `@hiyve/identity-client`) against Hiyve Cloud. Use it to protect your own API routes.

### Protected Routes

```typescript
import express from 'express';
import { createAuthMiddleware, loadHiyveConfig } from '@hiyve/admin';

const app = express();
const config = loadHiyveConfig();
const auth = createAuthMiddleware(config);

app.get('/api/me', auth, (req, res) => {
  // req.hiyveUser is populated after successful verification
  res.json({ user: req.hiyveUser });
});
```

`req.hiyveUser` contains:

| Field | Type | Description |
|-------|------|-------------|
| `id` | `string` | User ID |
| `email` | `string` | Email address |
| `name` | `string?` | Display name |
| `emailVerified` | `boolean?` | Whether the email is verified |
| `metadata` | `Record<string, unknown>?` | Custom metadata set during registration |
| `createdAt` | `string?` | Account creation timestamp |

If the `Authorization` header is missing or the token is invalid, the middleware responds with `401 Unauthorized`.

### Optional Authentication

For routes that work for both authenticated and anonymous users:

```typescript
const optionalAuth = createAuthMiddleware(config, { optional: true });

app.get('/api/data', optionalAuth, (req, res) => {
  if (req.hiyveUser) {
    // Authenticated user — return personalized data
    res.json({ greeting: `Hello, ${req.hiyveUser.name}` });
  } else {
    // Anonymous — return public data
    res.json({ greeting: 'Hello, guest' });
  }
});
```

### Middleware Options

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `optional` | `boolean` | `false` | Allow unauthenticated requests (`req.hiyveUser` is `null`) |
| `cacheTtlMs` | `number` | `300000` | Token verification cache duration (5 minutes) |
| `cacheMaxSize` | `number` | `1000` | Maximum number of cached token verifications |

The middleware caches successful verifications to reduce latency. Adjust `cacheTtlMs` for security-sensitive applications where you need faster token revocation.

---

## Email Verification and TFA Configuration

Hiyve Identity supports two independent security features that you can enable or disable per-organization:

| Feature | Org Setting | Default | Description |
|---------|-------------|---------|-------------|
| **Email Verification** | `settings.emailVerificationRequired` | `true` | Require new users to verify their email before they can use the app |
| **Two-Factor Authentication** | `settings.tfa.enabled` | `true` | Require OTP verification on unrecognized devices during login |

Both features are controlled at the **organization level** (per brand org). You can use them independently -- TFA without email verification, email verification without TFA, both, or neither.

### Platform Defaults (Hiyve Cloud Environment Variables)

When a new tenant registers, their brand org inherits defaults from the Hiyve Cloud deployment:

| Variable | Default | Description |
|----------|---------|-------------|
| `IDENTITY_EMAIL_VERIFICATION_REQUIRED` | `true` | Default `emailVerificationRequired` for new orgs |
| `IDENTITY_TFA_ENABLED` | `true` | Default `tfa.enabled` for new orgs |

Set these in your Hiyve Cloud `.env` to change what new tenants get by default:

```env
# Example: TFA enabled, but no email verification for new tenants
IDENTITY_EMAIL_VERIFICATION_REQUIRED=false
IDENTITY_TFA_ENABLED=true
```

### Per-Organization Override

Individual tenants can override these settings on their own org after creation via the admin API:

```bash
# Disable email verification for a specific org
PUT /admin/identity/orgs/:orgId
{
  "settings.emailVerificationRequired": false
}

# Disable TFA for a specific org
PUT /admin/identity/orgs/:orgId
{
  "settings.tfa.enabled": false
}
```

### How It Works

**Email Verification (`emailVerificationRequired`):**
- When `true`: New users are created with `emailVerified: false`. A verification email is sent with a link. The `EmailVerification` component (or `auth.verifyEmail()`) completes verification.
- When `false`: New users are created with `emailVerified: true`. No verification email is sent. Users can log in immediately after registration.

**TFA (`tfa.enabled`):**
- When `true`: Login from unrecognized devices triggers an email OTP challenge. The SDK handles this automatically via the `tfaRequired` response and `verifyTfa()` method. Once verified, the device is trusted for 90 days (configurable via `settings.tfa.trustedDeviceTTL`).
- When `false`: All logins return tokens directly, no OTP step.

### Common Configurations

| Use Case | Email Verification | TFA | Notes |
|----------|-------------------|-----|-------|
| Maximum security | `true` | `true` | Users verify email, then TFA on each new device |
| TFA only (no email verification) | `false` | `true` | Users can log in immediately; TFA protects against credential theft |
| Email verification only | `true` | `false` | Ensures valid email; no OTP step |
| Minimal friction | `false` | `false` | No verification steps; suitable for internal/testing apps |

### Client-Side Behavior

The `@hiyve/react-identity` `AuthFlow` component and `@hiyve/identity-client` SDK adapt automatically:

- If TFA is disabled, `login()` never returns `tfaRequired: true` -- the TFA UI is never shown.
- If email verification is disabled, `register()` returns `emailVerified: true` in the user object -- you can skip the verification pending screen.
- If email verification is enabled, show the `EmailVerification` component or direct users to check their email after registration.

```tsx
// Example: skip verification screen when not required
<RegisterForm
  onSuccess={(user) => {
    if (user.emailVerified) {
      navigate('/login');       // Can log in immediately
    } else {
      navigate('/check-email'); // Show verification pending screen
    }
  }}
/>
```

---

## Identity Proxy

The `ALL /hiyve/identity/*` route proxies browser requests to Hiyve Cloud's identity service. This is what enables `@hiyve/identity-client` and `@hiyve/react-identity` to handle user registration, login, two-factor authentication, and session management -- without exposing your API key to the browser.

The proxy automatically:

- Injects your `APIKEY` as the `X-Hiyve-Api-Key` header on every upstream request
- Forwards these headers from the client: `Authorization`, `X-Hiyve-Device-Id`, `X-Hiyve-Device-Fingerprint`, `X-Csrf-Token`, `Content-Type`
- Forwards `Set-Cookie` headers from the upstream response back to the browser
- Supports all HTTP methods (GET, POST, PUT, DELETE)

If you use `mountHiyveRoutes`, the identity proxy is registered automatically. If you use individual handlers, mount it as:

```typescript
app.all('/api/hiyve/identity/*', handlers.identityProxy);
```

Configure `@hiyve/identity-client` on the client side to point at your proxy:

```typescript
import { HiyveAuth } from '@hiyve/identity-client';

const auth = new HiyveAuth({
  baseUrl: '/api/hiyve/identity',
});
```

---

## CORS Configuration

### Express CORS

In development, allow your frontend origin:

```javascript
import cors from 'cors';

app.use(cors({
  origin: ['http://localhost:5173'],
  credentials: true,
}));
```

In production, restrict to your actual domains:

```javascript
app.use(cors({
  origin: ['https://myapp.com', 'https://staging.myapp.com'],
  credentials: true,
}));
```

### Hiyve Cloud Allowed Origins

Hiyve Cloud also validates the `Origin` header on identity requests. Use `AdminClient` to configure which origins are allowed for your organization:

```typescript
import { AdminClient } from '@hiyve/admin';

const admin = new AdminClient({
  secretKey: process.env.HIYVE_SECRET_KEY,
  environment: 'production',
});

// Replace all allowed origins
await admin.setAllowedOrigins('org_abc123', [
  'https://myapp.com',
  'https://staging.myapp.com',
]);

// Add origins without removing existing ones
await admin.addAllowedOrigins('org_abc123', ['https://new-app.com']);

// Remove specific origins
await admin.removeAllowedOrigins('org_abc123', ['https://old-app.com']);

// List current origins
const { origins } = await admin.listAllowedOrigins('org_abc123');
```

---

## CI/CD: Registry Authentication

To install `@hiyve/*` packages in CI environments, create a project-level `.npmrc` with environment variable expansion:

```ini
@hiyve:registry=https://api.hiyve.dev/registry/
//api.hiyve.dev/registry/:_authToken=${HIYVE_API_KEY}
```

Then set `HIYVE_API_KEY` in your CI environment:

- **GitHub Actions**: Add to repository secrets, reference as `${{ secrets.HIYVE_API_KEY }}`
- **GitLab CI**: Add as a CI/CD variable (masked)
- **AWS CodeBuild**: Store in AWS SSM Parameter Store or Secrets Manager

The `.npmrc` file is safe to commit -- it contains no actual secrets, only the variable reference.

---

## AdminClient (Profile Management)

`AdminClient` authenticates with a secret key (`sk_live_*` or `sk_test_*`) and provides server-side access to manage user profiles, organizations, and allowed origins.

```typescript
import { AdminClient } from '@hiyve/admin';

const admin = new AdminClient({
  secretKey: process.env.HIYVE_SECRET_KEY,
  environment: 'production',
});

// List profiles for your organization
const result = await admin.listProfiles('org_abc123', {
  limit: 20,
  search: 'john',
});

// Get a single profile
const profile = await admin.getProfile('profile_123', 'org_abc123');

// Update a profile
await admin.updateProfile('profile_123', 'org_abc123', {
  name: 'John Smith',
  metadata: { department: 'Engineering' },
});

// Deactivate a profile
await admin.deactivateProfile('profile_123', 'org_abc123');
```

For the full `AdminClient` API reference, see the [`@hiyve/admin` README](https://sdk.hiyve.dev/hiyve-components/latest/readmes/admin.md).

---

## Next.js Integration

Next.js API routes work the same way. Create a route handler that uses the individual handler factories:

```typescript
// app/api/generate-room-token/route.ts
import { createRoomTokenHandler, loadHiyveConfig } from '@hiyve/admin';

const handler = createRoomTokenHandler(loadHiyveConfig());

export async function POST(request: Request) {
  const body = await request.json();

  // Adapt Next.js Request/Response to Express-compatible shape
  let statusCode = 200;
  let responseBody: unknown;

  const req = { body, headers: Object.fromEntries(request.headers) };
  const res = {
    status(code: number) { statusCode = code; return this; },
    json(data: unknown) { responseBody = data; },
  };

  await handler(req, res);
  return Response.json(responseBody, { status: statusCode });
}
```

For a complete working example, see the [Next.js Example](https://github.com/hiyve/hiyve-examples/tree/main/nextjs-example).

---

## Summary

| What you need | How to set it up |
|---------------|------------------|
| Room tokens for WebRTC | `mountHiyveRoutes` or `handlers.roomToken` |
| Cloud tokens for AI features | `mountHiyveRoutes` or `handlers.cloudToken` |
| Join tokens for invite links | `mountHiyveRoutes` or `handlers.joinToken` |
| Identity auth (login, registration) | Identity proxy via `mountHiyveRoutes` |
| Protected API routes | `createAuthMiddleware` |
| CORS for Hiyve Cloud | `AdminClient.setAllowedOrigins()` |
| CI/CD registry access | `.npmrc` with `${HIYVE_API_KEY}` |

The fastest path: use `mountHiyveRoutes` with `loadHiyveConfig()` and the default client behavior handles the rest.
