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

# Credential refresh and exchange

> See how Composio refreshes provider credentials through your Keyring without receiving plaintext tokens.

export const RefreshExchangeDiagram = () => <figure className="keyring-diagram simple-request-flow refresh-flow">
    <div className="simple-request-flow__stage" role="img" aria-label="Composio notices an expired Gmail access token and sends the sealed refresh-token envelope from its database to Keyring. Your KMS unseals it inside Keyring, the plaintext refresh token goes only to Google's token endpoint, Google issues a new access token, Keyring seals it into a new envelope while expiry metadata stays plain, and Composio stores the new envelope.">
      <div className="simple-request-flow__track" aria-hidden="true" />

      <div className="simple-request-flow__nodes">
        <div className="simple-request-flow__node refresh-flow__node--composio">
          <span className="simple-request-flow__node-mark simple-request-flow__node-mark--composio" aria-hidden="true" />
          <b>Composio</b>
          <span className="simple-request-flow__node-caption">Ciphertext only</span>
        </div>
        <div className="simple-request-flow__node refresh-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 refresh-flow__node--google">
          <span className="simple-request-flow__node-mark simple-request-flow__node-mark--gmail">
            <svg viewBox="0 0 32 24" aria-hidden="true">
              <path d="M3 21 V6" />
              <path d="M3 6 L16 15 L29 6" />
              <path d="M29 6 V21" />
              <path d="M3 6 L8 9.5" />
            </svg>
          </span>
          <b>Google</b>
          <span className="simple-request-flow__node-caption">Token endpoint</span>
        </div>
      </div>

      <div className="simple-request-flow__kms-link refresh-flow__db-link" aria-hidden="true" />
      <div className="simple-request-flow__kms-packet refresh-flow__db-packet" aria-hidden="true" />
      <span className="refresh-flow__db-envelope" aria-hidden="true">
        <svg viewBox="0 0 24 24">
          <rect x="3" y="5.5" width="18" height="13" rx="2" />
          <path d="M4.5 7.5 12 13l7.5-5.5" />
          <circle cx="12" cy="15.4" r="1.4" />
        </svg>
      </span>
      <div className="simple-request-flow__kms refresh-flow__db">
        <span className="simple-request-flow__node-mark refresh-flow__node-mark--db">
          <svg viewBox="0 0 24 24" aria-hidden="true">
            <ellipse cx="12" cy="6" rx="7" ry="2.7" />
            <path d="M5 6v12c0 1.5 3.1 2.7 7 2.7s7-1.2 7-2.7V6" />
            <path d="M5 12c0 1.5 3.1 2.7 7 2.7s7-1.2 7-2.7" />
          </svg>
        </span>
        <b>Composio DB</b>
        <span className="simple-request-flow__node-caption">Sealed envelopes</span>
        <span className="refresh-flow__stored" aria-hidden="true">
          <svg viewBox="0 0 24 24">
            <rect x="3" y="5.5" width="18" height="13" rx="2" />
            <path d="M4.5 7.5 12 13l7.5-5.5" />
            <circle cx="12" cy="15.4" r="1.4" />
          </svg>
        </span>
      </div>

      <div className="simple-request-flow__kms-link refresh-flow__kms-link" aria-hidden="true" />
      <div className="simple-request-flow__kms-packet refresh-flow__kms-packet" aria-hidden="true" />
      <div className="simple-request-flow__kms refresh-flow__kms">
        <span className="simple-request-flow__node-mark simple-request-flow__node-mark--kms">
          <svg viewBox="0 0 24 24" aria-hidden="true">
            <circle cx="7.5" cy="12" r="3.5" />
            <path d="M11 12h10m-3 0v3m-3-3v2" />
          </svg>
        </span>
        <b>KMS</b>
      </div>

      <div className="refresh-flow__packet" aria-hidden="true">
        <div className="refresh-flow__payload refresh-flow__payload--expired">
          <svg viewBox="0 0 24 24" aria-hidden="true">
            <circle cx="12" cy="12" r="8" />
            <path d="M12 7.5V12l3 2" />
          </svg>
          <span>Access token</span>
          <small>expired</small>
        </div>
        <div className="refresh-flow__payload refresh-flow__payload--sealed">
          <svg viewBox="0 0 24 24" aria-hidden="true">
            <rect x="3" y="5.5" width="18" height="13" rx="2" />
            <path d="M4.5 7.5 12 13l7.5-5.5" />
            <circle cx="12" cy="15.4" r="1.4" />
          </svg>
          <span>Refresh token</span>
          <small>sealed envelope</small>
        </div>
        <div className="refresh-flow__payload refresh-flow__payload--refresh">
          <svg viewBox="0 0 24 24" aria-hidden="true">
            <path d="M12 4.5 13.2 8l3.5 1.2-3.5 1.2L12 13.9l-1.2-3.5L7.3 9.2l3.5-1.2Z" />
            <path d="M18.5 14.2l.7 1.9 1.9.7-1.9.7-.7 1.9-.7-1.9-1.9-.7 1.9-.7Z" />
            <path d="M6.2 15.7l.6 1.5 1.5.6-1.5.6-.6 1.5-.6-1.5-1.5-.6 1.5-.6Z" />
          </svg>
          <span>Refresh token</span>
          <small className="refresh-flow__refresh-value" />
        </div>
        <div className="refresh-flow__payload refresh-flow__payload--access">
          <svg viewBox="0 0 24 24" aria-hidden="true">
            <circle cx="8" cy="12" r="3.2" />
            <path d="M11.2 12h9.3m-3 0v2.8m-3-2.8v2" />
          </svg>
          <span>Access token</span>
          <small className="refresh-flow__access-value" />
        </div>
        <div className="refresh-flow__payload refresh-flow__payload--envelope">
          <svg viewBox="0 0 24 24" aria-hidden="true">
            <rect x="3" y="5.5" width="18" height="13" rx="2" />
            <path d="M4.5 7.5 12 13l7.5-5.5" pathLength="1" />
            <circle cx="12" cy="15.4" r="1.4" />
          </svg>
          <span>New envelope</span>
          <small>expires_in: 3600 stays plain</small>
        </div>
      </div>
    </div>
  </figure>;

When a connected account needs a new access token, Composio routes the token exchange through the
Keyring running in your environment. The provider can issue new credentials, but their plaintext form
does not return to Composio.

<Note>
  Your application does not call this route. Composio invokes the protected exchange flow as part of
  operating the connected account; your application continues to use Composio tools normally.
</Note>

## Follow one refresh

<RefreshExchangeDiagram />

The values in the animation are masked examples. Keyring does not place plaintext credentials in its
request or audit logs.

## What the exchange route does

`POST /api/v1/exchange` is a protected service-to-service route between the Composio backend and your
Keyring. It is not a Composio admin endpoint and it is not an API that customer applications need to
integrate with.

Composio uses the exchange flow for provider token operations such as initial token issuance, OAuth
refresh, and revocation. Keeping these operations separate from ordinary tool forwarding lets Keyring
apply stricter destination and response-handling rules.

### 1. Composio sends an encrypted instruction

The signed request identifies the toolkit, the approved provider token endpoint, and the exchange to
perform. Credential inputs—such as a refresh token or client secret—arrive as encrypted references.
The request also carries a data-key envelope that Keyring can use to protect any secrets returned by
the provider.

### 2. Keyring verifies before opening a secret

Keyring verifies Composio's signature and your organization audience, then checks the bundled policy.
The policy must allow the toolkit, exact token endpoint, request fields, response fields, and redirect
behavior. A failed check ends the request before plaintext is created.

After those checks pass, Keyring asks your KMS to authorize the required key operation. Your KMS root
key remains in the KMS; only Keyring's workload identity receives permission to use it.

### 3. The provider performs the refresh

Keyring resolves the encrypted refresh inputs in memory and constructs the provider request. For a
Gmail connection, the only external destination that receives those plaintext inputs is Google's
approved OAuth token endpoint.

The provider returns a response that can contain both secrets and ordinary metadata—for example, a new
access token alongside its expiry and token type.

### 4. Keyring protects the response field by field

Before a successful provider response leaves your environment, Keyring encrypts credential fields such
as `access_token` and `refresh_token`. Safe metadata such as `expires_in` and `token_type` can remain
plaintext so Composio can schedule the next refresh and operate the connection.

The toolkit policy decides which fields are sensitive. A request cannot downgrade a protected token
field to plaintext. If Keyring cannot parse and protect a successful response as required, it fails
closed instead of returning unknown plaintext.

### 5. The operation becomes auditable

Keyring records the toolkit, provider destination, exchange operation, policy result, and the
disposition of returned fields. It records that a field was encrypted or allowed as metadata—not the
field's secret value.

When required audit durability is enabled, the protected result is not returned until your collector
acknowledges the audit event. Composio then receives encrypted credential fields plus any permitted
non-secret metadata.

## Who can see each part

| Party                   | What it can see during refresh                                                                 |
| ----------------------- | ---------------------------------------------------------------------------------------------- |
| Composio                | Exchange instructions, encrypted credential envelopes, safe metadata, and the protected result |
| Your Keyring            | Plaintext credential inputs and provider token fields briefly in process memory                |
| Your KMS                | Authorized key operations and key metadata; not the provider request or token values           |
| Provider token endpoint | The plaintext refresh inputs required by that provider and the token it issues                 |
| Your audit collector    | Operation metadata and field dispositions; never plaintext credential values                   |

## Why ordinary forwarding cannot do this

Keyring rejects token endpoints on the ordinary provider-forwarding path. That prevents a normal tool
request from being repurposed to mint or refresh a credential without the exchange-specific checks.

The exchange route adds three guarantees:

1. The destination must be an approved token endpoint for the named toolkit.
2. Sensitive inputs are resolved only after authentication and policy checks pass.
3. Secret response fields are encrypted before the successful response leaves Keyring.

## What you configure

You do not configure individual refresh jobs. Your deployment provides the controls the exchange flow
depends on:

* Composio authentication settings, including your organization ID as `AUTH_AUDIENCE`;
* a workload identity with narrowly scoped access to your KMS keys;
* the bundled provider policy, or a reviewed custom policy when required; and
* an audit collector and durability mode appropriate for your security requirements.

See [Deployment overview](/deployment/overview#connect-keyring-to-composio) for authentication and network setup, and
[Encryption and key hierarchy](/concepts/encryption_and_keys) for the keys used to protect credentials.
