# Authentication and identity

Management API credentials and widget customer identity solve different problems.
Keep management keys and provider secrets on a trusted backend.

## Organization API keys

Create a key for the intended organization in the dashboard's developer settings.
Use the permissions needed for the integration. The current organization API
verifies keys sent in `X-API-Key`; an organization key is not a Bearer session token.
Every organization operation requires an `orgId` matching the key's organization.
A successful schema request does not prove permission to read or mutate resources.

A server-side read against the supported REST endpoint:

```ts
const apiKey = process.env.MASHEEV_API_KEY;
const orgId = process.env.MASHEEV_ORG_ID;
if (!apiKey || !orgId) throw new Error("Configure MASHEEV_API_KEY and MASHEEV_ORG_ID");

const url = new URL("https://api.masheev.com/api/rpc/inboxes");
url.searchParams.set("orgId", orgId);
const response = await fetch(url, {
  headers: { "X-API-Key": apiKey },
  signal: AbortSignal.timeout(10_000),
});
if (!response.ok) throw new Error(`Masheev request failed: ${response.status}`);
const { inboxes } = await response.json();
```

Use the [OpenAPI reference](https://docs.masheev.com/api-reference.md) for exact endpoint paths, inputs and
outputs. Validate access with a read before provisioning. Do not log authorization
headers or a full response containing customer information.

## Browser sessions

The dashboard uses Better Auth sessions. Browser session APIs are appropriate only
when the user is signed in to Masheev and the deployment's cookie/origin behavior
supports it. Signing into your own application does not create a Masheev session.
Do not put a management key in client JavaScript to work around this difference.

## Signed widget identity

An inbox ID is public configuration. The inbox's HMAC secret is private.
Generate `userHash` on your backend from the authenticated application user's ID:

```ts
import { createHmac } from "node:crypto";

// authenticatedUser must come from your server's existing session validation.
const userHash = createHmac("sha256", inboxSecret)
  .update(authenticatedUser.id)
  .digest("hex");
```

Pass `userId` and `userHash` in the SDK's `user` configuration. The signature
endpoint must derive the user from the session, not trust an arbitrary submitted ID.
Only include profile fields needed for support. Test logout and account switching
so the next user cannot see the previous user's conversation.

## Secret placement

| Value | Where it belongs |
| --- | --- |
| Inbox ID | Public widget configuration |
| Turnstile site key, when required | Public headless/widget configuration |
| Organization API key | Backend environment or secret store |
| Inbox HMAC secret | Backend environment or secret store |
| Provider access tokens | Existing backend/provider connection |

Use placeholder names in `.env.example`. Never prefix a management key with a
framework's public environment prefix. See [API client](https://docs.masheev.com/api-client.md) for known
server transport limitations and [MCP](https://docs.masheev.com/mcp.md) for its separate authentication path.
