> ## 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.

# Audit and observability

> Record every credential use, tool call, and token operation in customer-owned telemetry.

export const RequestIdDiagram = () => <figure className="keyring-diagram request-id">
    <div className="request-id__stage" role="img" aria-label="One request ID, returned to Composio in the X-Composio-Keyring-Request-Id header, appears on the Keyring log line, the trace, and the audit event for the same operation.">
      <div className="request-id__badge">
        <span className="request-id__badge-name">x-composio-keyring-request-id</span>
        <code className="request-id__badge-id">8c1f2e4a-…-9b7d</code>
      </div>
      <div className="request-id__tiles">
        <div className="request-id__tile request-id__tile--response">
          <span className="request-id__tile-title">Composio response header</span>
          <code className="request-id__tile-id">8c1f2e4a-…-9b7d</code>
        </div>
        <div className="request-id__tile request-id__tile--log">
          <span className="request-id__tile-title">Keyring log line</span>
          <code className="request-id__tile-id">8c1f2e4a-…-9b7d</code>
        </div>
        <div className="request-id__tile request-id__tile--trace">
          <span className="request-id__tile-title">Trace</span>
          <code className="request-id__tile-id">8c1f2e4a-…-9b7d</code>
        </div>
        <div className="request-id__tile request-id__tile--audit">
          <span className="request-id__tile-title">Audit event</span>
          <code className="request-id__tile-id">8c1f2e4a-…-9b7d</code>
        </div>
      </div>
    </div>
  </figure>;

export const AuditPathDiagram = ({scenario}) => {
  const labels = {
    acknowledged: "With AUDIT_DURABILITY=required, a tool call reaches the provider through Keyring. Keyring holds the provider's response, sends the audit event to your collector, waits for the acknowledgment, and only then releases the response to Composio.",
    unreachable: "With AUDIT_DURABILITY=required and the collector unreachable, Keyring holds the provider's response, fails to store the audit event, cancels the withheld response, and returns a 500 to Composio instead of an unrecorded success."
  };
  return <figure className={`keyring-diagram simple-request-flow audit-flow audit-flow--${scenario}`}>
      <div className="simple-request-flow__stage" role="img" aria-label={labels[scenario]}>
        <div className="simple-request-flow__track" aria-hidden="true" />

        <div className="simple-request-flow__nodes">
          <div className="simple-request-flow__node audit-flow__node--composio">
            <span className="simple-request-flow__node-mark simple-request-flow__node-mark--composio" aria-hidden="true" />
            <b>Composio</b>
          </div>
          <div className="simple-request-flow__node audit-flow__node--keyring">
            <span className="simple-request-flow__node-mark simple-request-flow__node-mark--keyring">
              <svg viewBox="0 0 24 24" aria-hidden="true">
              <path d="M12 3 5 6v5c0 4.5 2.8 7.5 7 9.5 4.2-2 7-5 7-9.5V6L12 3Z" />
              <circle cx="12" cy="11" r="2" />
              <path d="M12 13v3" />
            </svg>
            </span>
            <b>Keyring</b>
            <span className="simple-request-flow__node-caption">Your Cloud</span>
          </div>
          <div className="simple-request-flow__node audit-flow__node--provider">
            <span className="simple-request-flow__node-mark audit-flow__node-mark--provider">
              <svg viewBox="0 0 24 24" aria-hidden="true">
              <circle cx="12" cy="12" r="8" />
              <ellipse cx="12" cy="12" rx="3.4" ry="8" />
              <path d="M4 12h16" />
            </svg>
            </span>
            <b>Provider</b>
          </div>
        </div>

        <div className="simple-request-flow__kms-link audit-flow__link" aria-hidden="true" />
        <span className="audit-flow__event" aria-hidden="true">
          <svg viewBox="0 0 24 24" aria-hidden="true">
              <rect x="5" y="4.5" width="14" height="16" rx="2" />
              <path d="M9 4.5V3h6v1.5M8.5 10h7m-7 4h5" />
            </svg>
        </span>
        <div className="simple-request-flow__kms-packet audit-flow__ack" aria-hidden="true" />
        <div className="simple-request-flow__kms audit-flow__collector">
          <span className="simple-request-flow__node-mark audit-flow__node-mark--collector">
            <svg viewBox="0 0 24 24" aria-hidden="true">
              <rect x="5" y="4.5" width="14" height="16" rx="2" />
              <path d="M9 4.5V3h6v1.5M8.5 10h7m-7 4h5" />
            </svg>
            <svg className="audit-flow__collector-slash" viewBox="0 0 24 24" aria-hidden="true">
              <path d="M5 19 19 5" pathLength="1" />
            </svg>
          </span>
          <b>Audit collector</b>
          <span className="simple-request-flow__node-caption audit-flow__collector-note">
            {scenario === "acknowledged" ? "acknowledged" : "no acknowledgment"}
          </span>
        </div>

        <div className="audit-flow__packet" aria-hidden="true">
          <div className="audit-flow__payload audit-flow__payload--request">
            <svg viewBox="0 0 24 24" aria-hidden="true">
              <path d="M4.5 12 19.5 4.5l-4 15-4.5-6.5-6.5-1Z" />
              <path d="m11 13 8.5-8.5" />
            </svg>
            <span>Request</span>
            <small>tool call with a credential</small>
          </div>
          <div className="audit-flow__payload audit-flow__payload--response">
            <svg viewBox="0 0 24 24" aria-hidden="true">
              <circle cx="12" cy="12" r="8" />
              <path d="m8.5 12.2 2.4 2.4 4.6-4.8" />
            </svg>
            <span>Provider response</span>
            <small>held until the audit event is stored</small>
          </div>
          <div className="audit-flow__payload audit-flow__payload--released">
            <svg viewBox="0 0 24 24" aria-hidden="true">
              <circle cx="12" cy="12" r="8" />
              <path d="m8.5 12.2 2.4 2.4 4.6-4.8" />
            </svg>
            <span>Provider response</span>
            <small>released · audit event stored</small>
          </div>
          <div className="audit-flow__payload audit-flow__payload--failed">
            <svg viewBox="0 0 24 24" aria-hidden="true">
              <circle cx="12" cy="12" r="8" />
              <path d="m9 9 6 6m0-6-6 6" />
            </svg>
            <span>500</span>
            <small>response withheld · audit not stored</small>
          </div>
        </div>
      </div>
    </figure>;
};

export const AuditEventDiagram = () => <figure className="keyring-diagram audit-event">
    <div className="audit-event__stage" role="img" aria-label="An audit.operation event records the request ID, method and route, toolkit with Composio project and connected-account attribution, action, outcome and status, organization and token ID, failure class, and client IP. It never contains credential or token values, authorization headers, decrypted provider payloads, or plaintext data keys.">
      <div className="audit-event__header">
        <span className="audit-event__header-mark" aria-hidden="true">
          <svg viewBox="0 0 24 24" aria-hidden="true">
              <rect x="5" y="4.5" width="14" height="16" rx="2" />
              <path d="M9 4.5V3h6v1.5M8.5 10h7m-7 4h5" />
            </svg>
        </span>
        <span>audit.operation</span>
      </div>
      <div className="audit-event__columns">
        <ul className="auth-gate__checks audit-event__list audit-event__list--yes" aria-hidden="true">
          <li className="audit-event__title">Recorded</li>
          <li className="auth-gate__check audit-event__row audit-event__row--yes-request">
            <span className="auth-gate__mark auth-gate__mark--ok" aria-hidden="true">
              <svg viewBox="0 0 24 24">
                <path d="m6 12.5 4 4 8-9" />
              </svg>
            </span>
            Request ID · method · route
          </li>
          <li className="auth-gate__check audit-event__row audit-event__row--yes-toolkit">
            <span className="auth-gate__mark auth-gate__mark--ok" aria-hidden="true">
              <svg viewBox="0 0 24 24">
                <path d="m6 12.5 4 4 8-9" />
              </svg>
            </span>
            Toolkit · project · connected account
          </li>
          <li className="auth-gate__check audit-event__row audit-event__row--yes-outcome">
            <span className="auth-gate__mark auth-gate__mark--ok" aria-hidden="true">
              <svg viewBox="0 0 24 24">
                <path d="m6 12.5 4 4 8-9" />
              </svg>
            </span>
            Action · outcome · status
          </li>
          <li className="auth-gate__check audit-event__row audit-event__row--yes-actor">
            <span className="auth-gate__mark auth-gate__mark--ok" aria-hidden="true">
              <svg viewBox="0 0 24 24">
                <path d="m6 12.5 4 4 8-9" />
              </svg>
            </span>
            Organization · token ID
          </li>
          <li className="auth-gate__check audit-event__row audit-event__row--yes-failure">
            <span className="auth-gate__mark auth-gate__mark--ok" aria-hidden="true">
              <svg viewBox="0 0 24 24">
                <path d="m6 12.5 4 4 8-9" />
              </svg>
            </span>
            Failure class · never the message
          </li>
          <li className="auth-gate__check audit-event__row audit-event__row--yes-client">
            <span className="auth-gate__mark auth-gate__mark--ok" aria-hidden="true">
              <svg viewBox="0 0 24 24">
                <path d="m6 12.5 4 4 8-9" />
              </svg>
            </span>
            Client IP · environment
          </li>
        </ul>
        <ul className="auth-gate__checks audit-event__list audit-event__list--no" aria-hidden="true">
          <li className="audit-event__title">Never recorded</li>
          <li className="auth-gate__check audit-event__row audit-event__row--no-token">
            <span className="auth-gate__mark auth-gate__mark--bad" aria-hidden="true">
              <svg viewBox="0 0 24 24">
                <path d="m7 7 10 10m0-10L7 17" />
              </svg>
            </span>
            Credential or token values
          </li>
          <li className="auth-gate__check audit-event__row audit-event__row--no-headers">
            <span className="auth-gate__mark auth-gate__mark--bad" aria-hidden="true">
              <svg viewBox="0 0 24 24">
                <path d="m7 7 10 10m0-10L7 17" />
              </svg>
            </span>
            Authorization headers
          </li>
          <li className="auth-gate__check audit-event__row audit-event__row--no-payload">
            <span className="auth-gate__mark auth-gate__mark--bad" aria-hidden="true">
              <svg viewBox="0 0 24 24">
                <path d="m7 7 10 10m0-10L7 17" />
              </svg>
            </span>
            Decrypted provider payloads
          </li>
          <li className="auth-gate__check audit-event__row audit-event__row--no-dek">
            <span className="auth-gate__mark auth-gate__mark--bad" aria-hidden="true">
              <svg viewBox="0 0 24 24">
                <path d="m7 7 10 10m0-10L7 17" />
              </svg>
            </span>
            Plaintext data keys
          </li>
        </ul>
      </div>
    </div>
  </figure>;

Every tool call and credential lifecycle operation—including token issuance, OAuth refresh, and
revocation—passes through Keyring and produces a structured audit event. Events describe the use without
logging the credential, token, or decrypted provider payload.

## Durable audit path

<AuditPathDiagram scenario="acknowledged" />

| Mode          | Behavior                                                            | Use                               |
| ------------- | ------------------------------------------------------------------- | --------------------------------- |
| `required`    | Sensitive success waits for your collector to acknowledge the event | Recommended for production        |
| `best_effort` | The operation does not wait for durable acknowledgment              | Local evaluation or accepted risk |

Set `AUDIT_DURABILITY=required` and configure `OTEL_COLLECTOR_URL` in production. With this mode,
Composio cannot successfully use a credential through Keyring without the customer audit path recording
the attempt.

Use the [telemetry delivery guide](/deployment/observability) to deploy the recommended collector or
evaluate a compatible direct OTLP endpoint.

For ECS, a collector sidecar keeps the acknowledgment path local to the task while the collector owns
batching, retries, and vendor authentication. Other deployments can use a nearby or remote OTLP/HTTP
collector that meets the required availability and latency.

### When the collector does not acknowledge

<AuditPathDiagram scenario="unreachable" />

Keyring posts the event to `<collector>/v1/logs` and treats a 2xx reply as the acknowledgment. It makes
up to three attempts of two seconds each, so an unreachable collector adds at most about six seconds
before the request fails. If no attempt is acknowledged, Keyring does not release the provider
response. It cancels the withheld response and returns HTTP 500 to Composio, so the operation is never reported
as an unrecorded success. The provider may already have performed the action; what Keyring refuses to
do is hand the result back without evidence. Denials and errors, which carry no secret material, are
still exported but do not wait for the acknowledgment.

## What is recorded

<AuditEventDiagram />

Each acknowledged `audit.operation` event records:

* request ID, Composio's request ID, time, method, route, and environment;
* the toolkit whose credential was used, with the Composio project, user, and connected-account
  attribution the request carried;
* the operation (tool call, token issuance, refresh, revocation, or key operation), its outcome, and
  the HTTP status;
* the failure class when something went wrong—never the error message, which can quote request data;
* the Composio issuer and token ID; and
* the client IP.

Keyring's logs and traces add the per-request detail around each event: the provider host, the policy
decision, and whether each response field left Keyring encrypted, as plaintext metadata, or blocked.
They are exported to the same collector, but they are not part of the acknowledged audit record.

Keyring does not log raw credentials, access or refresh tokens, authorization headers, sealed browser
payloads, plaintext data-encryption keys, or collector credentials.

## Request correlation

<RequestIdDiagram />

Every Keyring response includes `X-Composio-Keyring-Request-Id`. Use it to join Keyring logs, traces,
audit events, and the corresponding Composio operation during investigation.

## Log levels

| `LOG_LEVEL` | Typical events                                                              |
| ----------- | --------------------------------------------------------------------------- |
| `debug`     | Detailed KMS, encryption, cache, and policy steps                           |
| `info`      | Authentication, credential use, provider calls, token operations, and audit |
| `warning`   | Invalid requests, policy denials, and blocked destinations                  |
| `error`     | Provider, runtime, startup, and audit persistence failures                  |

The default is `info`. Use `debug` only in a protected environment; it excludes credential values but
still contains sensitive operational context.

## Collector authentication

`OTEL_COLLECTOR_HEADERS` is a comma-separated list of percent-encoded `Name=value` headers:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
OTEL_COLLECTOR_HEADERS=Authorization=Bearer%20example-token,X-Tenant=customer-123
```

Store collector credentials in your deployment platform's secret manager. Keyring exports OTLP/HTTP
traces, logs, and metrics to the configured collector base URL.

<Warning>
  The Helm chart defaults to `best_effort` so a new installation can start without a collector. Set
  `required` and provide a reachable collector before handling production credentials.
</Warning>
