Authenticated Chat (Intranet)

Publish the agent inside your intranet, customer portal or web system: the chat automatically recognizes the logged-in user, without asking them to log in again.

Intranet

What it is

The Authenticated Chat (Intranet) is a way to publish the agent inside a platform where users are already logged in, like an intranet, a customer portal, a web system or an ERP.

The chat automatically recognizes who the user is, without asking them to log in again, and keeps each person’s conversation history separate and secure.


1. When to use

Publishing optionWhen to use
Public (link or website)Open websites and landing pages. Any visitor can talk to the agent.
Intranet (authenticated access)Systems where the user has already logged in to your platform. The chat inherits their identity (name, email and ID from your system).
Shared login and passwordRestricted websites where you want to protect the chat with a shared password.

Use Intranet mode when you want:

  • The conversation to start already knowing who the user is (no identification form);
  • The conversation history to be tied to the user’s ID in your system;
  • No one to be able to impersonate another user or see someone else’s conversation.

2. Creating the connection

  1. Open the project, click AI Agent Robots in the side menu and open the agent.
  2. Click the Channels tab.
  3. Click Add channel. If the agent doesn’t have any connections yet, the list of channels shows up right away.
  4. In the Web group, choose Authenticated web (intranet) and click Select.
  5. In Destination and access, click Continue. The platform lets you know that an intranet connection will be created.
  6. In Configuration, fill in:
    • Connection name: an internal name so you can recognize it later, like “Customer Portal”;
    • Allowed domains (optional): the websites where the chat can run, one per line.
  7. Click Create connection.

On the “Connection created” screen, click Manage connection and complete instructions. Unlike the other modes, the intranet has no ready-to-paste code: the credentials and examples are on the connection page.

⚠️ Heads up: creating the connection doesn’t publish a version of the agent. Until a version is published, the chat answers with the current draft. See how to publish in Your First Agent.


3. What the platform shows in the connection

To get back to the connection later, open the Channels tab, find the connection under Your connections and click Manage.

3.1 Code examples

In Installation, choose what to copy:

  • Backend (your server): the call your server makes to authenticate each user;
  • Frontend (browser): the code that opens the chat on the page with the token returned by your backend.

Both already come with your project’s Project ID. They correspond to integration Mode A. There are two ways to put the chat on your platform, explained in section 5.

3.2 Integration secret

In Credentials and actions, the Integration secret (intranet) block holds the connection’s secret key. It’s what your platform’s server uses to authenticate users in the chat. The secret is hidden: click Reveal secret to see and copy it, and Hide when you’re done. In the code examples, it shows up as SEU_SECRET_TOKEN.

⚠️ Never put the secret in browser code (HTML or JavaScript). It should only live in your application’s backend. If it leaks, anyone could generate access on behalf of your users.


4. How everything connects

┌─────────────────────┐   1. logged-in user    ┌──────────────────────┐
│  User on your       │ ─────────────────────▶ │  Your platform's     │
│  platform           │                        │  backend             │
└─────────────────────┘                        └──────────┬───────────┘
                                                          │ 2. POST /intranet-auth
                                                          │    (secret + user data)
                                                          ▼
                                               ┌──────────────────────┐
                                               │  Caramelo API        │
                                               │  → checks the secret │
                                               │  → creates or finds  │
                                               │    the contact       │
                                               │  → returns the token │
                                               └──────────┬───────────┘
                                                          │ 3. real_time_access_token (24h)
                                                          ▼
                                               ┌──────────────────────┐
                                               │  Your HTML page      │
                                               │  gets the token and  │
                                               │  loads the script    │
                                               └──────────┬───────────┘
                                                          │ 4. chat opens already identified
                                                          ▼
                                               ┌──────────────────────┐
                                               │  Chat with that      │
                                               │  user's history      │
                                               └──────────────────────┘

In summary:

  1. The user logs in normally on your platform;
  2. Your backend calls the Caramelo API with the integration secret and the user’s data;
  3. The API returns a temporary token unique to that user (the real_time_access_token field);
  4. Your page receives this token and passes it to the chat script (the secure_connection_token parameter);
  5. The chat opens already identified, with that person’s conversation history.

📌 Heads up: one token, two names.

Where it shows upName used
In the API response (your backend receives it)real_time_access_token
In the chat script (your page sends it)secure_connection_token

It’s the same value: your backend receives real_time_access_token and your page passes it to the script as secure_connection_token. Throughout this guide, whenever you see secure_connection_token, read it as “the real_time_access_token the API returned”.

💡 Tip: generate the token on every page load, because it expires in 24 hours. Don’t reuse old tokens or share the same token between different users.


5. The two integration modes

There are two ways to put the authenticated chat on your platform. Both use the same script (sdk/latest/client.js) and the same intranet-auth call on the backend. What changes is how the token reaches the chat:

Mode A: injected token (SSR)Mode B: on demand (async)
Who fetches the tokenYour backend, when rendering the pageThe chat script itself, by calling an endpoint on your backend
When the chat opensAutomatically, when the page loadsWhen the page calls .start()
Does the token show up in the HTML?Yes, injected into the pageNo, it only travels in your endpoint’s response
Best forServer-rendered websites (PHP, WordPress, templates, Next.js SSR)React apps or SPAs, cached or CDN pages, opening the chat only when a button is clicked

🤔 Not sure which to choose? If your page is generated on the server on every request, use Mode A (simpler). If your application runs in the browser (React, Vue, Angular) or you want to control when the chat opens, use Mode B.

5.1 Mode A: token injected by the server (SSR)

Step 1 (backend): when rendering the page, your server calls the Caramelo API with the logged-in user’s data:

curl -X POST https://api.carameloai.com/api/chatbox/project/SEU_PROJECT_ID/intranet-auth \
  -H "Authorization: Bearer SEU_SECRET_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "external_customer_id": "user-123",
    "name": "User Name",
    "email": "user@example.com"
  }'
FieldDescription
external_customer_idRequired. The user’s unique ID in your system. It’s what links the conversation history.
nameThe user’s name (shown to the support team).
emailThe user’s email.

Step 2 (frontend): your server injects the returned token into the page’s HTML, along with the chat script:

<!-- Caramelo AI chatbot (intranet) -->
<script src="https://static.carameloai.com/sdk/latest/client.js"></script>
<script>
  window.CarameloChatbot
    .create({
      secure_connection_token: 'TOKEN_RETORNADO_PELO_SEU_BACKEND',
      project_id: 'SEU_PROJECT_ID'
    })
    .start();
</script>

The script loads and opens the chat automatically, already identified.

📌 Already installed with the old code? The previous format, with var carameloaiChatbot and the prod/index.js script, keeps working.

5.2 Mode B: on demand (async)

┌──────────────────┐  1. opens the page  ┌───────────────────────────┐
│  Logged-in user  │ ──────────────────▶ │  Page loads client.js     │
└──────────────────┘                     │  (nothing shows up yet)   │
                                         └────────────┬──────────────┘
                                                      │ 2. chat.start()
                                                      ▼
                                         ┌───────────────────────────┐
                                         │  SDK makes a POST to YOUR │
                                         │  endpoint (same origin)   │
                                         └────────────┬──────────────┘
                                                      │ 3. your backend calls
                                                      │    intranet-auth (with the secret)
                                                      ▼
                                         ┌───────────────────────────┐
                                         │  Browser gets the token   │
                                         │  → chat opens identified  │
                                         └───────────────────────────┘

Step 1 (backend): create an endpoint on your domain, like /api/chatbot-token. It identifies the logged-in user through the session, calls intranet-auth and returns the token:

// Node.js / Express example
app.post('/api/chatbot-token', async (req, res) => {
  const user = req.user; // user already authenticated on YOUR platform
  if (!user) {
    return res.status(401).json({ error: 'unauthenticated' });
  }

  const response = await fetch(
    'https://api.carameloai.com/api/chatbox/project/SEU_PROJECT_ID/intranet-auth',
    {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer SEU_SECRET_TOKEN', // never exposed to the browser
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        external_customer_id: user.id,
        name: user.name,
        email: user.email
      })
    }
  );

  const data = await response.json();
  res.json({ real_time_access_token: data.real_time_access_token });
});

Step 2 (frontend): create the chat pointing to your endpoint, with autoStart: false, and start it whenever you want:

<script src="https://static.carameloai.com/sdk/latest/client.js"></script>
<script>
  var chat = window.CarameloChatbot.create(
    {
      project_id: 'SEU_PROJECT_ID',
      auth_endpoint: '/api/chatbot-token', // endpoint on YOUR domain
      on_error: function (err) {
        console.error('Failed to start the chat', err);
      }
    },
    { autoStart: false }
  );

  // The chat only opens when you tell it to, for example on a button click:
  document.getElementById('open-chat').addEventListener('click', function () {
    chat.start();
  });
</script>

If you already use the old format, with var carameloaiChatbot and CarameloChatbotClient.start(), it keeps working.

DirectionDetails
SDK → your endpointPOST <auth_endpoint>, with no body. The user is identified by your system’s session
Your endpoint → Caramelo APIPOST /api/chatbox/project/{PROJECT_ID}/intranet-auth with Bearer + user data
Your endpoint → SDKJSON with at least { "real_time_access_token": "..." }

6. Adjusting the appearance

In Manage, the Settings and Advanced sections have the same options as the Public Chat: balloon position, compact mode, keep chat open, fixed container, timing and allowed domains. See what each one does in the Public Chat guide. Click Save after making changes.


7. Frequently asked questions

Does the user need to log in again in the chat?

No. Their identity is passed securely by your backend, and the chat opens already knowing who they are.

My application is React/SPA. Which mode should I use?

Mode B. In the browser there's no way to hide the integration secret, so the chat calls an endpoint on your own backend, which handles the authentication securely.

Can I open the chat only when the user clicks a button?

Yes. Use Mode B and call chat.start() on the click.

What happens if the token expires?

The token lasts 24 hours. Just generate a new one on the next page load (Mode A) or on the next start() call (Mode B).

Can I use the same connection in several systems?

Yes, but we recommend creating one connection, with its own secret, for each system or environment. That makes it easier to control and revoke access.

What if the secret leaks?

Delete the connection in Manage > Danger zone > Delete connection and create a new one. The new connection comes with a different secret.