Authentication
The SDK supports multiple authentication strategies through a unified AuthenticationService. Choose the strategy that fits your security requirements.
Authentication Types
| Type | Use Case | Requires Server |
|---|---|---|
anonymous | Public access, demos | No |
pre-auth | API keys, static tokens, server-provided tokens | No |
pkce | OAuth 2.0 browser flow | No |
client-credentials | Server-to-server | Yes |
Anonymous Authentication (Default)
When no auth configuration is provided, the SDK automatically uses anonymous authentication:
// These are equivalent:
const agent = new AiAgent({
id: "agent-id",
endpoint: "https://your-endpoint.com"
// No auth = anonymous session
});
const agent = new AiAgent({
id: "agent-id",
endpoint: "https://your-endpoint.com",
auth: { type: "anonymous" }
});Security Note
Anonymous authentication should only be used for public-facing agents. The agent configuration must allow anonymous access.
Pre-Auth Authentication
The most common authentication method. Use for API keys, static tokens, or server-provided JWTs.
To generate an access token, follow the instructions for Generating An Access Token using PKCE Flow.
Required scopes:
core.aiservices.readknowledge.portalmgr.managecore.customermgr.read(required for AI Agent for Customer Self Service only)
import { AiAgent } from "@egain/ai-agent-sdk";
const agent = new AiAgent({
id: "agent-id",
endpoint: "https://your-endpoint.com",
auth: {
type: "pre-auth",
accessToken: "your-access-token"
}
});
await agent.initialize();Server-Provided Tokens
When your server manages authentication:
const agent = new AiAgent({
id: "agent-id",
endpoint: "https://your-endpoint.com",
auth: {
type: "pre-auth",
accessToken: "token-from-your-server"
}
});With Token Refresh
Handle token expiration with a refresh function:
const agent = new AiAgent({
id: "agent-id",
endpoint: "https://your-endpoint.com",
auth: {
type: "pre-auth",
accessToken: initialToken,
refreshTokenFn: async () => {
// Called when token is about to expire
const response = await fetch("/api/refresh-token");
const { token } = await response.json();
return token;
}
}
});Access token refresh window
Anonymous, pre-auth, and PKCE strategies all treat an access token as stale five minutes before its JWT exp (anonymous refetches the client-credentials token; PKCE refreshes via MSAL; pre-auth schedules tokenExpiring and uses refreshTokenFn when provided).
Pre-auth hosts can override the schedule with expiryBufferMs on the auth config. Integrators can reuse the same default:
import {
ACCESS_TOKEN_REFRESH_BUFFER_MS,
ACCESS_TOKEN_REFRESH_BUFFER_MINUTES,
} from "@egain/ai-agent-sdk";Getting the Current Token
Retrieve the current access token for use in external API calls:
// Get the current access token
const token = await agent.getAccessToken();
if (token) {
// Use the token for external API calls
const response = await fetch('https://api.example.com/data', {
headers: {
Authorization: `Bearer ${token}`
}
});
}Manual Token Updates
Update the token at runtime:
// Listen for token expiring event
agent.on("tokenExpiring", async (event) => {
console.log("Token expiring:", event.payload.reason);
// Fetch new token from your server
const newToken = await fetchNewToken();
// Update the agent's token
await agent.updateAccessToken(newToken);
});PKCE Authentication (OAuth 2.0)
For browser-based OAuth 2.0 with PKCE:
const agent = new AiAgent({
id: "agent-id",
endpoint: "https://your-endpoint.com",
auth: {
type: "pkce",
config: {
authorizationUrl: "https://auth.example.com/authorize",
tokenUrl: "https://auth.example.com/token",
clientId: "your-client-id",
redirectUri: "https://your-app.com/callback",
scope: "openid profile" // optional
}
}
});PKCE Flow
- User initiates login
- SDK redirects to authorization URL with PKCE challenge
- User authenticates with identity provider
- Redirect back to your app with authorization code
- SDK exchanges code for tokens
CC / auto-built PKCE options (AiAgentConfig)
When you do not pass a full PKCEAuthConfig and the SDK builds PKCE settings from deployment info (typical contact center flows), these top-level AiAgent options apply:
| Option | Description |
|---|---|
authScheme | 'popup' (default) opens a login popup; 'redirect' sends the full page to the IdP. Logout uses the same scheme. |
initParams.scopes | Comma-separated scopes, used exactly as given: no defaults, no agent extraScopes, no platform augmentation. A host-supplied PKCEAuthConfig.scopes takes precedence over this. |
agentDetails.extraScopes | Scopes configured on the agent (admin console → Settings → Advanced), returned by the agent details API. Only on the SDK-managed path (no host-supplied scopes): appended (deduplicated) after the defaults / platform addCustomAuthScopes list, for the anonymous client-credentials token and the PKCE config the SDK builds. |
Scope resolution, first match wins:
- Host
PKCEAuthConfig.scopes(authenticated agents) — used as-is; the config is never modified. initParams.scopes— used as-is. Also fills a hostPKCEAuthConfigthat has noscopes.- SDK-managed: platform
addCustomAuthScopes(defaults)result if the connector provides it, else the defaults for the agent's user type (knowledge.portalmgr.manage,core.aiservices.read, pluscore.customermgr.readfor customers); the agent'sextraScopesare appended last.
The anonymous client-credentials token follows the same resolution, except that MSAL-qualified host PKCE scopes never apply to it.
PKCEAuthConfig extras
When you supply auth: { type: 'pkce', config: { ... } }, you can also use:
| Field | Description |
|---|---|
localLogin | When true, adds localLogin: 'true' to MSAL extra query parameters to force local login vs federated SSO |
nextRoute | Redirect-only return URL sent as OAuth state (hash stripped). Used after login and logout so auth-redirect.html can bounce back to the app. Popup omits state. |
Custom client id from init params
Host apps can pass egclientid (and related variants supported by the SDK) inside initParams so the built PKCE config uses your Azure AD / app registration client id instead of the deployment default.
An agent can also carry its own client id (clientAppId, set in the admin console under Settings → Advanced and returned by the agent details API). The built PKCE config picks the client id in this order: initParams.egclientid → agentDetails.clientAppId → deployment intClientId (agent) / extClientId (customer) / clientId. The anonymous client-credentials token is not affected by clientAppId.
Domain hint
When deployment info includes a domain hint, the SDK passes it as MSAL domain_hint to steer the IdP login experience.
Logout
AiAgent.logout() signs the user out of the identity provider for PKCE. It takes no options — the SDK uses the same authScheme as login.
await agent.logout();- Disconnects the chat WebSocket (
skipGracefulDisconnect; errors ignored). - Calls
AuthenticationService.logout(), which delegates to the strategy when it implementslogout(), then drops the cached access token.
| Scheme | What PKCE does |
|---|---|
popup | logoutPopup. Omits OAuth state. postLogoutRedirectUri is redirectUri?logout=true so auth-redirect.html can close the popup. The promise resolves when the popup finishes. |
redirect | logoutRedirect. state is hash-stripped nextRoute (else window.location.href) so auth-redirect.html can bounce back to the app. postLogoutRedirectUri is redirectUri as-is. The page navigates away; the promise does not settle. |
idTokenHint is taken from the active MSAL account. end_session_endpoint is stored on authority metadata when PKCE config is built (OIDC discovery, or {authority}/oauth2/v2.0/logout when the metadata omits it). If MSAL throws, logout falls back to the access-token JWT logout claim, then that endpoint.
MSAL clears its own cache. Do not call clearCache / removeAccount before logout() — popup logout still needs the account and id token.
Anonymous, pre-auth, and client-credentials strategies have no IdP logout. AuthenticationService.logout() still clears the cached token and returns.
Host UI state (Pinia/Vuex, localStorage isAuthenticated, eGain session DELETE) is not part of AiAgent.logout(). Clear those yourself: before logout() on redirect (the page is leaving), after it returns on popup.
Client Credentials (Server-to-Server)
For backend services:
const agent = new AiAgent({
id: "agent-id",
endpoint: "https://your-endpoint.com",
auth: {
type: "client-credentials",
config: {
tokenUrl: "https://auth.example.com/token",
clientId: "your-client-id",
clientSecret: "your-client-secret"
}
}
});Security Warning
Never expose client secrets in browser code. Use this strategy only in server-side applications.
Custom Authentication
Implement custom authentication by providing an AuthProvider:
import { AuthProvider, AiAgent } from "@egain/ai-agent-sdk";
class CustomAuth implements AuthProvider {
async getToken(): Promise<string> {
// Your custom token retrieval logic
const response = await fetch("/api/custom-auth");
const { token } = await response.json();
return token;
}
}
const agent = new AiAgent({
id: "agent-id",
endpoint: "https://your-endpoint.com",
auth: new CustomAuth()
});Full AuthStrategy Implementation
For complete control over the authentication lifecycle:
import { AuthStrategy } from "@egain/ai-agent-sdk";
class CustomAuthStrategy implements AuthStrategy {
private token: string | null = null;
async initialize(options?: { deploymentInfo?: any }): Promise<void> {
// Setup, e.g., load cached tokens
this.token = localStorage.getItem("auth_token");
}
async authenticate(): Promise<void> {
// Perform authentication
const response = await fetch("/api/authenticate");
const { token } = await response.json();
this.token = token;
}
async getToken(): Promise<string | null> {
return this.token;
}
async cleanup(): Promise<void> {
// Cleanup resources
this.token = null;
}
// Optional on AuthStrategy. PKCE implements IdP logout via MSAL; omit if you have no IdP session.
async logout(): Promise<void> {}
}Best Practices
1. Never Hardcode Credentials
// ❌ Bad
auth: { type: "pre-auth", accessToken: "sk-abc123..." }
// ✅ Good
auth: { type: "pre-auth", accessToken: process.env.AI_AGENT_TOKEN }2. Use Environment-Appropriate Strategies
const auth = typeof window !== "undefined"
? { type: "pkce", config: pkceConfig } // Browser
: { type: "client-credentials", config: ccConfig }; // Server3. Handle Token Expiration
agent.on("tokenExpiring", async (event) => {
try {
const newToken = await refreshToken();
await agent.updateAccessToken(newToken);
} catch (error) {
// Handle refresh failure (e.g., redirect to login)
window.location.href = "/login";
}
});4. Secure Token Storage
// Browser: Use secure, httpOnly cookies managed by your server
// Node.js: Use environment variables or secret managers