ruLog in to Senler

Website user authorization for MCP

This guide is for a website developer: a user already has an external service token, and the agent needs to call an installed MCP with that user's permissions. The website backend saves the token in Senler, and signed widget initialization binds it to the correct lead.

Choose how to call methods

TaskApproach
Execute a JavaScript handler on the visitor's open pageCustom Actions with returnsResult: true; the handler uses the website's authorization.
Supply an existing user token to an MCP installed from a templateThe external-user-credentials methods described below.
Give a custom MCP a verified lead identitySigned lead authorization; the server verifies the Senler JWT and maps the user and their permissions itself.

“Call a user's API as tools” can refer to different approaches. Determine where the call should run — in a browser handler or on the MCP server — and which authorization data that server accepts.

Prepare the connection

You need a project, its Widget channel, and an MCP installed from a template in the same project with per-lead authorization (auth_mode: lead). Connect this MCP to the agent that answers visitors. The manual-token example requires a template supporting that authorization method. An arbitrary custom MCP URL is not supported by the credential storage methods.

On the website backend, prepare a Senler project API key or OAuth access token with can_manage_mcp_servers permission. Determine the external ID from the user's authenticated server session. If you supply an existing lead_id, first verify that it belongs to that user, channel, and project.

ValuePurpose
Senler API tokenAllows the backend to save or revoke credentials. Sent in the HTTP Authorization header.
External service user tokenAllows the MCP to act on behalf of the user. Sent in secret_payload.
external_user_id / user.external_idThe same website user ID in the server request and widget initialization.
user_hashAn HMAC signature of the external ID that verifies the visitor's identity.

user_hash neither contains nor issues an external service token. The backend obtains that token through the service's sign-in or OAuth flow, then saves it using the method below. The Senler API token, external token, and channel secret stay on the backend; the widget needs only the external ID and its completed signature.

Save the token from the backend

Call POST https://api.senler.io/api/mcp-servers/external-user-credentials. The method creates or replaces credentials for the combination of project, channel, external user, and installed MCP. Example for a template using a manual Bearer token:

POST /api/mcp-servers/external-user-credentials HTTP/1.1
Host: api.senler.io
Authorization: Bearer <SENLER_API_TOKEN>
Content-Type: application/json

{
  "project_id": "<PROJECT_ID>",
  "channel_id": "<WIDGET_CHANNEL_ID>",
  "external_user_id": "user-123",
  "mcp_server_id": "<INSTALLED_MCP_SERVER_ID>",
  "credential_type": "bearer",
  "auth_method": "manual",
  "secret_payload": {
    "access_token": "<USER_MCP_TOKEN>"
  }
}

Replace the values in angle brackets. project_id, channel_id, and mcp_server_id are Senler resource UUIDs. mcp_server_id identifies the installed project connection, not a template ID or MCP address. Pass the token value itself in access_token, without Bearer.

All seven fields in the example are required. The template determines the secret_payload format: a manual token or OAuth uses access_token; custom headers use their exact names as keys. For example, {"X-Session-Id":"<SESSION_VALUE>"} with credential_type: "custom" if the template requires that header. auth_method: "oauth" requires an OAuth-capable template and already obtained OAuth credentials; this request does not start user sign-in itself.

Optional fields:

FieldWhen to supply it
lead_idThe lead already exists and credentials should be synchronized with it immediately.
expires_atThe credential expiration time is known; an ISO 8601 string.
source_session_idAssociates the binding with the integration's server session; Senler stores a hash of this value. Supplying it does not connect your website's logout events automatically.
connected_identityPublic details about the connected account; an object with required type, such as {"type":"account","external_id":"user-123"}.

On success, the HTTP status is 200. The JSON contains project_id, channel_id, external_user_id, mcp_server_id, has_credential: true, auth_method, and validation information: validation_status, validation_error, validated_at. The response does not return the secret. Saved credentials do not yet mean that this MCP is assigned to the agent or that the binding has been synchronized with a lead.

Bind the user to the widget

After saving credentials successfully, sign the same ID on the backend:

import { createHmac } from "node:crypto";

const externalId = "user-123";
const userHash = createHmac("sha256", channelSecret)
  .update(externalId)
  .digest("hex");

channelSecret is the secret of this widget channel. See user identity configuration for how to obtain it. Send only externalId and userHash to the browser, then initialize the widget:

SenlerWidget.init({
  channel_id: "<WIDGET_CHANNEL_ID>",
  user: {
    external_id: externalId,
    user_hash: userHash,
  },
});

During verified initialization, Senler finds or creates the lead and synchronizes the saved credentials for this external user with it. The installed MCP assigned to the agent can then use them for calls in that lead's context. The token is not sent in a chat message or agent instruction.

If the widget is already initialized and the lead is known, add its lead_id to the server-side save request. This triggers synchronization immediately. Without lead_id, synchronization happens during the next verified initialization; saving credentials alone does not reinitialize an open widget.

Renew the token

Repeat POST /api/mcp-servers/external-user-credentials with the same project_id, channel_id, external_user_id, and mcp_server_id, and the new secret_payload. Update expires_at if needed. Supply lead_id to apply it immediately to an existing lead; otherwise the next verified initialization is required.

Replacing credentials revokes the previous active binding and its linked lead copies. Handle save or synchronization errors before continuing protected actions.

Revoke access

When disconnecting the integration or signing the user out, if access should stop, the backend calls POST https://api.senler.io/api/mcp-servers/external-user-credentials/revoke with the same Senler API token and can_manage_mcp_servers permission:

POST /api/mcp-servers/external-user-credentials/revoke HTTP/1.1
Host: api.senler.io
Authorization: Bearer <SENLER_API_TOKEN>
Content-Type: application/json

{
  "project_id": "<PROJECT_ID>",
  "channel_id": "<WIDGET_CHANNEL_ID>",
  "external_user_id": "user-123",
  "mcp_server_id": "<INSTALLED_MCP_SERVER_ID>"
}

All four fields are required. Successful response: HTTP 200, {"success":true}. Senler revokes the active binding and its linked lead credential copies. This stops use of the saved credentials in Senler; revocation of the token itself at the external provider uses that provider's facilities.

If a call fails

  • Check the Senler API token and can_manage_mcp_servers permission in the correct project.
  • Confirm that the MCP is installed from a template, belongs to the project, and uses lead mode.
  • Match auth_method and the secret_payload keys to the template's supported authorization methods.
  • Check the external token's expiration and the validation result when saving it.
  • For initialization-time binding, use matching external_user_id and user.external_id, the correct channel, and a signature made with its secret.

Current method schemas are available in the public API reference. Saving credentials successfully does not bypass permission checks at the external service.