# Headers Settings

This reference covers all of Pomerium's **Headers Settings**:

- [Host Header Settings](#host-rewrite)
- [Set Request Headers](#set-request-headers)
- [Remove Request Headers](#remove-request-headers)
- [Set Response Headers](#set-response-headers)
- [Rewrite Response Headers](#rewrite-response-headers)

## Host Header Settings

By default, Pomerium will set the `Host` header of an upstream request according to the host specified in the [**To**](https://www.pomerium.com/docs/reference/routes/to.md) URL for the route.

(Strictly speaking, the `Host` header is used only with HTTP/1.1. For HTTP/2 and HTTP/3 the `:authority` pseudo-header is used instead. These settings affect both identically.)

You can change how Pomerium sets this header using the following settings:

### 1. Preserve Host Header

`preserve_host_header` passes the Host header from the incoming request to the upstream service, instead of the host from the route's To URL.

This is like the Apache httpd [ProxyPreserveHost](http://httpd.apache.org/docs/2.0/mod/mod_proxy.html#proxypreservehost) directive.

### 2. Host Rewrite

`host_rewrite` rewrites the Host header to a fixed value.

### 3. Host Rewrite Header

`host_rewrite_header` rewrites the Host header using the value of some other header from the incoming request. For example:

```yaml
host_rewrite_header: X-My-Host
```

For an incoming request with the header `X-My-Host: foo.example.com`, this would rewrite the Host header to `foo.example.com`.

### 4. Host Path Regex Rewrite Pattern/Substitution

`host_path_regex_rewrite_pattern` and `host_path_regex_rewrite_substitution` rewrite the Host header based on a regular expression substitution using the URL path as the input. For example:

```yaml
host_path_regex_rewrite_pattern: '^/(.+)/.+$'
host_path_regex_rewrite_substitution: \1
```

For a request URL with the path `/example.com/some/path`, this would rewrite the Host header to `example.com`.

### How to Configure

**Core:**

| **YAML**/**JSON** settings             | **Type**  | **Usage**    |
| :------------------------------------- | :-------- | :----------- |
| `preserve_host_header`                 | `boolean` | **optional** |
| `host_rewrite`                         | `string`  | **optional** |
| `host_rewrite_header`                  | `string`  | **optional** |
| `host_path_regex_rewrite_pattern`      | `string`  | **optional** |
| `host_path_regex_rewrite_substitution` | `string`  | **optional** |

### Examples

```yaml
preserve_host_header: true
```

```yaml
host_rewrite: 'example.com'
```

**Enterprise:**

**Kubernetes:**

| **[Annotation name](https://www.pomerium.com/docs/deploy/k8s/ingress.md#set-ingress-annotations)** | **Type** | **Usage** |
| :-- | :-- | :-- |
| `host_rewrite` | `string` | **optional** |

### Examples

```yaml
ingress.pomerium.io/host_rewrite: 'example.com'
```

### Original Host Header

When host rewrite is active, Pomerium adds an `x-pomerium-original-host` header to upstream requests containing the pre-rewrite `Host`/`:authority` value. This applies to the default `auto_host_rewrite` behavior as well as explicit `host_rewrite`, `host_rewrite_header`, and `host_path_regex_rewrite` settings.

This header is not added when [`preserve_host_header`](#1-preserve-host-header) is enabled, because the `Host` header is not being rewritten.

The header value matches the client's original `Host` exactly, including port if present (e.g. `app.example.com:8443`). Pomerium overwrites any client-sent `x-pomerium-original-host` value, so upstream services can trust it.

To remove this header, add it to [`remove_request_headers`](#remove-request-headers):

```yaml
remove_request_headers:
  - x-pomerium-original-host
```

## Set Request Headers

**Set Request Headers** allows you to set both static and dynamic values for given request headers. Static values can be useful if you want to pass along additional information to upstream applications as headers, or to set a fixed authentication header on the request.

The dynamic values enable you to pass ID and Access tokens from your identity provider to upstream applications.

To pass dynamic values from the user's OIDC claim to an upstream service, see [JWT Claim Headers](https://www.pomerium.com/docs/reference/jwt-claim-headers.md).

Neither HTTP/2 [pseudo-headers](https://www.rfc-editor.org/rfc/rfc9113.html#PseudoHeaderFields) (for example, `:authority`) nor the `Host` header may be modified via this mechanism. The request path may instead be modified using the [Path Rewriting Settings](https://www.pomerium.com/docs/reference/routes/path-rewriting.md) and the `Host` header may be modified using the [Host Header Settings](#host-rewrite) above.

### How to Configure

**Core:**

| **YAML**/**JSON** setting | **Type**               | **Usage**    |
| :------------------------ | :--------------------- | :----------- |
| `set_request_headers`     | map of key-value pairs | **optional** |

### Examples

Pass static header values in the request:

```yaml
- from: https://verify.corp.example.com
  to: https://verify.pomerium.com
  policy:
    - allow:
        or:
          - email:
              is: user@example.com
  set_request_headers:
    # Set a fixed Basic Auth username and password (root:hunter42)
    Authorization: Basic cm9vdDpodW50ZXI0Mg==
    # Set a custom header
    X-Your-favorite-authenticating-Proxy: 'Pomerium'
    # To include a '$' character in a header value:
    X-Hello: $$world # header value is set to "$world"
```

Pass ID token, access token, and client certificate fingerprint (if present) as dynamic headers in the request:

```yaml
- from: https://verify.corp.example.com
  to: https://verify.pomerium.com
  policy:
    - allow:
        or:
          - email:
              is: user@example.com
  set_request_headers:
    x-pomerium-idp-id-token: ${pomerium.id_token}
    x-pomerium-idp-access-token: ${pomerium.access_token}
    x-pomerium-client-cert-fingerprint: ${pomerium.client_cert_fingerprint}
```

**Enterprise:**

**Kubernetes:**

| **[Annotation name](https://www.pomerium.com/docs/deploy/k8s/ingress.md#set-ingress-annotations)** | **Type** | **Usage** |
| :-- | :-- | :-- |
| `set_request_headers` | map of key-value pairs | **optional** |

```yaml
ingress.pomerium.io/set_request_headers: |
  X-Test: X-Value
```

### Pass Dynamic Tokens in Headers

The following token substitutions are available:

| **Token** | **Value** |
| :-- | :-- |
| `${pomerium.access_token}` | OAuth access token from the identity provider\* |
| `${pomerium.client_cert_fingerprint}` | Short form SHA-256 fingerprint of the presented client certificate (if [downstream mTLS](https://www.pomerium.com/docs/internals/certificates-and-tls.md) is enabled) |
| `${pomerium.client_cert_san_dns}` | Comma-separated list of any DNS Subject Alternative Names (SANs) from the presented client certificate |
| `${pomerium.client_cert_san_email}` | Comma-separated list of any email address Subject Alternative Names (SANs) from the presented client certificate |
| `${pomerium.id_token}` | OIDC ID token from the identity provider\* |
| `${pomerium.jwt}` | [Pomerium JWT](https://www.pomerium.com/docs/capabilities/getting-users-identity.md) (this is the same value as in the [`X-Pomerium-Jwt-Assertion` header](https://www.pomerium.com/docs/reference/routes/pass-identity-headers-per-route.md)) |

\*The ID token and access token are not available when using the [Hosted Authenticate](https://www.pomerium.com/docs/capabilities/authentication.md) service.

**Note:** Token values must use the `${pomerium.<token>}` syntax. To include a literal `$` character in a header value, use `$$`.

Be very careful when passing access tokens to an upstream application. This may allow the application to make other authenticated requests on behalf of the user.

### Rewrite Request Headers

In addition to token substitutions, request headers can be rewritten using `${pomerium.request.headers["HEADER-NAME"]}`. For example if a request had a header `X-Jwt: JWT` and you would like to send it as `Authorization: Bearer JWT`, you could do so using:

```yaml
set_request_headers:
  Authorization: Bearer ${pomerium.request.headers["X-Jwt"]}
```

## Remove Request Headers

**Remove Request Headers** allows you to remove given request headers. This can be useful if you want to prevent privacy information from being passed to upstream applications.

### How to Configure

**Core:**

| **YAML**/**JSON** setting | **Type**           | **Usage**    |
| :------------------------ | :----------------- | :----------- |
| `remove_request_headers`  | `array of strings` | **optional** |

### Examples

```yaml
- from: https://verify.corp.example.com
  to: https://verify.pomerium.com
  policy:
    - allow:
        or:
          - email:
              is: user@example.com
  remove_request_headers:
    - X-Email
    - X-Username
```

**Enterprise:**

**Kubernetes:**

| **[Annotation name](https://www.pomerium.com/docs/deploy/k8s/ingress.md#set-ingress-annotations)** | **Type** | **Usage** |
| :-- | :-- | :-- |
| `remove_request_headers` | `array of strings` | **optional** |

```yaml
ingress.pomerium.io/remove_request_headers: |
  - X-Email
  - X-User
```

## Set Response Headers

**Set Response Headers** allows you to set static values for the given response headers. These headers will take precedence over the global [`set_response_headers`](https://www.pomerium.com/docs/reference/set-response-headers.md).

### How to Configure

**Core:**

| **YAML**/**JSON** setting | **Type**               | **Usage**    |
| :------------------------ | :--------------------- | :----------- |
| `set_response_headers`    | map of key-value pairs | **optional** |

### Examples

```yaml
set_response_headers:
  X-Test: X-Value
```

**Enterprise:**

**Kubernetes:**

| **[Annotation name](https://www.pomerium.com/docs/deploy/k8s/ingress.md#set-ingress-annotations)** | **Type** | **Usage** |
| :-- | :-- | :-- |
| `set_response_headers` | map of key-value pairs | **optional** |

```yaml
ingress.pomerium.io/set_response_headers: |
  X-Test: X-Value
```

## Rewrite Response Headers

**Rewrite Response Headers** allows you to modify response headers before they are returned to the client. The `header` field will match the HTTP header name, and `prefix` will be replaced with `value`.

### How to Configure

**Core:**

| **YAML**/**JSON** setting  | **Type**           | **Usage**    |
| :------------------------- | :----------------- | :----------- |
| `rewrite_response_headers` | `array of objects` | **optional** |

### Examples

If the upstream server returns a header:

```text
Location: http://localhost:8000/two/some/path/
```

And the policy has this config:

```yaml
rewrite_response_headers:
  - header: Location
    prefix: http://localhost:8000/two/
    value: http://frontend/one/
```

The browser would be redirected to: `http://frontend/one/some/path/`. This is similar to nginx's [`proxy_redirect` option](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect), but can be used for any header.

**Enterprise:**

**Kubernetes:**

| **[Annotation name](https://www.pomerium.com/docs/deploy/k8s/ingress.md#set-ingress-annotations)** | **Type** | **Usage** |
| :-- | :-- | :-- |
| `rewrite_response_headers` | `array of objects` | **optional** |

### Examples

If the upstream server returns a header:

```text
Location: http://localhost:8000/two/some/path/
```

And the Ingress object has this annotation:

```yaml
ingress.pomerium.io/rewrite_response_headers: |
  - header: Location
    prefix: http://localhost:8000/two/
    value: http://frontend/one/
```

The browser would be redirected to: `http://frontend/one/some/path/`. This is similar to nginx's [`proxy_redirect` option](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect), but can be used for any header.
