Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.wisdom.ai/llms.txt

Use this file to discover all available pages before exploring further.

The impersonateUser mutation exchanges a permanent access key for a short-lived JWT token that authenticates subsequent requests as a specific user. This is the core of the embedded session flow — the returned JWT is passed as the token query parameter in iframe embed URLs. This mutation is public and unauthenticated — no Authorization header is required.

Signature

impersonateUser(accessToken: String!, userEmail: String!, attributes: [UserAttributeInput!]): String!

Parameters

accessToken
String!
required
Your permanent Descope access key. This is not a JWT or a prior session token — it is the long-lived key obtained from support@askwisdom.ai. Must be kept secret and only used server-side.
userEmail
String!
required
The email address of the user to impersonate. The user must already exist in Wisdom — call createUsers first if needed.
attributes
[UserAttributeInput!]
Optional key-value pairs applied only for this session. These override DATABASE-sourced attributes for the duration of the session and are not persisted. Useful for passing context that should not be stored on the user (e.g., a specific report context or request-scoped filter).
The impersonated_user_id claim cannot be overridden via attributes.
See User Attributes for how attribute sources are prioritized.

Response

Returns a raw String! — the short-lived JWT to use as the token query parameter in iframe embed URLs. The token expires after 1 hour.
Never expose your permanent access key in client-side code. Always call this mutation from your server. See Embed a Chat and Dashboards for the secure server-side flow.

Usage example

mutation ImpersonateUser($accessToken: String!, $userEmail: String!) {
  impersonateUser(accessToken: $accessToken, userEmail: $userEmail)
}
curl -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "query": "mutation ImpersonateUser($accessToken: String!, $userEmail: String!) { impersonateUser(accessToken: $accessToken, userEmail: $userEmail) }",
    "variables": {
      "accessToken": "<your_access_key>",
      "userEmail": "alice@yourcompany.com"
    }
  }' \
  https://{ACCOUNT}.askwisdom.ai/graphql
{
  "data": {
    "impersonateUser": "eyJhbGciOiJSUzI1NiIsInR5..."
  }
}
Attributes that are stable for a given user (such as account_id) should be set permanently via createUsers or setUserAttributes. Attributes that change per session (such as a selected view or context) can be passed transiently via attributes here.

Token lifecycle and refresh

PropertyValue
Lifetime1 hour
RefreshVia postMessage (see below)
Priority?token= URL param always takes precedence over any cached token

Built-in refresh via postMessage

WisdomAI sends a REQUEST_JWT_TOKEN event to the parent window approximately 10 seconds before the embedded token expires. It is the embedder’s responsibility to listen for this event, regenerate the token by calling impersonateUser from their backend, and post it back. WisdomAI then picks up the new token and continues the session seamlessly. Flow:
  1. WisdomAI iframe detects the token is about to expire
  2. WisdomAI sends window.parent.postMessage({ type: 'REQUEST_JWT_TOKEN' }, '*') to the host
  3. Host receives the event and validates event.origin matches the WisdomAI domain
  4. Host calls impersonateUser via its own backend to get a fresh JWT
  5. Host posts back iframe.contentWindow.postMessage({ type: 'JWT_TOKEN_RESPONSE', token }, WISDOM_ORIGIN)
  6. WisdomAI receives the new token and refreshes the session
<iframe
  id="wisdom-frame"
  src="https://{ACCOUNT}.askwisdom.ai/embed/dashboards/<id>?token=<JWT>"
  style="width:100%;height:800px;border:0"
></iframe>

<script>
  const iframe = document.getElementById('wisdom-frame');
  const WISDOM_ORIGIN = 'https://{ACCOUNT}.askwisdom.ai';

  async function getFreshWisdomToken() {
    // Call your own backend, which calls impersonateUser with the access key
    const response = await fetch('/api/wisdom-token');
    const data = await response.json();
    return data.token;
  }

  window.addEventListener('message', async (event) => {
    if (event.origin !== WISDOM_ORIGIN) return;
    if (event.source !== iframe.contentWindow) return;
    if (event.data?.type !== 'REQUEST_JWT_TOKEN') return;

    try {
      const token = await getFreshWisdomToken();
      iframe.contentWindow.postMessage(
        { type: 'JWT_TOKEN_RESPONSE', token },
        WISDOM_ORIGIN
      );
    } catch (error) {
      console.error('Unable to provide WisdomAI token', error);
    }
  });
</script>
Implementation notes:
  • WisdomAI sends with '*' as target origin — the host must validate event.origin on its side
  • If the host does not respond within 10 seconds, the request times out and retries on the next render cycle
  • Only one refresh request is in-flight at a time (duplicate requests are suppressed)
  • The ?token= URL param always takes priority over any cached token

Embed a Dashboard

Use the token in an iframe embed URL

Embed a Chat

Use the token for embedded chat

Create Users

Create users before impersonating them

User Attributes

Understand transient vs persistent attributes

Session Management

Full token lifecycle reference, including switching users