Skip to content

Auth - Access Key

The recommended way to authenticate widgets. Your backend exchanges access credentials for a short-lived JWT, which is injected into the widget tag as an HTML attribute. No persistent auth endpoint needed.

When to use

  • Logged-in portals and trader dashboards where you know the user server-side.
  • Any integration where server-verified identity is important.
  • Bundle mode (native DOM rendering) for the best performance and CSS integration.

Step 1 - Get access credentials

In the Returning.AI admin panel, generate an accessId and accessKey pair. Store them in your server's environment variables - they must never be exposed to the client.

Step 2 - Create a backend endpoint

Your server calls the Access Key API with your accessId and accessKey. The response returns a short-lived embed token at data.embedToken. End-user identity is still provided separately on the widget element via configured data-* attributes.

server.js
app.get('/api/widget-token', async (req, res) => {
  const response = await fetch(
    'https://api-v2.returning.ai/v2/api/widget-access-keys/token',
    {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        accessId: process.env.RAI_ACCESS_ID,
        accessKey: process.env.RAI_ACCESS_KEY,
      }),
    }
  )
  const json = await response.json()
  const embedToken = json.data?.embedToken
  if (!embedToken) throw new Error('Missing embed token')

  res.json({ embedToken })
})

Step 3 - Inject the token into the page

Your server renders the widget tag with the embed-token attribute set to the token from Step 2. The SDK validates that token in the browser as an access gate, then continues startup using the configured user identifiers on the widget element.

Step 4 - Add the widget

Add the widget tag with embed-token and bundle-url attributes. The bundle-url enables bundle mode (recommended) where the widget renders directly in the page DOM instead of an iframe.

<rai-store-widget
  community-id="YOUR_COMMUNITY_ID"
  api-url="https://prod-widgets.returning.ai"
  v2-api-url="https://api-v2.returning.ai"
  embed-token="TOKEN_FROM_YOUR_SERVER"
  domain-key="PROD"
  data-user-id="USER_ID"
  data-user-objectid="USER_OBJECT_ID"
  data-username="USERNAME"
  bundle-url="https://prod-widgets.returning.ai/store-widget/bundle/widget.js"
  theme="dark"
  width="100%"
  height="600px"
></rai-store-widget>

Bundle mode

When bundle-url is set, the widget renders in the light DOM (no iframe). Your page CSS cascades into the widget, scrolling is native, and performance is better. Omit bundle-url to fall back to iframe mode if you need CSS isolation.

Token lifecycle

Access Key tokens are short-lived JWTs that expire after 15 minutes. The SDK does not call your backend to mint a fresh embed-token automatically. For long-lived views, your app must fetch a new embed token, update the attribute, and reload the widget.

ScenarioStrategy
Server-rendered pagesToken generated per page load. 15 minutes is plenty for most page sessions.
SPAsRe-fetch the token from your backend on route navigation. Each view gets a fresh token.
Long-lived sessions (>15 min on one view)Listen for the rai-error event, re-fetch a token from your backend, update the embed-token attribute, and call window.ReturningAIWidget.reload().

Handling token expiry in long-lived sessions

If a user stays on the same page for more than 15 minutes, the token will expire. Use this pattern to recover automatically:

token-refresh.js
const widget = document.querySelector('rai-store-widget')

widget.addEventListener('rai-error', async (e) => {
  console.warn('Widget token expired, refreshing...')

  // Re-fetch a fresh token from your backend
  const res = await fetch('/api/widget-token')
  const { token } = await res.json()

  // Update the attribute and reload
  widget.setAttribute('embed-token', token)
  await window.ReturningAIWidget.reload()
})