Authentication can be handled through the onBeforeConnect or createConnState lifecycle hook, which acts as middleware before allowing clients to interact with your actor.

Using onBeforeConnect or createConnState

The onBeforeConnect and createConnState hook is called whenever a new client attempts to connect to your actor. It receives a context object that contains the client’s connection parameters. createConnState should return an object that will become the connection state.

Throwing an error in onBeforeConnect or createConnState will abort the connection.

Here’s a basic example:

import { actor } from "actor-core";

const exampleActor = actor({
  state: {
    // Actor state...
  },
  
  createConnState: async (c, { params }) => {
    // Verify the token with your authentication system
    const userData = await myValidateAuthToken(params.authToken);
    if (!userData) {
      throw new Error('Invalid auth token');
    }

    // Return the user data to store with the connection
    return {
      userId: userData.id,
      role: userData.role
    };
  },
  
  actions: {
    // Actor actions...
  }
});

Accessing Connection State

After authentication, you can access the connection state in any action through the context object:

import { actor } from "actor-core";

const authenticatedActor = actor({
  state: {
    // Actor state...
  },
  
  createConnState: (c) => {
    // Authentication logic...
    return {
      userId: "user_123",
      role: "admin"
    };
  },
  
  actions: {
    exampleAdminCommand: (c) => {
      // Example of validating admin access
      if (c.conn.state.role !== 'admin') {
        throw new Error('User must be an admin');
      }

      // Admin-only functionality...
      return { success: true };
    }
  }
});

Integration Examples

With API Server Authentication

import { actor } from "actor-core";

const apiAuthenticatedActor = actor({
  state: {
    // Actor state...
  },
  
  createConnState: async (c, { params }) => {
    // Validate API key with your server
    const response = await fetch('https://api.yourserver.com/validate', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${params.apiKey}`
      }
    });

    if (!response.ok) {
      throw new Error('Invalid API key');
    }

    const user = await response.json();

    return {
      userId: user.id
    };
  },
  
  actions: {
    // Actor actions...
  }
});

When authentication fails, throwing an error in createConnState will prevent the connection from being established, and the client will receive the error message.

With JWT Authentication

import { actor } from "actor-core";
import jwt from "jsonwebtoken";

const JWT_SECRET = process.env.JWT_SECRET;

const jwtAuthenticatedActor = actor({
  state: {
    // Actor state...
  },
  
  createConnState: (c, { params }) => {
    try {
      // Verify JWT token
      const decoded = jwt.verify(params.jwt, JWT_SECRET);
      
      return {
        userId: decoded.sub,
        permissions: decoded.permissions
      };
    } catch (error) {
      throw new Error('Invalid or expired JWT token');
    }
  },
  
  actions: {
    secureAction: (c, data) => {
      // Check permissions before proceeding
      if (!c.conn.state.permissions.includes('write')) {
        throw new Error('Permission denied: requires write access');
      }
      
      // Perform action with data...
      return { success: true };
    }
  }
});