Security

Security: Code is Law

In Happen, we believe that security should be architectural, not procedural.

In traditional systems, developers are forced to write the same boilerplate checks inside every function: "Is this user logged in?", "Is this data valid?", "Do they have permission?"

This manual approach is fragile. If you forget the check in one handler, the system is compromised.

Happen inverts this model. Instead of writing security code, you declare security policies. The framework enforces a rule that every event must pass through before it ever reaches your business logic.

The Philosophy: "Policies, Not Boilerplate"

Security is not something you do; it is something you declare.

When you create a Node, you define its laws. The framework acts as the enforcer. If an event does not satisfy the laws, it is rejected at the edge, and your handler never runs.

The Three Gates

Every event sent to a Safe Node travels through three automatic checkpoints.

Gate 1: Authentication (The "Who")

"Prove you are who you say you are."

  • Mechanism: Cryptographic Signature Verification.

  • How it works: The framework automatically uses the sender's nodeId (public key) to verify the digital signature of the event's causal.hash.

  • Result: Absolute proof of origin. If the signature is invalid or the payload has been tampered with, the event is dropped instantly.

Gate 2: Interface Control (The "How")

"Prove you are speaking my language."

  • Mechanism: Cryptographic Schema Hashing.

  • How it works: Instead of slow, runtime JSON schema validation, Happen compares the event's structure hash against a whitelist of allowed schemaHash values for that event type.

  • Result: Malformed data, injection attacks, and unexpected payloads are physically impossible to process.

Gate 3: Authorization (The "What")

"Prove you are allowed to do this."

  • Mechanism: Role-Based Origin Check.

  • How it works: The framework inspects the context.origin chain (the original user or system that triggered the flow) and checks it against your allowedRoles.

  • Result: Granular control. You can allow a "Viewer" to trigger get events but only an "Admin" to trigger delete events.

Implementation

You define these gates in a simple policies configuration object when creating a node.

import { createSafeNode } from 'happen';

// 1. Define your policies
const policies = {
  // Policy for 'order.create' events
  'order.create': {
    // Gate 2: Only accept payloads matching this exact shape hash
    schemaHash: 'sha256-a7b8...', 
    
    // Gate 3: Only accept these roles
    allowedRoles: ['role:customer', 'role:system']
  },
  
  // Policy for sensitive admin actions
  'system.shutdown': {
    schemaHash: 'sha256-9c4d...',
    allowedRoles: ['role:super-admin']
  }
};

// 2. Create the Node
const secureNode = createSafeNode('payment-service', {
  policies: policies,
  
  // Global Gate 1 is enforced automatically by createSafeNode
});

// 3. Write pure business logic
secureNode.on('order.create', (event) => {
  // If this code runs, you KNOW:
  // 1. The sender is valid (Gate 1)
  // 2. The data shape is valid (Gate 2)
  // 3. The user is authorized (Gate 3)
  
  return processPayment(event.payload);
});

Advanced: Custom Security Liners

Because Happen is built on Liners, you are not limited to the standard Three Gates. You can inject custom security logic that runs between the gates.

Example: The PII Filter

A customized Liner that scans payloads for sensitive data (like credit card numbers) and redacts them before logging.

const withPIIRedaction = (next) => (event, context) => {
  // Run before the handler
  if (containsCreditCard(event.payload)) {
    event.payload = redact(event.payload);
  }
  
  return next(event, context);
};

// Apply it to your node
secureNode.line('order.create', withPIIRedaction);

Summary

Security in Happen is:

  • Declarative: Defined in config, not code.

  • Automatic: Enforced by the framework, not the developer.

  • Fail-Safe: Invalid events are blocked at the door.

By moving security out of your functions and into the framework, you eliminate entire classes of vulnerabilities and keep your code clean, readable, and focused on the domain.

Last updated