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

# Tenant embedding guide

> External integration guide for embedding Narrative SDK widgets into tenant applications.

<Info>
  Use this page for embedded runtime implementation details after you choose embedded auth as your integration pattern. For authentication pattern selection across embedded, standalone, and API auth, use [Authentication](/sdk/authentication). For parameter-by-parameter definitions, defaults, and validation rules, use [Configuration reference](/sdk/configuration).
</Info>

<Tip>
  Need brand alignment? Use [Configuration reference](/sdk/configuration#ui-theme-customisation) to customise font and theme colours from your host app.
</Tip>

## What you need before you embed

<Columns cols={3}>
  <Card title="Frontend host page" icon="https://mintcdn.com/narrative-b13c445c/qi6sqKB_OLTe8ty2/SVG/frontend-shell.svg?fit=max&auto=format&n=qi6sqKB_OLTe8ty2&q=85&s=13c676d362a2a3a7a60bfa0fae245ad6" width="64" height="64" data-path="SVG/frontend-shell.svg">
    A page in your tenant application where you can load the SDK script and render a mount container.
  </Card>

  <Card title="Backend token route" icon="https://mintcdn.com/narrative-b13c445c/qi6sqKB_OLTe8ty2/SVG/lock.svg?fit=max&auto=format&n=qi6sqKB_OLTe8ty2&q=85&s=be29c8f389110e9dd5032501c0e8f00b" width="64" height="64" data-path="SVG/lock.svg">
    A backend endpoint that can mint short-lived Embed Tokens for the currently authenticated tenant user.
  </Card>

  <Card title="Connected App setup" icon="https://mintcdn.com/narrative-b13c445c/qi6sqKB_OLTe8ty2/SVG/link-handoff.svg?fit=max&auto=format&n=qi6sqKB_OLTe8ty2&q=85&s=710c716f96a2cf04ebe7fa38257b5ea1" width="64" height="64" data-path="SVG/link-handoff.svg">
    A provisioned Connected App with a client id and secret that match the token-signing configuration on your backend.
  </Card>
</Columns>

## Scope of this guide

This guide only covers embedded Narrative SDK boot and runtime decisions.

* For the end-to-end embedded integration path, use [SDK integration](/sdk/integration).
* For Azure AD OIDC sign-in or request-level API token handling, use [Authentication guide](/sdk/api-auth).
* For token lifecycle and auth pattern comparison, use [Authentication](/sdk/authentication).

## Required configuration

| Value                           | Where it is used    | Why it matters                                     |
| ------------------------------- | ------------------- | -------------------------------------------------- |
| `NSDK_BASE_URL`                 | Tenant frontend     | Loads `nsdk-loader.js` from the hosted SDK origin. |
| `NSDK_CONNECTED_APP_CLIENT_ID`  | Tenant backend      | Used as JWT `iss` when minting the Embed Token.    |
| `NSDK_CONNECTED_APP_SECRET_KEY` | Tenant backend only | Signs the Embed Token with HS256.                  |

<Note>
  The full field-level reference for these values lives in [Configuration reference](/sdk/configuration).
</Note>

<Steps>
  <Step title="Load the SDK loader">
    ```html Loader script theme={null}
    <script>
      (function (w, d, s, u, n) {
        w[n] = w[n] || function () {
          ;(w[n].q = w[n].q || []).push(arguments)
        }
        var js = d.createElement(s)
        js.async = true
        js.src = u
        d.head.appendChild(js)
      })(window, document, 'script', '<NSDK_BASE_URL>/nsdk-loader.js', 'NSDK')
    </script>
    ```
  </Step>

  <Step title="Add a widget container">
    <CodeGroup>
      ```html Static HTML theme={null}
      <div id="nsdk-container" data-nsdk="true" data-nsdk-widget="insights"></div>
      ```

      ```tsx React theme={null}
      <div id="nsdk-container" data-nsdk="true" data-nsdk-widget="insights" />
      ```
    </CodeGroup>
  </Step>

  <Step title="Fetch and set Embed Token">
    ```js Browser theme={null}
    const { embed_token } = await fetch('/your-embed-token-endpoint').then((r) => r.json())
    const container = document.getElementById('nsdk-container')
    container?.setAttribute('data-nsdk-token', embed_token)
    ```
  </Step>
</Steps>

## Runtime decisions

<AccordionGroup>
  <Accordion title="When should the frontend fetch the Embed Token?">
    Fetch it only after the tenant app has already established its own authenticated user session. The Embed Token should represent the current tenant user, not an anonymous browser session.
  </Accordion>

  <Accordion title="Should you use declarative or imperative boot?">
    Use declarative boot when you have a stable host page and container. Use imperative boot when your application needs to control mount timing, page transitions, or cleanup explicitly.
  </Accordion>

  <Accordion title="How long should the Embed Token live?">
    Keep it short-lived. The current guidance is 5-15 minutes, with `iat` and `exp` expressed in Unix seconds.
  </Accordion>

  <Accordion title="What makes a token valid?">
    It must be JWT + HS256, use `aud = nsdk-embed`, include the required claims (`iss`, `sub`, `aud`, `iat`, `exp`, `jti`), and include `nsdk.user.name` plus `nsdk.user.email`.
  </Accordion>
</AccordionGroup>

## Minimal implementation flow

```mermaid theme={null}
sequenceDiagram
  participant App as Tenant app
  participant Backend as Tenant backend
  participant NSDK as Narrative SDK

  App->>Backend: Request Embed Token for current user
  Backend-->>App: Short-lived Embed Token
  App->>NSDK: Load loader + set token on container
  NSDK-->>App: Render embedded widget
```

## Security checklist

<Warning>
  Keep connected app secrets server-side only. Do not expose token signing logic in browser code.
</Warning>

<Columns cols={3}>
  <Card title="No browser signing" icon="https://mintcdn.com/narrative-b13c445c/qi6sqKB_OLTe8ty2/SVG/lock.svg?fit=max&auto=format&n=qi6sqKB_OLTe8ty2&q=85&s=be29c8f389110e9dd5032501c0e8f00b" width="64" height="64" data-path="SVG/lock.svg">
    Never expose the Connected App secret or JWT signing logic to frontend code.
  </Card>

  <Card title="Short-lived token handoff" icon="https://mintcdn.com/narrative-b13c445c/qi6sqKB_OLTe8ty2/SVG/timer.svg?fit=max&auto=format&n=qi6sqKB_OLTe8ty2&q=85&s=218100a8011939edb626ef3480a13724" width="64" height="64" data-path="SVG/timer.svg">
    Do not store Embed Tokens in browser local storage. Treat them as short-lived bootstrap credentials.
  </Card>

  <Card title="Transport and access controls" icon="https://mintcdn.com/narrative-b13c445c/qi6sqKB_OLTe8ty2/SVG/server.svg?fit=max&auto=format&n=qi6sqKB_OLTe8ty2&q=85&s=4a767cfdcb6585e74810e5c286495132" width="64" height="64" data-path="SVG/server.svg">
    Use HTTPS, strict origin or CSP controls, and validate tenant user authorisation before minting each token.
  </Card>
</Columns>

## Optional imperative mode

```js Browser theme={null}
NSDK('boot', {
  widgets: [{ type: 'insights' }],
  mount: '#nsdk-container',
  embedToken: '<EMBED_TOKEN>'
})

NSDK('destroy')
```

## Validation and troubleshooting

<AccordionGroup>
  <Accordion title="The SDK script loads but the widget does not render">
    Check that the container exists before boot, `data-nsdk="true"` is present for declarative mode, and the token has been set on the container before the SDK initializes.
  </Accordion>

  <Accordion title="The token endpoint works but NSDK rejects the token">
    Recheck `iss`, `aud`, `iat`, `exp`, and the HS256 signing secret. Audience mismatches and milliseconds-vs-seconds timestamps are the most common causes.
  </Accordion>

  <Accordion title="The frontend cannot fetch the token route">
    Prefer a same-origin token endpoint. If that is not possible, configure CORS explicitly for the tenant frontend origin and any required credentials flow.
  </Accordion>

  <Accordion title="Need the full parameter reference">
    Use [Configuration reference](/sdk/configuration) for field-by-field definitions and [Authentication](/sdk/authentication) for token and session lifecycle behaviour.
  </Accordion>
</AccordionGroup>

<Info>
  For the complete troubleshooting guide covering all common integration issues, see [Troubleshooting](/sdk/troubleshooting). For common questions, see [FAQ](/sdk/faq).
</Info>
