New protocol version released: This page may contain outdated information.
The HAIP Server uses JWT (JSON Web Tokens) for authentication, providing secure, stateless authentication for all client connections.

JWT Authentication

Secure token-based authentication

Session Management

Per-client session tracking and management

Token Validation

Automatic token validation and expiry checking

User Identification

Extract user information from tokens

JWT Configuration

Basic Configuration

const server = new HAIPServer({
  jwtSecret: "your-secret-key-here",
  jwtExpiresIn: "24h",
});

Environment Variables

# Required: JWT secret for signing tokens
JWT_SECRET=your-secret-key-here

# Optional: Token expiration time (default: 24h)
JWT_EXPIRES_IN=24h

Security Best Practices

// Production configuration
const secureConfig = {
  jwtSecret: process.env.JWT_SECRET, // Use environment variable
  jwtExpiresIn: "1h", // Short expiration for security
  enableCORS: false, // Disable CORS in production
  enableLogging: true,
};

Token Structure

JWT Payload

{
  "userId": "user-123",
  "iat": 1634567890,
  "exp": 1634654290,
  "iss": "haip-server",
  "aud": "haip-client"
}

Required Claims

  • userId: Unique identifier for the user
  • iat: Issued at timestamp
  • exp: Expiration timestamp

Optional Claims

  • iss: Issuer (default: “haip-server”)
  • aud: Audience (default: “haip-client”)
  • sub: Subject (user ID)
  • jti: JWT ID (unique identifier)

Client Authentication

WebSocket Authentication

// Connect with JWT token
const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...";
const ws = new WebSocket(`ws://localhost:8080/haip/websocket?token=${token}`);

ws.on("open", () => {
  console.log("Authenticated WebSocket connection");
});

ws.on("error", (error) => {
  console.error("Authentication failed:", error);
});

SSE Authentication

// Connect with JWT token
const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...";
const eventSource = new EventSource(
  `http://localhost:8080/haip/sse?token=${token}`
);

eventSource.onopen = () => {
  console.log("Authenticated SSE connection");
};

eventSource.onerror = (error) => {
  console.error("Authentication failed:", error);
};

HTTP Streaming Authentication

// Connect with JWT token in Authorization header
const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...";

const response = await fetch("http://localhost:8080/haip/stream", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${token}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify(handshakeMessage),
});

if (response.ok) {
  console.log("Authenticated HTTP streaming connection");
} else {
  console.error("Authentication failed:", response.status);
}

Token Generation

Server-Side Token Generation

import jwt from "jsonwebtoken";

// Generate JWT token
function generateToken(
  userId: string,
  secret: string,
  expiresIn: string = "24h"
) {
  const payload = {
    userId,
    iat: Math.floor(Date.now() / 1000),
    iss: "haip-server",
    aud: "haip-client",
  };

  return jwt.sign(payload, secret, { expiresIn });
}

// Example usage
const token = generateToken("user-123", process.env.JWT_SECRET, "1h");
console.log("Generated token:", token);

Token Validation

import jwt from "jsonwebtoken";

// Validate JWT token
function validateToken(token: string, secret: string) {
  try {
    const decoded = jwt.verify(token, secret);
    return {
      valid: true,
      payload: decoded,
    };
  } catch (error) {
    return {
      valid: false,
      error: error.message,
    };
  }
}

// Example usage
const result = validateToken(token, process.env.JWT_SECRET);
if (result.valid) {
  console.log("Valid token for user:", result.payload.userId);
} else {
  console.error("Invalid token:", result.error);
}

Session Management

Session Creation

When a client connects with a valid token, the server automatically creates a session:
// Session is created automatically
const session = {
  id: "session-uuid",
  userId: "user-123",
  connected: true,
  handshakeCompleted: false,
  lastActivity: Date.now(),
  credits: new Map([
    ["USER", 1000],
    ["AGENT", 1000],
    ["SYSTEM", 1000],
  ]),
  // ... other session properties
};

Session Tracking

// Get session information
const session = server.getSession("session-id");
if (session) {
  console.log("Session user:", session.userId);
  console.log("Session connected:", session.connected);
  console.log("Last activity:", session.lastActivity);
}

Session Cleanup

Sessions are automatically cleaned up when clients disconnect:
// Session cleanup happens automatically
server.on("disconnect", (sessionId) => {
  console.log("Session disconnected:", sessionId);
  // Session is automatically removed from memory
});

Error Handling

Authentication Errors

// Invalid token
{
  "type": "ERROR",
  "channel": "SYSTEM",
  "payload": {
    "code": "INVALID_TOKEN",
    "message": "Invalid or expired JWT token"
  }
}

// Missing token
{
  "type": "ERROR",
  "channel": "SYSTEM",
  "payload": {
    "code": "MISSING_TOKEN",
    "message": "JWT token is required"
  }
}

// Expired token
{
  "type": "ERROR",
  "channel": "SYSTEM",
  "payload": {
    "code": "TOKEN_EXPIRED",
    "message": "JWT token has expired"
  }
}

Client-Side Error Handling

// Handle authentication errors
ws.on("message", (data) => {
  const message = JSON.parse(data.toString());

  if (message.type === "ERROR") {
    switch (message.payload.code) {
      case "INVALID_TOKEN":
        console.error("Invalid token, please re-authenticate");
        // Redirect to login or refresh token
        break;
      case "TOKEN_EXPIRED":
        console.error("Token expired, please refresh");
        // Refresh token or redirect to login
        break;
      case "MISSING_TOKEN":
        console.error("No token provided");
        // Redirect to login
        break;
    }
  }
});

Token Refresh

Client-Side Token Refresh

class HAIPClient {
  constructor(url, token, refreshToken) {
    this.url = url;
    this.token = token;
    this.refreshToken = refreshToken;
    this.ws = null;
  }

  async refreshToken() {
    try {
      const response = await fetch("/auth/refresh", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          refreshToken: this.refreshToken,
        }),
      });

      if (response.ok) {
        const data = await response.json();
        this.token = data.token;
        this.refreshToken = data.refreshToken;
        return true;
      }
    } catch (error) {
      console.error("Token refresh failed:", error);
    }
    return false;
  }

  async connect() {
    // Try to connect with current token
    this.ws = new WebSocket(`${this.url}?token=${this.token}`);

    this.ws.onerror = async (error) => {
      // If authentication fails, try to refresh token
      if (await this.refreshToken()) {
        // Reconnect with new token
        this.connect();
      } else {
        // Redirect to login
        window.location.href = "/login";
      }
    };
  }
}

Security Considerations

1. Secure Token Storage

// Client-side secure storage
class TokenManager {
  static setToken(token) {
    // Store in memory for session duration
    sessionStorage.setItem("haip_token", token);
  }

  static getToken() {
    return sessionStorage.getItem("haip_token");
  }

  static clearToken() {
    sessionStorage.removeItem("haip_token");
  }
}

2. Token Rotation

// Server-side token rotation
class TokenService {
  static async rotateToken(oldToken: string, secret: string) {
    const decoded = jwt.verify(oldToken, secret);

    // Generate new token with same user
    const newToken = jwt.sign(
      {
        userId: decoded.userId,
        iat: Math.floor(Date.now() / 1000),
        iss: "haip-server",
        aud: "haip-client",
      },
      secret,
      { expiresIn: "1h" }
    );

    return newToken;
  }
}

3. Rate Limiting

// Implement rate limiting for authentication
import rateLimit from "express-rate-limit";

const authLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 5, // limit each IP to 5 requests per windowMs
  message: "Too many authentication attempts",
});

app.use("/auth", authLimiter);

4. HTTPS in Production

// Always use HTTPS in production
const productionConfig = {
  // ... other config
  ssl: {
    enabled: true,
    cert: process.env.SSL_CERT,
    key: process.env.SSL_KEY,
  },
};

Monitoring and Logging

Authentication Events

// Listen for authentication events
server.on("connect", (sessionId) => {
  const session = server.getSession(sessionId);
  console.log(`User ${session?.userId} connected with session ${sessionId}`);
});

server.on("disconnect", (sessionId) => {
  const session = server.getSession(sessionId);
  console.log(`User ${session?.userId} disconnected from session ${sessionId}`);
});

Authentication Statistics

// Get authentication statistics
const stats = server.getStats();
console.log("Active sessions:", stats.activeConnections);
console.log("Total connections:", stats.totalConnections);

Testing Authentication

Generate Test Tokens

// Generate test tokens for development
function generateTestToken(userId: string = "test-user") {
  const payload = {
    userId,
    iat: Math.floor(Date.now() / 1000),
    exp: Math.floor(Date.now() / 1000) + 3600, // 1 hour
    iss: "haip-server",
    aud: "haip-client",
  };

  return jwt.sign(payload, "test-secret-key");
}

// Usage
const testToken = generateTestToken("test-user-123");
console.log("Test token:", testToken);

Test Authentication

// Test authentication with generated token
const testToken = generateTestToken("test-user");
const ws = new WebSocket(
  `ws://localhost:8080/haip/websocket?token=${testToken}`
);

ws.on("open", () => {
  console.log("✅ Authentication test passed");
  ws.close();
});

ws.on("error", (error) => {
  console.error("❌ Authentication test failed:", error);
});

Next Steps