Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.svantic.com/llms.txt

Use this file to discover all available pages before exploring further.

Dispatch auth

import {
  verify_dispatch_auth,
  DispatchAuthVerifyError,
  MESH_DISPATCH_JWT_ISSUER,
  type DispatchAuthContext,
  type VerifierConfig,
  type DispatchAuthVerifyErrorCode,
} from '@svantic/sdk';

What it is

Dispatch auth is the SDK module that proves an inbound A2A dispatch really came from the Svantic mesh. Every capability invocation Svantic routes to an agent can carry a svantic_auth envelope inside the DataPart. That envelope is either an HS256 JWT issued by the mesh (scheme: 'svantic_jwt') or a shared-secret comparison (scheme: 'shared_secret'). verify_dispatch_auth parses the envelope, checks the signature / secret, enforces audience binding and clock skew, and hands you a typed DispatchAuthContext you can log or pass into authorization decisions. Two key points:
  • Hosted-mode agents should enable it. Without dispatch auth, anyone who learns the agent’s public URL can invoke capabilities.
  • Connected-mode agents get it for free on the transport. The outbound WebSocket is already authenticated, so dispatch auth there is accepted but optional.
The SDK calls this for you automatically when AgentConfig.dispatch_auth is set. You only import the low-level helpers when you’re extracting auth from raw payloads yourself — e.g. a custom transport, a test harness, or a middleware before the SDK touches the request.

When to use it directly

  • You’re hosting an agent outside Agent.start() / attach() (custom transport).
  • You want an authorization check inside a capability handler based on the verified subject.
  • You’re writing a compatibility layer that consumes A2A dispatches and want the same safety guarantees.

Functional usage

import { verify_dispatch_auth, DispatchAuthVerifyError } from '@svantic/sdk';

async function handle_dispatch(payload: Record<string, unknown>) {
  try {
    const ctx = verify_dispatch_auth(payload, {
      agent_instance_id: 'orders-agent-prod-1',
      jwt_secret: process.env.SVANTIC_DISPATCH_JWT_SECRET, // enables svantic_jwt
      shared_secret: process.env.SVANTIC_DISPATCH_SHARED_SECRET, // enables shared_secret
      required: true, // reject anything missing/invalid
    });

    log.info({
      scheme: ctx.scheme,
      caller: ctx.claims?.sub,
    }, 'dispatch accepted');

    // ctx.claims is strongly typed when scheme === 'svantic_jwt'.
    return await run_capability(payload);
  } catch (err) {
    if (err instanceof DispatchAuthVerifyError) {
      log.warn({ code: err.code }, 'dispatch rejected');
      throw new HttpError(401, 'unauthorized');
    }
    throw err;
  }
}
See the Securing dispatches guide for setup, key rotation, and the hands-off path via AgentConfig.dispatch_auth.

verify_dispatch_auth(data, config)

function verify_dispatch_auth(
  data: Record<string, unknown> | undefined | null,
  config: VerifierConfig,
): DispatchAuthContext;
Verify a dispatch. data is the DataPart payload as received by the SDK (the object your capability handler sees, before argument extraction). Supported schemes:
  • svantic_jwt — HS256 JWT signed with the agent’s signing_secret. The verifier checks iss = 'svantic-mesh', aud = agent:<instance_id>, and exp. Claims (tenant_id, agent_type, instance_id, dispatch_id, jti) are surfaced on the returned context.
  • shared_secret — opaque token compared in constant time against a locally configured secret. Supports per-credentials-ref secrets via shared_secrets map.

VerifierConfig

FieldTypePurpose
instance_idstringThis agent’s instance id. The verifier requires the JWT audience to be exactly agent:<instance_id> to prevent token reuse across instances.
signing_secret?stringHS256 shared secret for svantic_jwt verification.
shared_secrets?ReadonlyMap<string, string> | { default?: string }Material for shared_secret verification. Map keyed by credentials_ref, or a single default secret.
now?() => numberClock (epoch ms). Defaults to Date.now.
clock_skew_s?numberJWT-expiry tolerance in seconds. Defaults to 5.

DispatchAuthContext

Returned by a successful verification. Only scheme and expires_at are guaranteed; JWT claims are populated for svantic_jwt only.
FieldTypeDescription
scheme'svantic_jwt' | 'shared_secret'Which scheme verified.
expires_atnumberEpoch seconds when the envelope expires.
tenant_id?stringJWT claim.
agent_type?stringJWT claim.
instance_id?stringJWT claim.
dispatch_id?stringJWT claim.
jti?stringJWT id — use for replay prevention if you want it.
credentials_ref?stringEchoed ref for shared_secret, useful when the agent holds multiple secrets.

DispatchAuthVerifyError

Thrown for every failure. err.code is one of:
CodeMeaning
missing_envelopeAuth was required but none was attached.
malformed_envelopeEnvelope failed schema validation.
unsupported_schemeScheme not handled by this verifier.
invalid_signatureJWT signature did not verify.
wrong_issuerJWT iss was not svantic-mesh.
wrong_audienceJWT aud did not match this agent.
expiredJWT exp or envelope expires_at is in the past.
secret_mismatchshared_secret token did not match local secret.
no_local_secretshared_secret verification requested but the agent has no configured secret.
not_configuredsvantic_jwt verification requested but the agent has no signing_secret.

Constants

MESH_DISPATCH_JWT_ISSUER

export const MESH_DISPATCH_JWT_ISSUER = 'svantic-mesh';
Issuer value the mesh always sets on svantic_jwt dispatch tokens.

Example

import {
  verify_dispatch_auth,
  DispatchAuthVerifyError,
} from '@svantic/sdk';

agent.define_capability({
  name: 'publish_post',
  description: '…',
  parameters: { /* … */ },
  handler: async (args, ctx) => {
    // `data` is what the SDK received — pass it through from the executor
    // integration in your wrapper, or use the SDK's built-in wiring once enabled.
    try {
      const auth_ctx = verify_dispatch_auth(args as any, {
        instance_id: agent.instance_id,
        signing_secret: process.env.SVANTIC_DISPATCH_SECRET,
      });
      console.log('Authorized caller tenant', auth_ctx.tenant_id);
    } catch (err) {
      if (err instanceof DispatchAuthVerifyError) {
        throw new Error(`Unauthorized: ${err.code}`);
      }
      throw err;
    }

    return { ok: true };
  },
});

See also