mastra-ai/mastra · error

Agent Card signature is missing a protected "alg" header

Error message

Agent Card signature is missing a protected "alg" header

What it means

Each Agent Card signature is a detached JWS. The library decodes the signature's `protected` header and requires a string `alg` header parameter before verifying. This error is thrown (and collected per-signature) when the protected header either has no `alg` or the `alg` is not a string, making it impossible to select a verification algorithm.

Source

Thrown at client-sdks/client-js/src/utils/verify-agent-card-signature.ts:115

    return agentCard;
  }

  const canonicalPayload = canonicalize(stripAgentCardSignatures(agentCard));
  if (!canonicalPayload) {
    throw new MastraClientError(200, 'OK', 'Failed to canonicalize A2A Agent Card for signature verification');
  }

  const allowedAlgorithms = options.algorithms ?? [...DEFAULT_AGENT_CARD_SIGNATURE_ALGORITHMS];
  const encodedPayload = base64url.encode(canonicalPayload);
  const verificationErrors: string[] = [];

  for (const [index, signature] of signatures.entries()) {
    try {
      const compactJws = `${signature.protected}.${encodedPayload}.${signature.signature}`;
      const protectedHeader = decodeProtectedHeader(compactJws);

      if (typeof protectedHeader.alg !== 'string') {
        throw new Error('Agent Card signature is missing a protected "alg" header');
      }

      if (!allowedAlgorithms.includes(protectedHeader.alg)) {
        throw new Error(`Agent Card signature algorithm "${protectedHeader.alg}" is not allowed`);
      }

      const verificationKey = await options.keyProvider({
        agentCard,
        signature,
        protectedHeader,
        alg: protectedHeader.alg,
        kid: typeof protectedHeader.kid === 'string' ? protectedHeader.kid : undefined,
        jku: typeof protectedHeader.jku === 'string' ? protectedHeader.jku : undefined,
        index,
      });

      if (!verificationKey) {
        throw new Error('No verification key was provided for Agent Card signature verification');

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Fix the signer so it includes a string `alg` in the protected header (e.g. ES256 or RS256).
  2. Decode the `protected` segment (base64url → JSON) to confirm what header the server is actually emitting.
  3. Regenerate the Agent Card signature with a standard JOSE library (jose, jsonwebtoken) rather than a custom encoder.
  4. If the header is corrupted in transit, check for proxies/gateways rewriting the response body.

Example fix

// before: header without alg
const protectedHeader = { typ: 'JWT' };

// after
const protectedHeader = { alg: 'ES256', typ: 'JWT' };
Defensive patterns

Strategy: validation

Validate before calling

// pre-flight: decode each signature's protected header and require a string alg
card.signatures?.forEach((sig, i) => {
  const header = JSON.parse(atob(sig.protected.replace(/-/g, '+').replace(/_/g, '/')));
  if (typeof header.alg !== 'string') {
    throw new Error(`signature ${i} has no alg header; fix the signer before verification`);
  }
});

Type guard

function hasAlgHeader(h: unknown): h is { alg: string } & Record<string, unknown> {
  return typeof h === 'object' && h !== null && typeof (h as any).alg === 'string';
}

Try / catch

try {
  await client.getAgentCard();
} catch (e) {
  if (e instanceof MastraClientError && e.message.includes('missing a protected "alg" header')) {
    // fall back to unverified card or surface a clear config error
  }
}

Prevention

When it happens

Trigger: getAgentCard() with verification enabled where the card's signatures[i].protected base64url-decodes to a JOSE header lacking a string `alg` (e.g. header is {"typ":"JWT"} or alg: null).

Common situations: Signer produced the JWS without an alg (rare, but possible with hand-rolled signers); a corrupted or truncated `protected` segment; a mock fixture with an empty/placeholder protected header; server library version producing headers this verifier rejects.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/979a41f2c9c5e078. Report an issue: GitHub.