# Skydda en assistent med din egen inloggning via callbackUrl

`callbackUrl` är fältet du använder när en coreAI-assistent ska vara tillgänglig endast för inloggade användare i ditt eget system. När fältet är satt kontaktar coreAI din egen URL med användarens token innan chattwidgeten initialiseras, och bara användare som din endpoint godkänner med HTTP 200 får tala med assistenten. Inloggningen, sessionen och användardatabasen stannar hos dig – coreAI äger inte logiken för vem som är vem.

## När du bör använda callbackUrl

Använd `callbackUrl` när assistenten svarar på data som inte ska vara offentlig: kundportaler, intranät, anställdadokument eller flerkundlösningar där varje användare bara ska se sitt eget. Det typiska upplägget är att användaren loggar in hos dig, du embeddar coreAI-widgeten på en skyddad sida, och widgeten skickar med en token (din egen sessions-ID, en JWT, en signerad engångskod – det du redan använder) som coreAI verifierar mot din endpoint innan chatten startar.

Om assistenten ska svara alla som besöker en öppen sida behöver du inte `callbackUrl`. Lämna fältet tomt.

## Två sätt att skicka token

`callbackUrl` stöder två format, och coreAI väljer metod utifrån hur URL:en är skriven:

- **`{TOKEN}` i URL:en.** Skriv `https://mitt-system.se/validate?token={TOKEN}` så byter coreAI platshållaren mot användarens token och anropar URL:en med GET (faller tillbaka till POST om GET ger 404). Platshållaren kan stå var som helst i URL:en, även i sökvägen: `https://mitt-system.se/validate/{TOKEN}` fungerar också.
- **Bearer-header.** Skriv en fast URL utan `{TOKEN}`, till exempel `https://mitt-system.se/api/validate`. coreAI anropar då URL:en med POST och lägger till `Authorization: Bearer <token>` (faller tillbaka till GET om POST ger 404).

Välj det som är enklast att bygga in i din befintliga auth-stack. Bearer-varianten passar bäst när du redan har ett JSON-API som validerar tokens; URL-varianten är enklast när validatorn är en fristående endpoint.

## Så svarar din endpoint

Din endpoint måste svara HTTP 200 med en JSON-kropp för att släppa igenom användaren. Allt annat – 401, 403, 500, nätverksfel – tolkas som avslag, och widgeten initialiseras inte. Om svaret innehåller fältet `status` måste värdet vara `"success"`; allt annat avvisar även om statuskoden är 200.

JSON-svaret kan också returnera ett eller flera `external_id`:

```json
{
  "status": "success",
  "external_id": ["customer-4711", "department-sales"]
}
```

När fältet finns låser coreAI samtalet till de datakällor som matchar dessa `external_id` i assistentens kunskapsbas. Det är denna mekanism som gör flerkundsportaler praktiska: en assistent, en kunskapsbas, men varje användare får bara se sina egna ordrar, sin egen organisations dokument, sitt eget innehåll. Du bestämmer scopingen i din egen endpoint – coreAI läser bara resultatet.

## Vad som stängs av automatiskt

Så snart en assistent har en `callbackUrl` satt stänger coreAI av tre ytor som annars skulle kringgå kontrollen:

- **Offentlig sökdemo** – sökendpointen för opublicerade demoträffar svarar 403.
- **Direktlänk till widgeten** – den delbara URL:en som öppnar widgeten ensam i webbläsaren returnerar 403.
- **MCP-exponering** – assistenten registreras inte som ett MCP-verktyg för AI-agenter.

Det finns ingen väg runt callbacken när den väl är satt. Om du vill exponera något offentligt igen måste du ta bort `callbackUrl` eller skapa en separat assistent för den öppna ytan.

## Varför kontrollen körs en gång per widget-laddning

Token valideras när widgeten initialiseras – alltså en gång per sidladdning – och inte för varje fråga användaren ställer eller varje meddelande som strömmas tillbaka. Det är ett medvetet val. Att validera på nytt för varje chattanrop skulle lägga nätverkslatens från din endpoint mellan varje fråga och varje svar, men inte ge någon reell säkerhetsvinst: åtkomsten till assistenten avgörs redan av att widgeten laddades i en autentiserad session. En komprometterad session hos dig skulle släppas igenom oavsett hur ofta coreAI frågade.

I praktiken betyder det att din endpoint får en HTTP-förfrågan per gång en användare öppnar sidan assistenten ligger på. Det är en realistisk last att bygga för, även för endpoints som gör tunga lookups mot din databas.