---
title: "@microsoft/rayfin-embed-host"
description: "Parent-page SDK reference for brokering external Entra authentication into a Rayfin app embedded in an iframe."
url: https://rayfin.ai/docs/reference/sdk/rayfin-embed-host
markdown_url: https://rayfin.ai/docs/reference/sdk/rayfin-embed-host.md
section: reference
product: Rayfin
sdk_version: 1.36.2
cli_version: 1.36.2
applies_to: "@microsoft/rayfin-embed-host >= 1.36"
last_updated: 2026-10-03T17:23:06-07:00
source: reference/sdk/rayfin-embed-host.mdx
---

# @microsoft/rayfin-embed-host

> Parent-page SDK reference for brokering external Entra authentication into a Rayfin app embedded in an iframe.

[New in 1.36](/docs/reference/changelog#rayfin-136)

`@microsoft/rayfin-embed-host` is the parent-page SDK for embedding a Rayfin app in an iframe and brokering its external Entra authentication. The parent portal supplies a delegated Entra token; the iframe receives only a single-use handoff code.

## Installation [#installation]

```bash
npm install @microsoft/rayfin-embed-host
```

## Exports [#exports]

```typescript
export { createEmbedHost };
export { EmbedHostError };
export type {
  EmbedHost,
  EmbedHostErrorCode,
  EmbedHostOptions,
  HandoffProvider,
  HandoffRequest,
  HandoffResult,
};
```

`HandoffProvider` is a contributor extension seam, not a Builder-facing API.

## createEmbedHost [#createembedhost]

```typescript
function createEmbedHost(options: EmbedHostOptions): EmbedHost;
```

Registers a `message` listener in the parent window. Call it before mounting or navigating the Rayfin iframe because the embedded app sends its readiness message once.

```typescript
import { createEmbedHost } from '@microsoft/rayfin-embed-host';

const host = createEmbedHost({
  allowedOrigins: ['https://my-rayfin-app.example.com'],
  getAccessToken: () => acquireDelegatedEntraToken(),
});

host.dispose();
```

`createEmbedHost()` throws a Rayfin `SdkError` if called outside a browser environment.

## EmbedHostOptions [#embedhostoptions]

```typescript
interface EmbedHostOptions {
  allowedOrigins: string[];
  getAccessToken: () => string | Promise<string>;
  handoffProvider?: HandoffProvider;
}
```

| Option            | Type                              | Description                                                                                                                                                      |
| ----------------- | --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `allowedOrigins`  | `string[]`                        | Exact origins of embedded Rayfin apps this host will broker for. The same list gates the iframe sender origin and the return origin bound into the handoff code. |
| `getAccessToken`  | `() => string \| Promise<string>` | Returns the parent portal's delegated Entra access token. Called once per handoff request and never cached by the host.                                          |
| `handoffProvider` | `HandoffProvider`                 | Internal acquisition seam. Omit in application code.                                                                                                             |

Use origins only, such as `https://my-rayfin-app.example.com`. Do not include paths.

## EmbedHost [#embedhost]

```typescript
interface EmbedHost {
  dispose(): void;
}
```

`dispose()` removes the parent-window message listener and stops brokering handoffs. It is idempotent.

## Wire protocol behavior [#wire-protocol-behavior]

The host handles two message families on channel `fabric-auth`:

| Message               | Direction        | Purpose                                                                                                      |
| --------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------ |
| `externalEmbed.ready` | iframe to parent | One-shot readiness announcement.                                                                             |
| `externalEmbed.ack`   | parent to iframe | Scenario acknowledgement declaring `externalEmbed`.                                                          |
| `auth.requestHandoff` | iframe to parent | Correlated handoff request with PKCE challenge, return origin, brokered-authorize endpoint, and artifact ID. |
| `response`            | parent to iframe | Correlated success or error response.                                                                        |

The host ignores readiness and handoff messages from origins outside `allowedOrigins`. Handoff requests must come from the same window and origin that completed readiness.

## HandoffRequest and HandoffResult [#handoffrequest-and-handoffresult]

```typescript
interface HandoffRequest {
  brokeredAuthorizeUrl: string;
  artifactId: string;
  returnOrigin: string;
  codeChallenge: string;
  codeChallengeMethod: string;
  state?: string;
  getAccessToken: () => string | Promise<string>;
}

interface HandoffResult {
  handoffCode: string;
  state?: string;
}
```

The default provider posts to `brokeredAuthorizeUrl` with:

* `Authorization: Bearer <delegated Entra token>`
* `x-ms-workload-resource-moniker: <artifactId>`
* JSON body containing `returnOrigin`, PKCE challenge fields, and optional `state`

The delegated token is never sent over `postMessage`.

## EmbedHostError [#embedhosterror]

```typescript
type EmbedHostErrorCode =
  | 'EXCHANGE_NOT_ENABLED'
  | 'AUTH_FAILED'
  | 'INSUFFICIENT_PERMISSIONS'
  | 'NOT_AVAILABLE'
  | 'AUTHORIZE_FAILED'
  | 'VALIDATION_FAILED';

class EmbedHostError extends SdkError {
  readonly code: EmbedHostErrorCode;
}
```

| Code                       | Meaning                                                                                        |
| -------------------------- | ---------------------------------------------------------------------------------------------- |
| `EXCHANGE_NOT_ENABLED`     | The target app has not enabled external Entra exchange.                                        |
| `AUTH_FAILED`              | The delegated Entra token was rejected.                                                        |
| `INSUFFICIENT_PERMISSIONS` | The user lacks Execute permission on the item.                                                 |
| `NOT_AVAILABLE`            | The brokered-authorize endpoint is unavailable or wrong.                                       |
| `AUTHORIZE_FAILED`         | Network failure, malformed response, missing handoff code, or an unrecognized endpoint status. |
| `VALIDATION_FAILED`        | The handoff request failed host-side validation before any network call.                       |

Messages are safe to log and do not include the delegated token or raw response body.

## Default error messages [#default-error-messages]

| Code                                                                                                   | Message                                                       |
| ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------- |
| `VALIDATION_FAILED`                                                                                    | `returnOrigin is not permitted by the embed host.`            |
| `AUTHORIZE_FAILED`                                                                                     | `Failed to broker the authentication handoff.`                |
| `AUTHORIZE_FAILED`                                                                                     | `Failed to reach the brokered-authorize endpoint.`            |
| `AUTHORIZE_FAILED`                                                                                     | `Brokered-authorize endpoint returned a malformed response.`  |
| `AUTHORIZE_FAILED`                                                                                     | `Brokered-authorize endpoint returned no handoff code.`       |
| `EXCHANGE_NOT_ENABLED`, `AUTH_FAILED`, `INSUFFICIENT_PERMISSIONS`, `NOT_AVAILABLE`, `AUTHORIZE_FAILED` | `Brokered-authorize endpoint responded with status <status>.` |

## Browser requirements [#browser-requirements]

This package runs in a parent browser window. It uses `window.addEventListener('message', ...)`, `postMessage`, and `fetch`. It is not for Node.js.
