> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/honojs/hono/llms.txt
> Use this file to discover all available pages before exploring further.

# Proxy

> Fetch API wrapper for proxying HTTP requests

The Proxy helper provides a secure and convenient way to proxy HTTP requests through your Hono application. It automatically handles hop-by-hop headers, encoding, and provides security features to prevent header injection attacks.

## Import

```typescript theme={null}
import { proxy } from 'hono/proxy'
```

## Basic Usage

Proxy requests to another server:

```typescript theme={null}
import { proxy } from 'hono/proxy'

const originServer = 'example.com'

app.get('/proxy/:path', (c) => {
  const path = c.req.param('path')
  return proxy(`http://${originServer}/${path}`)
})
```

## Function Signature

```typescript theme={null}
function proxy(
  input: string | URL | Request,
  init?: ProxyRequestInit
): Promise<Response>
```

<ParamField path="input" type="string | URL | Request" required>
  The destination URL or Request object to proxy to
</ParamField>

<ParamField path="init" type="ProxyRequestInit">
  Optional configuration object (extends RequestInit with proxy-specific options)
</ParamField>

**Returns**: `Promise<Response>` - A Response object ready to be returned from your handler

## Proxy Options

### raw

Pass the original request to copy method, body, and headers:

```typescript theme={null}
app.all('/proxy/:path', (c) => {
  return proxy(`http://${originServer}/${c.req.param('path')}`, {
    raw: c.req.raw,
  })
})
```

<ParamField path="raw" type="Request">
  Original Request object to copy method, body, and headers from
</ParamField>

### headers

Customize or override headers:

```typescript theme={null}
app.get('/proxy/:path', (c) => {
  return proxy(`http://${originServer}/${c.req.param('path')}`, {
    headers: {
      ...c.req.header(),
      'X-Forwarded-For': '127.0.0.1',
      'X-Forwarded-Host': c.req.header('host'),
      Authorization: undefined, // Remove Authorization header
    },
  })
})
```

<ParamField path="headers" type="HeadersInit | Record<string, string | undefined>">
  Headers to send with the proxied request. Set to `undefined` to remove a header.
</ParamField>

### customFetch

Use a custom fetch implementation:

```typescript theme={null}
const customFetch = async (request: Request) => {
  console.log('Proxying request:', request.url)
  return fetch(request)
}

app.get('/proxy/:path', (c) => {
  return proxy(`http://${originServer}/${c.req.param('path')}`, {
    customFetch,
  })
})
```

<ParamField path="customFetch" type="(request: Request) => Promise<Response>">
  Custom fetch function for making the proxied request
</ParamField>

### strictConnectionProcessing

Enable RFC 9110 compliant Connection header processing:

```typescript theme={null}
app.get('/internal-proxy/:path', (c) => {
  return proxy(`http://${internalServer}/${c.req.param('path')}`, {
    raw: c.req.raw,
    strictConnectionProcessing: true,
  })
})
```

<ParamField path="strictConnectionProcessing" type="boolean" default="false">
  * `false` (default): Ignores Connection header to prevent Hop-by-Hop Header Injection attacks. **Recommended for untrusted clients.**
  * `true`: Processes Connection header per RFC 9110 and removes listed headers. **Only use in trusted environments.**
</ParamField>

<Warning>
  **Security**: Only enable `strictConnectionProcessing` in trusted environments. When `false` (default), the Connection header is ignored to prevent potential security vulnerabilities.
</Warning>

## Complete Example

### Simple Proxy

```typescript theme={null}
import { Hono } from 'hono'
import { proxy } from 'hono/proxy'

const app = new Hono()

app.get('/proxy', (c) => {
  return proxy('https://example.com/')
})

export default app
```

### Forward All Request Data

Proxy the entire request including method, body, and headers:

```typescript theme={null}
import { proxy } from 'hono/proxy'

const originServer = 'api.example.com'

app.all('/api/*', (c) => {
  const path = c.req.path.replace(/^\/api/, '')
  return proxy(`https://${originServer}${path}`, {
    raw: c.req.raw,
    headers: {
      'X-Forwarded-Host': c.req.header('host'),
    },
  })
})
```

### Modify Response

Modify the proxied response before returning:

```typescript theme={null}
import { proxy } from 'hono/proxy'

app.get('/proxy/:path', async (c) => {
  const res = await proxy(`http://${originServer}/${c.req.param('path')}`, {
    headers: {
      'X-Forwarded-For': '127.0.0.1',
    },
  })
  
  // Remove sensitive headers from response
  res.headers.delete('Set-Cookie')
  res.headers.delete('X-Internal-Header')
  
  return res
})
```

### Add Authentication

Add authentication to proxied requests:

```typescript theme={null}
import { proxy } from 'hono/proxy'

app.get('/secure-proxy/*', async (c) => {
  // Verify client authentication
  const token = c.req.header('Authorization')
  if (!token) {
    return c.json({ error: 'Unauthorized' }, 401)
  }
  
  const path = c.req.path.replace(/^\/secure-proxy/, '')
  return proxy(`https://${originServer}${path}`, {
    headers: {
      'Authorization': 'Bearer secret-backend-token',
      'X-Client-Token': token,
    },
  })
})
```

### Handle Query Parameters

```typescript theme={null}
import { proxy } from 'hono/proxy'

app.get('/search', (c) => {
  const query = c.req.query('q')
  const url = new URL('https://api.example.com/search')
  url.searchParams.set('q', query)
  
  return proxy(url.toString())
})
```

## Automatic Processing

The proxy helper automatically:

### Removes Hop-by-Hop Headers

The following headers are automatically removed from both request and response per [RFC 2616](https://datatracker.ietf.org/doc/html/rfc2616#section-13.5.1):

* `Connection`
* `Keep-Alive`
* `Proxy-Authenticate`
* `Proxy-Authorization`
* `TE`
* `Trailer`
* `Transfer-Encoding`
* `Upgrade`

### Handles Accept-Encoding

The `Accept-Encoding` header is automatically removed from the request. The runtime will handle compression natively.

### Handles Content-Encoding

If the response has `Content-Encoding`, it's removed along with `Content-Length` to prevent decompression issues.

## Security Considerations

<Warning>
  **Hop-by-Hop Header Injection**: By default (`strictConnectionProcessing: false`), the Connection header is ignored to prevent attackers from manipulating which headers are removed. Only enable strict processing in trusted environments.
</Warning>

<Warning>
  **Credentials Exposure**: Be careful when forwarding request headers with `...c.req.header()`. This may expose credentials like `Authorization` or `Cookie` to the target server. Explicitly control which headers are forwarded.
</Warning>

<Warning>
  **Open Proxy**: Avoid creating an open proxy that allows users to proxy to arbitrary URLs. Always validate or restrict destination URLs.
</Warning>

## Validation Example

Restrict proxy destinations for security:

```typescript theme={null}
import { proxy } from 'hono/proxy'

const ALLOWED_HOSTS = ['api.example.com', 'cdn.example.com']

app.get('/proxy/:host/:path', async (c) => {
  const host = c.req.param('host')
  const path = c.req.param('path')
  
  if (!ALLOWED_HOSTS.includes(host)) {
    return c.json({ error: 'Host not allowed' }, 403)
  }
  
  return proxy(`https://${host}/${path}`)
})
```

## Error Handling

Handle fetch errors gracefully:

```typescript theme={null}
import { proxy } from 'hono/proxy'

app.get('/proxy/:path', async (c) => {
  try {
    return await proxy(`http://${originServer}/${c.req.param('path')}`)
  } catch (error) {
    console.error('Proxy error:', error)
    return c.json({ error: 'Proxy failed' }, 502)
  }
})
```

## Type Definitions

```typescript theme={null}
interface ProxyRequestInit extends Omit<RequestInit, 'headers'> {
  raw?: Request
  headers?:
    | HeadersInit
    | [string, string][]
    | Record<string, string | undefined>
  customFetch?: (request: Request) => Promise<Response>
  strictConnectionProcessing?: boolean
}

function proxy(
  input: string | URL | Request,
  init?: ProxyRequestInit
): Promise<Response>
```

## Best Practices

<CardGroup cols={2}>
  <Card title="Validate Destinations" icon="shield-check">
    Always validate or allowlist destination URLs to prevent open proxy vulnerabilities
  </Card>

  <Card title="Control Headers" icon="lock">
    Explicitly specify which headers to forward rather than forwarding all headers
  </Card>

  <Card title="Remove Credentials" icon="key">
    Set sensitive headers like `Authorization` to `undefined` when they shouldn't be forwarded
  </Card>

  <Card title="Handle Errors" icon="triangle-exclamation">
    Wrap proxy calls in try-catch blocks and return appropriate error responses
  </Card>
</CardGroup>

<Info>
  The proxy helper returns a fully-formed Response object that can be returned directly from your handler or modified before returning.
</Info>
