> Legacy approach
>
> For new integrations, use the [Widget SDK with Access Key Embed](https://docs.returning.ai/widget-sdk/auth-access-key.md).

## Migrating to Access Key Embed

Use this migration checklist before changing an installed integration. The following token-auth changes do not establish drop-in compatibility for every old loader, widget ID or bundle. Ask Returning.AI to confirm the supplied setup, including permitted legacy maintenance and support scope; retained documentation is not a support deadline.

If you are currently using `auth-url` token auth, here is what changes:

- **Endpoint:** Replace your `POST /widget/{id}/signin` call with `POST /v2/api/widget-access-keys/token`.
- **Attribute:** Replace `auth-url` with `embed-token` on the widget tag.
- **Refresh:** Legacy `auth-url` can auto-refresh using refresh tokens. Access Key Embed does not call your backend for a new `embed-token`; fetch a fresh token and update the attribute. The SDK watches this attribute (added in 1.4.2); use the current release 1.8.11, with reload as an older-build fallback.

See the [Access Key guide](https://docs.returning.ai/widget-sdk/auth-access-key.md) for the full walkthrough.

1. **Inventory the installation.** Record the actual loader and SDK versions, widget ID, URL, rendering mode, public attributes, callbacks, listeners/storage, identity mapping and credential dependencies. Store secret values separately.
2. **Confirm the replacement.** Obtain the approved widget ID and matching bundle URL. Copy IDs unchanged; do not translate old attributes or recreate users by guessing. Have the setup owner confirm which configuration and user history must carry across.
3. **Prove the same-user journey before cutover.** Confirm usable membership, identity, saved state and the expected widget view. Test logout/account switch and the bundle's display refresh separately from token renewal.
4. **Confirm cleanup and rollback before cutover.** Identify exactly how the old loader releases its listeners, callbacks and owned storage. Keep only one active host integration as a default, not as proof that the two implementations are compatible. Do not clear unrelated browser storage.
5. **Keep a usable return path.** Save the approved prior configuration and verify its identity/credential dependencies still work. A revoked credential or changed mapping can invalidate rollback; never restore compromised credentials. Unknown cleanup, continuity or rollback dependencies stop cutover until the responsible owner supplies evidence.
6. **Record approval and switch.** Name the cutover owner, pause condition and verified rollback action in the [handover decision gates](https://docs.returning.ai/broker-integrations/launch-checklist.md#decision-gates). Referral integrations also need their [relationship and qualification checks](https://docs.returning.ai/broker-integrations/referrals.md).

Rendering and authentication are separate choices. Confirm Access Key and iframe compatibility for the actual supplied widget/version before retaining iframe mode; this checklist does not certify an unknown legacy loader.

# Auth - Token

Sign users in server-side so the widget loads pre-authenticated. The user never sees a login screen - the token is fetched behind the scenes before the widget renders.

## Attribute auth vs token auth

|  | Attribute authentication | Token authentication |
| --- | --- | --- |
| User identity | Client-side via data-* attributes (email, userId, etc.) | Server-verified via API key |
| Backend required | No | Yes |
| Token flow | None - attributes passed directly | Your backend calls Returning.AI, returns a short-lived token |
| User experience | Seamless - user identified by attributes | Seamless - already signed in |
| Best for | Quick integrations, internal tools, controlled environments | Logged-in areas, client portals, trader dashboards |

## Step 1 - Create a backend endpoint

Your server calls the Returning.AI sign-in API with your secret API key and the current user's email. It receives a short-lived token that the SDK will use to authenticate the widget session.

> Keep your API key server-side
>
> Never expose `WIDGET_API_KEY` in client-side code. It should only exist in environment variables on your backend.

**Node.js**

`server.js`

```javascript
app.post('/api/widget-auth', async (req, res) => {
  const response = await fetch(
    'https://prod-widgets.returning.ai/widget/{community_id}/signin',
    {
      method: 'POST',
      headers: {
        'returningai-api-key': process.env.WIDGET_API_KEY,
        'email': req.user.email,
        'Content-Type': 'application/json',
      },
    }
  )
  const data = await response.json()
  res.json({ token: data.token })
})
```

## Step 2 - Point the widget to your endpoint

Add the `auth-url` attribute to your widget tag. The SDK will POST to that URL on load, receive the token, and authenticate automatically.

```html
<rai-channel-widget
  community-id="YOUR_COMMUNITY_ID"
  widget-url="YOUR_WIDGET_URL"
  auth-url="/api/widget-auth"
></rai-channel-widget>
```

> How the flow works
>
> 1. Widget mounts and detects the `auth-url` attribute.
> 2. SDK sends a POST request to your backend endpoint.
> 3. Your backend verifies the user and calls the Returning.AI sign-in API.
> 4. Your backend returns the token to the SDK.
> 5. SDK passes the token into the widget iframe - the user is signed in.

## Token expiry and refresh

Tokens are short-lived (typically around 5 minutes). The SDK handles renewal automatically - when a token is about to expire, it re-calls your `auth-url` endpoint to fetch a fresh one. No extra code is needed on your side.

If the refresh fails (e.g. the user's session has expired on your backend), the widget fires an `rai-error` event that you can listen for to prompt re-authentication.
