> ## Documentation Index
> Fetch the complete documentation index at: https://keyring.docs.composio.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Network and request policy

> How Keyring limits inbound callers, provider destinations, token operations, redirects, and secret placement.

export const AnimatedRequestFlow = ({flow}) => {
  const iconStroke = {
    fill: "none",
    stroke: "currentColor",
    strokeWidth: 1.7,
    strokeLinecap: "round",
    strokeLinejoin: "round"
  };
  function diagramIcon(name, x, y) {
    const transform = `translate(${x - 10} ${y - 10})`;
    if (name === "composio") {
      return <g className="keyring-diagram__icon" transform={transform}>
          <path d="M4 6.5 15.5 4v4L7 9.3v1.4l8.5 1.3v4L4 13.5z" {...iconStroke} />
          <path d="M8 2.7v14.6" {...iconStroke} />
        </g>;
    }
    if (name === "key") {
      return <g className="keyring-diagram__icon" transform={transform}>
          <circle cx="7" cy="9" r="3.2" {...iconStroke} />
          <path d="m9.8 7.5 6-3m-2 1 1.5 2" {...iconStroke} />
        </g>;
    }
    if (name === "lock") {
      return <g className="keyring-diagram__icon" transform={transform}>
          <rect x="4" y="8" width="12" height="9" rx="2.5" {...iconStroke} />
          <path d="M7 8V6a3 3 0 0 1 6 0v2m-3 3.5v2" {...iconStroke} />
        </g>;
    }
    if (name === "shield") {
      return <g className="keyring-diagram__icon" transform={transform}>
          <path d="M10 2.5 16 5v4.5c0 4-2.4 6.5-6 8-3.6-1.5-6-4-6-8V5z" {...iconStroke} />
          <path d="m7.3 10 1.8 1.8 3.8-4" {...iconStroke} />
        </g>;
    }
    if (name === "sparkles") {
      return <g className="keyring-diagram__icon" transform={transform}>
          <path d="m10 2 1.2 4.2L15 8l-3.8 1.8L10 14l-1.2-4.2L5 8l3.8-1.8zM4 14l.5 1.5L6 16l-1.5.5L4 18l-.5-1.5L2 16l1.5-.5z" {...iconStroke} />
        </g>;
    }
    if (name === "check") {
      return <g className="keyring-diagram__icon" transform={transform}>
          <circle cx="10" cy="10" r="7" {...iconStroke} />
          <path d="m6.5 10 2.2 2.2 4.8-5" {...iconStroke} />
        </g>;
    }
    if (name === "settings") {
      return <g className="keyring-diagram__icon" transform={transform}>
          <circle cx="10" cy="10" r="2.6" {...iconStroke} />
          <path d="M10 2.5v2m0 11v2M2.5 10h2m11 0h2M4.7 4.7l1.4 1.4m7.8 7.8 1.4 1.4m0-10.6-1.4 1.4m-7.8 7.8-1.4 1.4" {...iconStroke} />
        </g>;
    }
    if (name === "network") {
      return <g className="keyring-diagram__icon" transform={transform}>
          <circle cx="4" cy="10" r="2" {...iconStroke} />
          <circle cx="16" cy="5" r="2" {...iconStroke} />
          <circle cx="16" cy="15" r="2" {...iconStroke} />
          <path d="m6 9 8-3m-8 5 8 3" {...iconStroke} />
        </g>;
    }
    if (name === "route") {
      return <g className="keyring-diagram__icon" transform={transform}>
          <circle cx="4" cy="5" r="2" {...iconStroke} />
          <circle cx="16" cy="15" r="2" {...iconStroke} />
          <path d="M6 5h3a3 3 0 0 1 3 3v4a3 3 0 0 0 3 3" {...iconStroke} />
        </g>;
    }
    if (name === "identity") {
      return <g className="keyring-diagram__icon" transform={transform}>
          <circle cx="10" cy="7" r="3.5" {...iconStroke} />
          <path d="M3.5 17c.8-3.2 3-5 6.5-5s5.7 1.8 6.5 5" {...iconStroke} />
        </g>;
    }
    if (name === "server") {
      return <g className="keyring-diagram__icon" transform={transform}>
          <rect x="3" y="3" width="14" height="6" rx="2" {...iconStroke} />
          <rect x="3" y="11" width="14" height="6" rx="2" {...iconStroke} />
          <path d="M6 6h.1M6 14h.1M9 6h5M9 14h5" {...iconStroke} />
        </g>;
    }
    return <g className="keyring-diagram__icon" transform={transform}>
        <rect x="3" y="3" width="14" height="14" rx="4" {...iconStroke} />
        <path d="M7 7h6v6H7z" {...iconStroke} />
      </g>;
  }
  function serviceIcon(step, x, y) {
    if (step.icon === "composio") {
      return <image className="minimal-flow__composio-mark" href="/assets/brand/composio_mark_black.svg" x={x - 13} y={y - 13} width="26" height="26" />;
    }
    return diagramIcon(step.icon, x, y);
  }
  function flowTiming(count) {
    const pause = 0.72;
    const travel = 0.28;
    const total = count * pause + (count - 1) * travel;
    const keyPoints = [0, 0];
    const keyTimes = [0, pause / total];
    let elapsed = pause;
    for (let index = 1; index < count; index += 1) {
      elapsed += travel;
      const position = index / (count - 1);
      keyPoints.push(position);
      keyTimes.push(elapsed / total);
      elapsed += pause;
      keyPoints.push(position);
      keyTimes.push(elapsed / total);
    }
    return {
      duration: `${Math.max(7, count * 1.35)}s`,
      keyPoints: keyPoints.join(";"),
      keyTimes: keyTimes.join(";")
    };
  }
  function flowCanvas(spec, flowName, mobile) {
    const width = mobile ? 420 : 1000;
    const height = mobile ? 68 + spec.steps.length * 96 : 250;
    const positions = spec.steps.map((step, index) => {
      if (mobile) return {
        x: 78,
        y: 46 + index * 96,
        step
      };
      const gap = 820 / (spec.steps.length - 1);
      return {
        x: 90 + index * gap,
        y: 112,
        step
      };
    });
    const path = mobile ? `M 78 ${positions[0].y} L 78 ${positions[positions.length - 1].y}` : `M ${positions[0].x} 112 L ${positions[positions.length - 1].x} 112`;
    const timing = flowTiming(spec.steps.length);
    const titleId = `minimal-${flowName}-${mobile ? "mobile" : "desktop"}-title`;
    const descriptionId = `minimal-${flowName}-${mobile ? "mobile" : "desktop"}-description`;
    return <svg className={mobile ? "minimal-flow__mobile" : "minimal-flow__desktop"} viewBox={`0 0 ${width} ${height}`} role="img" aria-labelledby={`${titleId} ${descriptionId}`}>
        <title id={titleId}>{spec.steps.map(step => step.title).join(" to ")}</title>
        <desc id={descriptionId}>{spec.description}</desc>
        <path className="minimal-flow__track" d={path} />
        {!mobile && spec.packet ? <g className="minimal-flow__request" aria-hidden="true">
            <rect x="-88" y="-88" width="176" height="54" rx="11" />
            <text className="minimal-flow__request-title" x="0" y="-67" textAnchor="middle">
              {spec.packet.title}
            </text>
            <text className="minimal-flow__request-detail" x="0" y="-47" textAnchor="middle">
              {spec.packet.detail}
            </text>
            <animateMotion path={path} dur={timing.duration} keyPoints={timing.keyPoints} keyTimes={timing.keyTimes} calcMode="linear" repeatCount="indefinite" />
          </g> : null}
        <g className="minimal-flow__streak" aria-hidden="true">
          <line x1="-18" x2="18" />
          <line className="minimal-flow__streak-glow" x1="-12" x2="12" />
          <animateMotion path={path} dur={timing.duration} keyPoints={timing.keyPoints} keyTimes={timing.keyTimes} calcMode="linear" rotate="auto" repeatCount="indefinite" />
        </g>
        {positions.map(({x, y, step}, index) => <g className={`minimal-flow__node minimal-flow__node--${step.kind}`} key={`${step.title}-${index}`}>
            <circle className="minimal-flow__disc" cx={x} cy={y} r="25" />
            {serviceIcon(step, x, y)}
            <text className="minimal-flow__title" x={mobile ? x + 46 : x} y={mobile ? y - 2 : y + 45} textAnchor={mobile ? "start" : "middle"}>
              {step.title}
            </text>
            <text className="minimal-flow__detail" x={mobile ? x + 46 : x} y={mobile ? y + 18 : y + 64} textAnchor={mobile ? "start" : "middle"}>
              {step.detail}
            </text>
          </g>)}
      </svg>;
  }
  const flowSpecs = {
    connection: {
      description: "A signed request from Composio reaches the customer Keyring endpoint, is verified for the customer organization, and continues to an approved provider.",
      steps: [{
        title: "Composio",
        detail: "Signed request",
        kind: "composio",
        icon: "composio"
      }, {
        title: "HTTPS edge",
        detail: "Composio-only ingress",
        kind: "customer",
        icon: "network"
      }, {
        title: "Keyring",
        detail: "Organization verified",
        kind: "customer",
        icon: "shield"
      }, {
        title: "Provider",
        detail: "Connected route",
        kind: "provider",
        icon: "check"
      }]
    },
    policy: {
      description: "Keyring authenticates Composio and checks the requested toolkit, destination, credential placement, and redirects before allowing credential use.",
      steps: [{
        title: "Composio",
        detail: "Signed tool call",
        kind: "composio",
        icon: "composio"
      }, {
        title: "Identity",
        detail: "JWT + source IP",
        kind: "customer",
        icon: "identity"
      }, {
        title: "Toolkit",
        detail: "Operation allowed",
        kind: "control",
        icon: "toolkit"
      }, {
        title: "Destination",
        detail: "Host + redirects",
        kind: "control",
        icon: "route"
      }, {
        title: "Provider",
        detail: "Approved request",
        kind: "provider",
        icon: "check"
      }],
      packet: {
        title: "PROVIDER_REQUEST",
        detail: "Policy: pending"
      }
    },
    deployment: {
      description: "Composio reaches a restricted customer HTTPS edge, Keyring uses workload identity for customer KMS access, and approved traffic continues to providers.",
      steps: [{
        title: "Composio",
        detail: "Allowed source",
        kind: "composio",
        icon: "composio"
      }, {
        title: "HTTPS edge",
        detail: "TLS + allowlist",
        kind: "customer",
        icon: "network"
      }, {
        title: "Keyring",
        detail: "Customer runtime",
        kind: "customer",
        icon: "shield"
      }, {
        title: "Cloud identity",
        detail: "Short-lived access",
        kind: "customer",
        icon: "identity"
      }, {
        title: "Your KMS",
        detail: "Scoped keys",
        kind: "customer",
        icon: "key"
      }, {
        title: "Provider",
        detail: "Approved traffic",
        kind: "provider",
        icon: "sparkles"
      }]
    },
    aws: {
      description: "Composio reaches an allowlisted AWS load balancer, private ECS tasks run Keyring, and the task role authorizes access to tagged KMS keys before provider traffic leaves.",
      steps: [{
        title: "Composio",
        detail: "Allowed source",
        kind: "composio",
        icon: "composio"
      }, {
        title: "AWS ALB",
        detail: "TLS + allowlist",
        kind: "customer",
        icon: "network"
      }, {
        title: "ECS Keyring",
        detail: "Private task",
        kind: "customer",
        icon: "server"
      }, {
        title: "Task role",
        detail: "Short-lived identity",
        kind: "customer",
        icon: "identity"
      }, {
        title: "AWS KMS",
        detail: "Tagged keys",
        kind: "customer",
        icon: "key"
      }, {
        title: "Provider",
        detail: "Approved traffic",
        kind: "provider",
        icon: "sparkles"
      }]
    },
    gcp: {
      description: "Composio reaches Cloud Armor and the HTTPS load balancer, Cloud Run hosts Keyring, and its service identity authorizes exact-key Cloud KMS access.",
      steps: [{
        title: "Composio",
        detail: "Allowed source",
        kind: "composio",
        icon: "composio"
      }, {
        title: "Cloud Armor",
        detail: "TLS + allowlist",
        kind: "customer",
        icon: "network"
      }, {
        title: "Cloud Run",
        detail: "Keyring service",
        kind: "customer",
        icon: "server"
      }, {
        title: "Service identity",
        detail: "Metadata token",
        kind: "customer",
        icon: "identity"
      }, {
        title: "Cloud KMS",
        detail: "Exact-key IAM",
        kind: "customer",
        icon: "key"
      }, {
        title: "Provider",
        detail: "Approved traffic",
        kind: "provider",
        icon: "sparkles"
      }]
    }
  };
  const spec = flowSpecs[flow];
  if (!spec) return null;
  const figureClassName = `keyring-diagram minimal-flow minimal-flow--${flow}`;
  return <figure className={figureClassName}>
      {flowCanvas(spec, flow, false)}
      {flowCanvas(spec, flow, true)}
    </figure>;
};

Every provider request passes through layered policy before Keyring decrypts a credential. A valid
Composio signature is necessary, but it is not enough on its own.

<AnimatedRequestFlow flow="policy" />

## Bundled provider policy

The official image includes a reviewed Composio policy that defines, per toolkit:

* approved provider origins;
* token issuance, refresh, and revocation destinations;
* where credentials may be placed in structured provider requests; and
* which response fields must be encrypted before leaving Keyring.

Standard deployments should omit `origin_policy.manifest_url`. Omitting it selects the bundled policy;
it never disables policy enforcement.

## Inbound access

At your public edge, allow HTTPS only from the
[Composio production egress addresses](/deployment/overview#network-access). Keyring also requires a valid
Composio JWT for every credential operation, so possession of an allowed source IP is not sufficient.

The Composio Dashboard receives only the public transfer key through Composio and does not need a direct
network path to Keyring.

## Outbound destination controls

In staging and production, provider targets must use HTTPS. Keyring rejects local hostnames and direct
loopback, link-local, private, reserved, or otherwise non-public IP destinations. The target must also
belong to the requested toolkit's approved origins.

Unknown toolkits and unmatched destinations are denied before decryption.

## Token operations are isolated

Provider token issuance, refresh, and revocation are handled as protected token operations rather than
ordinary provider forwarding. Their destinations must match the toolkit policy, and sensitive response
fields are encrypted before returning to Composio.

This separation prevents an ordinary tool request from calling a token endpoint and returning a new
plaintext credential.

See [Credential refresh and exchange](/concepts/credential_refresh) to follow an OAuth refresh through
authentication, KMS authorization, the provider token endpoint, response encryption, and audit delivery.

## Request and redirect controls

Credentials can be inserted only into reviewed request locations for the toolkit and destination.
Arbitrary or nested credential placement in provider bodies is denied.

Redirects are not trusted automatically. When following is permitted, Keyring checks the new
destination against the same HTTPS, public-address, toolkit, and token-endpoint rules before continuing.

Keyring also removes transport-specific and untrusted internal headers before forwarding requests or
returning provider responses.

## Customer controls

You have three levels of shutdown:

1. **All credential use:** stop Keyring or revoke its workload identity's KMS access.
2. **Selected projects or auth configs:** disable Keyring routing for that Composio scope.
3. **Selected toolkits or operation classes:** apply a reviewed custom policy that removes those
   destinations or capabilities while preserving the rest.

Use a custom policy only when it has been reviewed for your deployment. Broad wildcards increase the
risk of credential exfiltration; prefer the narrowest provider hosts and operation patterns possible.

## Private and self-hosted providers

Self-hosted services and per-connection endpoints may not have stable public origins. They remain denied
until an appropriate network path and reviewed custom policy are configured. Do not use production
`APP_ENV=local` to bypass private-address protection.
