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

# Traffic Policy for Devices

> Authenticate, rate limit, and control access to your devices at ngrok's edge using Traffic Policy.

[Traffic Policy](/traffic-policy/) lets you configure access controls once and enforce them on every device in your fleet.
No firmware pushes, OTA updates, or truck rolls required to update security rules.

Use Traffic Policy to:

* **Authenticate and restrict traffic before it reaches your devices.** Require JWTs, OAuth, or specific IP ranges so only authorized traffic can reach your fleet, and rate limit noisy consumers before they overwhelm a device.
* **Access services, not entire devices.** Unlike VPNs, ngrok exposes exactly the service each consumer needs and not a single port or process more. Use [internal endpoints](/gateway/internal-endpoints/) combined with [Cloud Endpoints](/gateway/cloud-endpoints/) to control which services are accessible and to whom, and to [forward and load balance traffic](/gateway/cloud-endpoints/forwarding-and-load-balancing/) across them.
* **Update policy without touching devices.** When a new security requirement comes in, update one Traffic Policy and the change applies across your entire fleet immediately. No need to push updates to individual devices.

## Restrict access by IP

Limit access to specific IP addresses or CIDR ranges:

The following [Traffic Policy](/traffic-policy)
configuration demonstrates how to restrict access to specific IP addresses
using the `restrict-ips` action.

#### Example Traffic Policy document

<CodeGroup>
  ```yaml policy.yml theme={null}
  on_tcp_connect:
    - actions:
        - type: restrict-ips
          config:
            enforce: true
            allow:
              - 1.1.1.1/32
            deny:
              - 110.0.0.0/8
  ```

  ```json policy.json theme={null}
  {
    "on_tcp_connect": [
      {
        "actions": [
          {
            "type": "restrict-ips",
            "config": {
              "enforce": true,
              "allow": [
                "1.1.1.1/32"
              ],
              "deny": [
                "110.0.0.0/8"
              ]
            }
          }
        ]
      }
    ]
  }
  ```
</CodeGroup>

This configuration will ensure that only requests from the IP `1.1.1.1` are
allowed, while requests from the IP `110.0.0.0`
are denied.

#### Example request

If the request comes from an allowed IP, the response will proceed as normal. If
the request comes from a denied IP, the connection will be closed:

```bash theme={null}
$ telnet 5.tcp.ngrok.io 22984

Trying...
Connected to 5.tcp.ngrok.io.
Connection closed by foreign host.
```

See the [restrict-ips action reference](/traffic-policy/actions/restrict-ips/) for details.

## JWT validation

Require a valid JWT token on every request:

The following [Traffic Policy](/traffic-policy/)
configuration is an example configuration of the `jwt-validation` action. For a
more real-world example, check out the [Auth0 guide](/integrations/jwt-validation/auth0/).

#### Example Traffic Policy document

<CodeGroup>
  ```yaml policy.yml theme={null}
  on_http_request:
    - actions:
        - type: jwt-validation
          config:
            issuer:
              allow_list:
                - value: https://example.com/issuer
            audience:
              allow_list:
                - value: urn:example:api
            http:
              tokens:
                - type: access_token
                  method: header
                  name: Authorization
                  prefix: 'Bearer '
                - type: it+jwt
                  method: body
                  name: _id_token
            jws:
              allowed_algorithms:
                - RS256
                - ES256
              keys:
                sources:
                  additional_jkus:
                    - https://example.com/issuer/jku
  ```

  ```json policy.json theme={null}
  {
    "on_http_request": [
      {
        "actions": [
          {
            "type": "jwt-validation",
            "config": {
              "issuer": {
                "allow_list": [
                  {
                    "value": "https://example.com/issuer"
                  }
                ]
              },
              "audience": {
                "allow_list": [
                  {
                    "value": "urn:example:api"
                  }
                ]
              },
              "http": {
                "tokens": [
                  {
                    "type": "access_token",
                    "method": "header",
                    "name": "Authorization",
                    "prefix": "Bearer "
                  },
                  {
                    "type": "it+jwt",
                    "method": "body",
                    "name": "_id_token"
                  }
                ]
              },
              "jws": {
                "allowed_algorithms": [
                  "RS256",
                  "ES256"
                ],
                "keys": {
                  "sources": {
                    "additional_jkus": [
                      "https://example.com/issuer/jku"
                    ]
                  }
                }
              }
            }
          }
        ]
      }
    ]
  }
  ```
</CodeGroup>

#### Example request

```bash theme={null}
$ curl --request GET \
  --url http://example-api.ngrok.app/ \
  --header 'authorization: Bearer <VALID-JWT>'
```

```http theme={null}
HTTP/2 200 OK
content-type: text/html

...
```

In this example, a request is sent to the API with a valid JWT token in
the `Authorization` header with the `Bearer` prefix and getting back a `200 OK`
response.

See the [jwt-validation action reference](/traffic-policy/actions/jwt-validation/) for full configuration options.

## OAuth

Require login via Google, GitHub, Microsoft, or other providers:

<CodeGroup>
  ```yaml policy.yml theme={null}
  on_http_request:
    - actions:
        - type: oauth
          config:
            provider: google
            client_id: '{your oauth client id}'
            client_secret: '{your oauth client secret}'
            scopes:
              - https://www.googleapis.com/auth/userinfo.profile
              - https://www.googleapis.com/auth/userinfo.email
  ```

  ```json policy.json theme={null}
  {
    "on_http_request": [
      {
        "actions": [
          {
            "type": "oauth",
            "config": {
              "provider": "google",
              "client_id": "{your oauth client id}",
              "client_secret": "{your oauth client secret}",
              "scopes": [
                "https://www.googleapis.com/auth/userinfo.profile",
                "https://www.googleapis.com/auth/userinfo.email"
              ]
            }
          }
        ]
      }
    ]
  }
  ```
</CodeGroup>

See the [OAuth action reference](/traffic-policy/actions/oauth/) for full configuration options.

## Rate limit by host header

Prevent a misbehaving integrator, customer app, or internal service from overwhelming your devices:

The following [Traffic Policy](/traffic-policy/)
configuration demonstrates how to use the `rate-limit` action to rate limit
all incoming requests by the `Host` header.

#### Example Traffic Policy document

<CodeGroup>
  ```yaml policy.yml {10} theme={null}
  on_http_request:
    - actions:
        - type: rate-limit
          config:
            name: Only allow 30 requests per minute
            algorithm: sliding_window
            capacity: 30
            rate: 60s
            bucket_key:
              - 'hasReqHeader(''host'') ? getReqHeader(''host'')[0] : ''unknown'''
  ```

  ```json policy.json {13} theme={null}
  {
    "on_http_request": [
      {
        "actions": [
          {
            "type": "rate-limit",
            "config": {
              "name": "Only allow 30 requests per minute",
              "algorithm": "sliding_window",
              "capacity": 30,
              "rate": "60s",
              "bucket_key": [
                "hasReqHeader('host') ? getReqHeader('host')[0] : 'unknown'"
              ]
            }
          }
        ]
      }
    ]
  }
  ```
</CodeGroup>

For this example, assume that ngrok is pointing at the upstream service
[https://httpbin.org](https://httpbin.org).

#### Example request

```bash theme={null}
$ curl https://httpbin.ngrok.app/get
```

```http theme={null}
HTTP/2 429
retry-after: 24
```

In this example, a connection attempt to `httpbin.ngrok.app` using the `curl`
command returns a `429` status code with a `retry-after` header indicating
the number of seconds to wait before retrying the request.

See the [rate-limit action reference](/traffic-policy/actions/rate-limit/) for details.

## Forward traffic to internal services

Route public traffic to internal endpoints so devices are never directly exposed.

This example configuration will set up a public endpoint (`forward-internal-example.ngrok.app`) forwarding all traffic it receives to a internal endpoint (`example.internal`) that forwards the request to port `80` on your local machine. Since it is forwarding all traffic to the internal endpoint, no traffic will be sent to `8080` which is the upstream port for the public endpoint.

#### Example Traffic Policy document

<CodeGroup>
  ```yaml policy.yml theme={null}
  on_http_request:
    - actions:
        - type: forward-internal
          config:
            url: https://example.internal
  ```

  ```json policy.json theme={null}
  {
    "on_http_request": [
      {
        "actions": [
          {
            "type": "forward-internal",
            "config": {
              "url": "https://example.internal"
            }
          }
        ]
      }
    ]
  }
  ```
</CodeGroup>

#### Start an internal endpoint

```bash theme={null}
ngrok http 80 --url example.internal
```

#### Start public endpoint with Traffic Policy

```bash theme={null}
ngrok http 8080 --url forward-internal-example.ngrok.app --traffic-policy-file /path/to/policy.yml
```

### Example request

```bash theme={null}
$ curl https://forward-internal-example.ngrok.app -v
 ...
> GET / HTTP/2
> Host: forward-internal-example.ngrok.app
> User-Agent: curl/[version]
> Accept: */*
...
```

This request will be forwarded to the internal endpoint `https://example.internal` which will then forward the request to port `80` on your local machine.

```http theme={null}
GET / HTTP/1.1
Host: forward-internal-example.ngrok.app
User-Agent: curl/[version]
Accept: */*
X-Forwarded-For: [ngrok IP]
X-Forwarded-Host: forward-internal-example.ngrok.app
X-Forwarded-Proto: https
Accept-Encoding: gzip
```

See the [forward-internal action reference](/traffic-policy/actions/forward-internal/) for details.

## Next steps

* [Traffic Policy reference](/traffic-policy/): explore all available actions
* [Security](/guides/device-gateway/security): credential management, mTLS, and compliance
* [Cloud-to-device](/guides/device-gateway/cloud-to-device): configure internal and Cloud Endpoints for your device services
