New protocol version released: This page may contain outdated information.
 
Secure your HAIP applications with robust JWT authentication. Learn how to implement token-based security, manage authentication state, and follow security best practices for production deployments.
The HAIP SDK uses JWT (JSON Web Token) Bearer token authentication for secure communication with HAIP servers.
JWT Authentication
HAIP uses standard JWT tokens with the following structure:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
 
Token Components
A JWT token consists of three parts:
- Header: Contains the algorithm and token type
 
- Payload: Contains claims (user data, permissions, etc.)
 
- Signature: Verifies the token’s authenticity
 
Example Token Payload
{
  "sub": "user123",
  "name": "John Doe",
  "iat": 1516239022,
  "exp": 1516242622,
  "permissions": ["read", "write"],
  "haip": {
    "channels": ["USER", "AGENT"],
    "max_runs": 10
  }
}
 
Setting Up Authentication
Basic Authentication
import { createHAIPClient } from "haip-sdk";
const client = createHAIPClient({
  url: "ws://localhost:8080",
  token: "your-jwt-token-here",
  transport: "websocket",
});
 
Environment Variables
Store your authentication token securely using environment variables:
# .env
HAIP_SERVER_URL=ws://localhost:8080
HAIP_AUTH_TOKEN=your-jwt-token-here
 
import { createHAIPClient } from "haip-sdk";
const client = createHAIPClient({
  url: process.env.HAIP_SERVER_URL!,
  token: process.env.HAIP_AUTH_TOKEN!,
  transport: "websocket",
});
 
Dynamic Token Management
For applications that need to refresh tokens or use different tokens:
class AuthenticatedClient {
  private client: any;
  private tokenProvider: () => Promise<string>;
  constructor(url: string, tokenProvider: () => Promise<string>) {
    this.tokenProvider = tokenProvider;
    this.client = null;
  }
  async connect() {
    const token = await this.tokenProvider();
    this.client = createHAIPClient({
      url: "ws://localhost:8080",
      token,
      transport: "websocket",
    });
    await this.client.connect();
  }
  async refreshToken() {
    if (this.client) {
      await this.client.disconnect();
    }
    await this.connect();
  }
}
// Usage
const client = new AuthenticatedClient("ws://localhost:8080", async () => {
  // Fetch fresh token from your auth service
  const response = await fetch("/api/auth/token");
  const { token } = await response.json();
  return token;
});
 
Token Validation
Parsing JWT Tokens
Use the SDK’s utility functions to parse and validate tokens:
import { HAIPUtils } from "haip-sdk";
// Parse token payload
const payload = HAIPUtils.parseJWT(token);
console.log("Token payload:", payload);
// Check expiration
const now = Math.floor(Date.now() / 1000);
if (payload.exp && payload.exp < now) {
  console.log("Token has expired");
}
 
Token Validation Example
function validateToken(token: string): boolean {
  try {
    const payload = HAIPUtils.parseJWT(token);
    // Check expiration
    const now = Math.floor(Date.now() / 1000);
    if (payload.exp && payload.exp < now) {
      return false;
    }
    // Check required claims
    if (!payload.sub) {
      return false;
    }
    // Check HAIP-specific claims
    if (payload.haip) {
      if (payload.haip.channels && !Array.isArray(payload.haip.channels)) {
        return false;
      }
    }
    return true;
  } catch (error) {
    console.error("Token validation failed:", error);
    return false;
  }
}
 
Error Handling
Authentication Errors
Handle authentication-related errors:
client.on("error", (error: Error) => {
  if (error.message.includes("AUTHENTICATION_FAILED")) {
    console.log("Authentication failed - check your token");
    // Attempt to refresh token
    refreshToken();
  } else if (error.message.includes("TOKEN_EXPIRED")) {
    console.log("Token has expired - refreshing...");
    refreshToken();
  } else if (error.message.includes("INSUFFICIENT_PERMISSIONS")) {
    console.log("Insufficient permissions for this operation");
  }
});
 
Token Refresh Strategy
Implement automatic token refresh:
class TokenManager {
  private refreshThreshold = 5 * 60 * 1000; // 5 minutes
  private refreshPromise: Promise<string> | null = null;
  constructor(private tokenProvider: () => Promise<string>) {}
  async getValidToken(): Promise<string> {
    const token = await this.tokenProvider();
    const payload = HAIPUtils.parseJWT(token);
    const now = Math.floor(Date.now() / 1000);
    const expiresIn = payload.exp ? (payload.exp - now) * 1000 : Infinity;
    if (expiresIn < this.refreshThreshold) {
      return this.refreshToken();
    }
    return token;
  }
  private async refreshToken(): Promise<string> {
    if (this.refreshPromise) {
      return this.refreshPromise;
    }
    this.refreshPromise = this.tokenProvider();
    try {
      const token = await this.refreshPromise;
      return token;
    } finally {
      this.refreshPromise = null;
    }
  }
}
 
Security Best Practices
Token Storage
✅ Secure Storage Methods:
// Server-side: Environment variables
const token = process.env.HAIP_AUTH_TOKEN;
// Browser: Memory only (for sensitive tokens)
let tokenInMemory: string | null = null;
// Browser: Secure HTTP-only cookies (set by server)
// No client-side access needed
// Mobile: Secure keychain/keystore
// Use platform-specific secure storage
 
❌ Avoid:
// Don't store in localStorage (vulnerable to XSS)
localStorage.setItem("haip_token", token);
// Don't store in sessionStorage (cleared on tab close)
sessionStorage.setItem("haip_token", token);
// Don't hardcode in source code
const token = "hardcoded-token-here";
 
Token Rotation
Implement token rotation for enhanced security:
class SecureClient {
  private client: any;
  private tokenManager: TokenManager;
  constructor(url: string, tokenProvider: () => Promise<string>) {
    this.tokenManager = new TokenManager(tokenProvider);
    this.client = createHAIPClient({
      url,
      token: "", // Will be set during connect
      transport: "websocket",
    });
    // Set up automatic token refresh
    this.setupTokenRefresh();
  }
  private setupTokenRefresh() {
    // Refresh token every 4 minutes
    setInterval(async () => {
      try {
        const newToken = await this.tokenManager.getValidToken();
        // Reconnect with new token
        await this.reconnectWithToken(newToken);
      } catch (error) {
        console.error("Token refresh failed:", error);
      }
    }, 4 * 60 * 1000);
  }
  private async reconnectWithToken(token: string) {
    if (this.client.isConnected()) {
      await this.client.disconnect();
    }
    // Update client with new token
    this.client = createHAIPClient({
      url: this.client.url,
      token,
      transport: "websocket",
    });
    await this.client.connect();
  }
}
 
Network Security
Use Secure Connections:
// Production: Always use WSS (WebSocket Secure)
const client = createHAIPClient({
  url: "wss://api.example.com",
  token: "your-token",
  transport: "websocket",
});
// Development: Can use WS for local development
const devClient = createHAIPClient({
  url: "ws://localhost:8080",
  token: "dev-token",
  transport: "websocket",
});
 
Certificate Validation:
// Node.js: Custom certificate validation
const client = createHAIPClient({
  url: "wss://api.example.com",
  token: "your-token",
  transport: "websocket",
  options: {
    // WebSocket-specific options for certificate validation
    rejectUnauthorized: true,
    ca: fs.readFileSync("/path/to/ca-cert.pem"),
  },
});
 
Permission-Based Access
Channel Permissions
Check channel permissions before sending messages:
function canSendToChannel(token: string, channel: string): boolean {
  try {
    const payload = HAIPUtils.parseJWT(token);
    if (!payload.haip || !payload.haip.channels) {
      return false;
    }
    return payload.haip.channels.includes(channel);
  } catch (error) {
    return false;
  }
}
// Usage
if (canSendToChannel(token, "USER")) {
  await client.sendTextMessage("USER", "Hello", "user", runId);
} else {
  console.log("No permission to send to USER channel");
}
 
Run Limits
Enforce run limits based on token permissions:
function checkRunLimit(token: string, currentRuns: number): boolean {
  try {
    const payload = HAIPUtils.parseJWT(token);
    if (!payload.haip || !payload.haip.max_runs) {
      return currentRuns < 5; // Default limit
    }
    return currentRuns < payload.haip.max_runs;
  } catch (error) {
    return false;
  }
}
// Usage
if (checkRunLimit(token, client.getActiveRuns().length)) {
  await client.startRun("new-run");
} else {
  console.log("Run limit exceeded");
}
 
Testing Authentication
Mock Authentication
For testing purposes, create mock tokens:
function createMockToken(claims: Record<string, any> = {}): string {
  const header = {
    alg: "HS256",
    typ: "JWT",
  };
  const payload = {
    sub: "test-user",
    iat: Math.floor(Date.now() / 1000),
    exp: Math.floor(Date.now() / 1000) + 3600,
    ...claims,
  };
  // Note: This creates an unsigned token for testing only
  const headerB64 = btoa(JSON.stringify(header));
  const payloadB64 = btoa(JSON.stringify(payload));
  return `${headerB64}.${payloadB64}.mock-signature`;
}
// Usage in tests
const testToken = createMockToken({
  haip: {
    channels: ["USER", "AGENT"],
    max_runs: 10,
  },
});
 
Authentication Testing
describe("Authentication", () => {
  test("should connect with valid token", async () => {
    const client = createHAIPClient({
      url: "ws://localhost:8080",
      token: "valid-token",
      transport: "websocket",
    });
    await expect(client.connect()).resolves.not.toThrow();
    await client.disconnect();
  });
  test("should fail with invalid token", async () => {
    const client = createHAIPClient({
      url: "ws://localhost:8080",
      token: "invalid-token",
      transport: "websocket",
    });
    await expect(client.connect()).rejects.toThrow("AUTHENTICATION_FAILED");
  });
});
 
Next Steps