---
description: Add, overwrite, and remove HTTP request headers in Gateway HTTP policies using static or dynamic values.
title: Modify HTTP request headers in Gateway
image: https://developers.cloudflare.com/cloudflare-one/traffic-controls/http-policies/tenant-control/og.png?v=dfe395b03af7ef91
---

[Skip to content](#main-content)

> Documentation Index  
> Fetch the complete documentation index at: https://developers.cloudflare.com/cloudflare-one/llms.txt  
> Use this file to discover all available pages before exploring further.

# Modify HTTP request headers in Gateway

Last updated Oct 15, 2026|Copy as Markdown| [View as Markdown](https://developers.cloudflare.com/cloudflare-one/traffic-controls/http-policies/tenant-control/index.md)| [Agent setup](https://developers.cloudflare.com/agent-setup/)

Gateway HTTP policies with Allow actions can modify the headers of matching requests before they reach their destination. You can add dynamic values to set headers to forward information like user identity, source IP, and other inputs to upstream services, enforce SaaS tenant control, strip internal headers, override header content.

Header manipulation requires [TLS decryption](https://developers.cloudflare.com/cloudflare-one/traffic-controls/http-policies/tls-decryption/), because HTTP headers are only visible on traffic which Gateway can decrypt.

For header changes that require custom code or response transformations, use [Forward](https://developers.cloudflare.com/cloudflare-one/traffic-controls/integrate-workers/forward-traffic/) (beta) to invoke a Worker after HTTP filtering. Built-in Allow-policy header operations remain available for changes expressed directly in the policy.

## Header operations

Gateway supports three header operations on HTTP policies. When a request matches an Allow policy with header operations configured, Gateway applies them in the following order:

1. **Delete** - Remove headers from the request.
2. **Overwrite** - Overwrite headers on the request. Headers with matched names will have their values overwritten. If the header does not exist, it is created.
3. **Add** - Append headers to the request. If the header already exists, the added value is appended to the existing value.

You can configure up to 20 header operations per policy. Header names are limited to 256 bytes, and header values are limited to 4 KB.

### Add headers

Adding a header appends a value to the request. If the header already exists, the value is added alongside the existing value rather than replacing it.

### Overwrite headers

Overwriting a header overwrites any existing value. If the header does not already exist on the request, it is created. Use this operation when you need to guarantee a specific header value regardless of what the client sent.

### Delete headers

Deleting a header removes it from the request entirely. If the header does not exist, the operation has no effect.

## Dynamic header values

Header values can include dynamic variables that Gateway resolves at request time using identity, device, and network context from the current session. Dynamic variables use the `@{...}` syntax and can be mixed with static text in the same value.

For example, a header value of `user-@{identity.email}` resolves to `user-jdoe@example.com` at request time.

The following dynamic variables are available:

| Variable | Description |
| --- | --- |
| `@{identity.email}` | User's email address from the identity provider. |
| `@{identity.name}` | User's display name from the identity provider. |
| `@{identity.id}` | User's Cloudflare identity UUID. |
| `@{identity.groups}` | User's identity provider group memberships. |
| `@{identity.SAML}` | User's SAML attributes from the identity provider if configured. |
| `@{identity.OIDC}` | User's OIDC claims from the identity provider if configured. |
| `@{source.ip}` | Source IP address of the user's connection as seen in Gateway. |
| `@{destination.ip}` | Destination IP address of the request. |
| `@{device.id}` | Cloudflare One Client device UUID. |
| `@{device.posture}` | Device posture check results (serialized as a JSON string). |

Dynamic variables require an active identity session. If Gateway cannot resolve a variable (for example, the user is not authenticated), the variable is replaced with a warning string such as `cf-unresolved` or `cf-invalid`, and a warning is added to the HTTP log.

## Configure header operations

### Dashboard

To create an HTTP policy with header operations:

1. In the [Cloudflare One dashboard ↗︎](https://dash.cloudflare.com/one), go to **Traffic policies** > **Firewall policies** > **HTTP**.
2. Select **Add a policy**.
3. Build an expression to match the traffic you want to modify.
4. In **Action**, select *Allow*.
5. Under **Modify request headers**, select **Add** or **Overwrite** to add or overwrite headers, or select **Remove** to delete a header.
6. For Add and Overwrite operations, enter the header name and value. To use a dynamic variable, enter the `@{...}` syntax in the value field, or select the `{}` button to see the list of available values. For Remove operations, enter only the header name.
7. Save your policy.

### API

To create an HTTP policy with header operations via the API, include `add_headers`, `set_headers`, and `delete_headers` in the `rule_settings` object.

```bash
curl https://api.cloudflare.com/client/v4/accounts/{account_id}/gateway/rules \
--header "Authorization: Bearer {api_token}" \
--header "Content-Type: application/json" \
--data '{
  "name": "Forward identity headers",
  "action": "allow",
  "enabled": true,
  "filters": ["http"],
  "traffic": "any(http.request.domains[*] in {\"app.example.com\"})",
  "rule_settings": {
    "add_headers": {
      "X-User-Email": ["@{identity.email}"],
      "X-User-Groups": ["@{identity.groups}"]
    },
    "set_headers": {
      "X-Forwarded-User": ["@{identity.email}"]
    },
    "delete_headers": ["X-Debug-Token", "X-Internal-Only"]
  }
}'
```

The `rule_settings` fields for header manipulation are:

| Field | Type | Description |
| --- | --- | --- |
| `add_headers` | `map<string, array<string>>` | Headers to append. Each key is a header name, each value is a list of values to add. |
| `set_headers` | `map<string, array<string>>` | Headers to overwrite. Each key is a header name, each value is a list of values to set. |
| `delete_headers` | `array<string>` | Header names to remove from the request. |

A single header value can contain a mix of static text and dynamic variables. For example:

```json
{
  "add_headers": {
    "X-Request-Context": ["user=@{identity.email}, device=@{device.id}, src=@{source.ip}"]
  }
}
```

### Verify custom headers

If you save a HAR (HTTP Archive) file from a browser to analyze your web traffic, custom headers defined with Gateway will not appear in the file. This is because Gateway injects the header after the request leaves the browser.

To verify Gateway is applying a custom header:

1. In your policy with custom headers, add a selector to match traffic for [HTTPBin ↗︎](https://httpbin.org/), an open-source site for testing HTTP requests. For example:

   | Selector | Operator | Value | Logic | Action | Untrusted certificate action |
   | --- | --- | --- | --- | --- | --- |
   | Application | in | *Google Workspace* | Or | Allow | Block |
   | Domain | in | `httpbin.org` |  |  |  |
2. On your device, go to [`httpbin.org/anything` ↗︎](https://httpbin.org/anything). Your custom header will appear in the list of headers.
3. (Optional) Remove the HTTPBin expression from your policy.

## Use cases

### SaaS tenant control

Tenant control allows your users to access corporate SaaS applications while blocking access to personal accounts on the same service. For example, you can allow access to your company's Google Workspace while blocking personal Gmail logins.

Gateway implements tenant control by injecting custom HTTP headers into matching requests. These headers tell the SaaS application which tenant (organization) is authorized. If the user attempts to authenticate with a personal account, the SaaS application reads the header and rejects the request.

<details>

<summary>

Microsoft 365

</summary>

Microsoft 365 tenant control requires two policies. When you order your policies, make sure they follow <a href="https://developers.cloudflare.com/cloudflare-one/traffic-controls/order-of-enforcement/#order-of-precedence">order of precedence</a>.

| Precedence | Selector | Operator | Value | Action | Untrusted certificate action |
| --- | --- | --- | --- | --- | --- |
| 1 | Domain | is | <code>login.live.com</code> | Allow | Block |

| Custom header name | Custom header value |
| --- | --- |
| <code>Sec-Restrict-Tenant-Access-Policy</code> | <code>restrict-msa</code> |

| Precedence | Selector | Operator | Value | Action | Untrusted certificate action |
| --- | --- | --- | --- | --- | --- |
| 2 | Application | in | *Microsoft Office365* | Allow | Block |

| Custom header name | Custom header value |
| --- | --- |
| <code>Restrict-Access-To-Tenants</code>, <code>Restrict-Access-Context</code> | Your organization's domain |

For more information, refer to the <a href="https://learn.microsoft.com/entra/identity/enterprise-apps/tenant-restrictions">Microsoft Entra ID documentation ↗︎</a>.

</details>

<details>

<summary>

Google Workspace

</summary>

| Selector | Operator | Value | Action | Untrusted certificate action |
| --- | --- | --- | --- | --- |
| Application | in | *Google Workspace* | Allow | Block |

| Custom header name | Custom header value |
| --- | --- |
| <code>X-GoogApps-Allowed-Domains</code> | Your organization's domain |

For more information, refer to the <a href="https://support.google.com/a/answer/1668854">Google Workspace documentation ↗︎</a>.

</details>

<details>

<summary>

Slack

</summary>

| Selector | Operator | Value | Action | Untrusted certificate action |
| --- | --- | --- | --- | --- |
| Application | in | *Slack* | Allow | Block |

| Custom header name | Custom header value |
| --- | --- |
| <code>X-Slack-Allowed-Workspaces-Requester</code>, <code>X-Slack-Allowed-Workspaces</code> | Your organization's workspace |

For more information, refer to the <a href="https://slack.com/help/articles/360024821873-Approve-Slack-workspaces-for-your-network">Slack documentation ↗︎</a>.

</details>

<details>

<summary>

Dropbox

</summary>

| Selector | Operator | Value | Action | Untrusted certificate action |
| --- | --- | --- | --- | --- |
| Application | in | *Dropbox* | Allow | Block |

| Custom header name | Custom header value |
| --- | --- |
| <code>X-Dropbox-allowed-Team-Ids</code> | Your organization's ID |

For more information, refer to the <a href="https://help.dropbox.com/security/network-control">Dropbox documentation ↗︎</a>.

</details>

<details>

<summary>

ChatGPT

</summary>

| Selector | Operator | Value | Action | Untrusted certificate action |
| --- | --- | --- | --- | --- |
| Application | in | *ChatGPT* | Allow | Block |

| Custom header name | Custom header value |
| --- | --- |
| <code>Chatgpt-Allowed-Workspace-Id</code> | Your organization's workspace ID |

For more information, refer to the <a href="https://help.openai.com/articles/8798594-what-is-a-workspace-how-do-i-access-my-chatgpt-business-workspace">OpenAI documentation ↗︎</a>.

</details>

<details>

<summary>

Claude

</summary>

| Selector | Operator | Value | Action | Untrusted certificate action |
| --- | --- | --- | --- | --- |
| Application | in | *Claude* | Allow | Block |

| Custom header name | Custom header value |
| --- | --- |
| <code>anthropic-allowed-org-ids</code> | Your organization's UUID |

To allow access from multiple organizations, enter a comma-separated list of UUIDs with no spaces (for example, <code>&lt;org-uuid-1&gt;,&lt;org-uuid-2&gt;</code>).

You can find your organization UUID in **Settings** &gt; **Account** &gt; **Organization ID** on <a href="https://claude.ai/settings/account">claude.ai ↗︎</a>.

For more information, refer to the <a href="https://support.claude.com/en/articles/13198485-enforce-network-level-access-control-with-tenant-restrictions">Claude documentation ↗︎</a>.

</details>

### Forward user identity to upstream services

You can use dynamic header values to forward user identity information to your upstream applications without requiring those applications to integrate with Cloudflare Access directly.

| Header name | Header value |
| --- | --- |
| `X-User-Email` | `@{identity.email}` |
| `X-User-Name` | `@{identity.name}` |
| `X-User-Groups` | `@{identity.groups}` |
| `X-Source-IP` | `@{source.ip}` |

Your upstream application can read these headers to identify the user, enforce authorization logic, or populate audit logs.

### Strip internal headers

To prevent clients from spoofing internal headers, use the delete operation to remove headers before forwarding the request, then use the add or set operation to re-inject them with verified values.

```bash
curl https://api.cloudflare.com/client/v4/accounts/{account_id}/gateway/rules \
--header "Authorization: Bearer {api_token}" \
--header "Content-Type: application/json" \
--data '{
  "name": "Replace internal headers",
  "action": "allow",
  "enabled": true,
  "filters": ["http"],
  "traffic": "any(http.request.domains[*] in {\"internal.example.com\"})",
  "rule_settings": {
    "delete_headers": ["X-Internal-User"],
    "set_headers": {
      "X-Internal-User": ["@{identity.email}"]
    }
  }
}'
```

### Exempt users in Cloudflare WAF

You can include custom headers in an HTTP policy to allow your users through [Cloudflare WAF](https://developers.cloudflare.com/waf/). This is useful for allowing only Cloudflare One Client users through your WAF.

1. Create an Allow policy for an internal domain behind your WAF with a custom header.

   | Selector | Operator | Value | Action |
   | --- | --- | --- | --- |
   | Domain | in | `internalapp.com` | Allow |
   | Custom header name | Custom header value |
   | --- | --- |
   | `X-Example-Header` | `example-value` |
2. In Cloudflare WAF, [create a custom rule](https://developers.cloudflare.com/waf/custom-rules/) to [require the same HTTP header](https://developers.cloudflare.com/waf/custom-rules/use-cases/require-specific-headers/#example-2-require-http-header-with-a-specific-value).

### Use custom headers with Browser Isolation

You can configure [Browser Isolation](https://developers.cloudflare.com/cloudflare-one/remote-browser-isolation/) to send custom headers. This is useful for implementing tenant control for isolated SaaS applications or sending arbitrary custom request headers to isolated websites.

To use custom headers with Browser Isolation, create two HTTP policies targeting the same domain or application group. For example, you can create policies for [HTTPBin ↗︎](https://httpbin.org/), an open-source site for testing HTTP requests:

1. Create an Isolate policy for `httpbin.org`.

   | Selector | Operator | Value | Action |
   | --- | --- | --- | --- |
   | Domain | in | `httpbin.org` | Isolate |
2. Create an Allow policy for `httpbin.org` with a custom header.

   | Selector | Operator | Value | Action |
   | --- | --- | --- | --- |
   | Domain | in | `httpbin.org` | Allow |
   | Custom header name | Custom header value |
   | --- | --- |
   | `Example-Header` | `example-value` |
3. Go to [`httpbin.org/anything` ↗︎](https://httpbin.org/anything). Cloudflare will render the site in an isolated browser. Your custom header will appear in the list of headers.

Was this helpful?

YesNo

## On this page

[![](https://developers.cloudflare.com/_astro/logo.te5VL_aD.svg)Docs](https://developers.cloudflare.com/)

```json
{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/cloudflare-one/traffic-controls/http-policies/tenant-control/#page","headline":"Modify HTTP request headers in Gateway","description":"Add, overwrite, and remove HTTP request headers in Gateway HTTP policies using static or dynamic values.","url":"https://developers.cloudflare.com/cloudflare-one/traffic-controls/http-policies/tenant-control/","inLanguage":"en","image":"https://developers.cloudflare.com/cloudflare-one/traffic-controls/http-policies/tenant-control/og.png?v=dfe395b03af7ef91","dateModified":"2026-10-15","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"},"keywords":["Headers"]}
```
