Build Channels and Auth Providers

Normalize a custom protocol into canonical events and authenticate ingress with bounded identity evidence.

Before you begin

Choose the protocol, target Agent, and customer identity mode. Use the platform Constal API Key provider for Constal keys; write an Auth Provider only for external proof such as signed webhooks or third-party bearer tokens.

Steps

  1. Define authentication. Return only a stable subject, optional downstream customer external id, bounded claims, and optional expiry:
ts
import { authProvider } from "@constal/sdk";

export default authProvider({
  id: "signed-webhook", version: "1.0.0",
  needs: [{ binding: "verifier", kind: "service", ops: ["verify"] }],
  async authenticate({ request }, context) {
    const proof = await context.invoke<{ valid: boolean; subject?: string }>(
      context.resources.verifier!, "verify", { headers: request.headers, bodyBase64: request.bodyBase64 },
    );
    return proof.valid && proof.subject
      ? { authenticated: true, subject: proof.subject }
      : { authenticated: false, reason: "invalid signature" };
  },
});
  1. Define the Channel after the Auth Provider has a stable CRN:
ts
import { authProviderName, channel, resourceName } from "@constal/sdk";

export default channel({
  id: "webhook", version: "1.0.0", public: true,
  authProvider: authProviderName("crn:constal:production:acme:default:auth-provider/signed-webhook"),
  target: resourceName({ environment: "production", tenant: "acme", namespace: "default", kind: "agent", path: "support" }),
  protocol: {
    id: "json-webhook", version: "1",
    receive(request) {
      const body = JSON.parse(atob(request.bodyBase64 ?? ""));
      return { id: body.id, type: "message", session: body.session, data: body.message };
    },
    respond(result) {
      return { status: result.status === "failed" ? 500 : 200,
        headers: { "content-type": "application/json" }, bodyBase64: btoa(JSON.stringify(result)) };
    },
  },
});
  1. Set customerIdentity in the manifest to required, optional, or none. Central authentication maps provider evidence to accepted authority before receive. Use ChannelContext.invoke() for declared external work; Channel and Auth Provider code never receives Credential bytes.

Verify

Send one invalid and one valid signed request to /v1/channels/:tenant/:namespace/:channel/*. Invalid proof must fail before receive; valid proof must produce the expected source, target, principal, and customer partition. Repeat the delivery id and confirm the recorded outcome is reused.

Next steps

Read Deploy a Channel, Deploy an Auth Provider, and Operate Channels for packaging, ingress, messages, events, and alarms.