# Serverless API Gateway

Open-source API gateway on Cloudflare Workers. Config-driven routing, JWT auth, Auth0, CORS, service binding, and variable mapping at the edge.

## Introduction

The Serverless API Gateway is a globally distributed, Cloudflare Workers–powered solution that simplifies how you manage and secure your APIs. Whether you’re stitching together multiple microservices or transforming requests on the fly, this gateway brings crucial features—routing, CORS, authentication, service binding, and more—into a single, lightweight tool.

### Goals and Motivation

Modern applications rely on APIs for data exchange, yet securing and organizing these APIs can be a headache. Traditional reverse proxies or monolithic API gateways often require complex setups, dedicated servers, or costly managed solutions. The Serverless API Gateway emerged to address these pain points:

* **Security at the Edge:** Enforce JWT-based authentication or integrate with Auth0, ensuring only valid requests pass through.
* **Simple, Config-Driven Routing:** Avoid sprawling or duplicated routing logic. Define paths in a JSON file and let the gateway do the heavy lifting.
* **Global Reach, No Servers:** Because it’s built on Cloudflare Workers, your APIs are served from Cloudflare’s edge network—no server upkeep required.
* **Adaptable for Microservices:** Tightly couple front-end routes to multiple backends or Worker services in one place, reducing architectural complexity.
* **Cost-Effective:** Only pay for the Cloudflare Workers usage (with a generous free tier), bypassing the overhead of maintaining dedicated gateways.

### Where It Fits in Your Architecture

In a typical microservices environment, each service (e.g., Users, Payments, Notifications) might be deployed separately. The Serverless API Gateway sits in front of these services:

```markdown
[ Client / Frontend ]
           |  (API calls)
           v
  ┌───────────────────────────────────┐
  │  Serverless API Gateway (Worker) │
  │   - Routing & Path Matching      │
  │   - CORS & Auth                  │
  │   - Request Transformation       │
  │   - Service Binding (Workers)    │
  └───────────────────────────────────┘
           |
           v
 [ Users Service ]   [ Payment Service ]   [ External API ]  ...

```

* **Client**: Sends HTTP requests to a single gateway URL (e.g., `my-api.example.com`).
* **Gateway (this project)**: Matches each request to a route, applies JWT or Auth0 checks, transforms headers/queries if needed, and proxies/calls the correct backend.
* **Backend Services**: Focus solely on business logic—relying on the gateway to handle cross-cutting concerns like authentication and cross-origin allowances.

By centralizing these features at the Worker layer, you can unify your security model and reduce the boilerplate in downstream microservices.

### Key Features at a Glance

* **JS Workers**: Write serverless JavaScript Workers that intercept and modify your API requests and responses on the fly.
* [**Routing (Path and Method)**](/configuration/paths): Simplify your API architecture with flexible path and method-based routing for directing traffic to the appropriate endpoints.
* [**Service Binding**](/configuration/service-binding): Bind your API to a service as Workers, so you can use the Workers capabilities within your API.
* [**CORS**](/configuration/cors): Manage cross-origin resource sharing settings with ease, ensuring your APIs can securely handle requests from different origins.
* [**Authentication (JWT)**](/configuration/authorizer): Secure your APIs by implementing JSON Web Token (JWT) based authentication to validate and manage user access efficiently.
  * **JWT**: Validate tokens using a shared secret (HS256) or RS256 with Auth0’s JWKS.
  * **Supabase OTP**: Optionally integrate phone/email OTP flows if you’re using Supabase.
  * **Auth0 Authentication:** This service offers reliable identity management by simplifying user authentication. It supports multiple providers, ensuring secure, easy integration for developers and users.
* [**Variable Mapping**](/configuration/variable-mapping): Map variables from sources to destinations, allowing you to easily transform your data.

### How It Differs from Traditional Solutions

* **No Dedicated Infrastructure**: Everything runs on Cloudflare’s edge, eliminating the typical overhead of provisioning servers or VMs for a gateway.
* **Fine-Grained Control at the Edge**: Because it’s serverless code, you can place custom logic right where requests arrive, with extremely low latency.
* **Pay-as-You-Go**: Unlike many managed API gateways that charge flat monthly fees or have complex pricing tiers, this leverages Cloudflare’s usage-based model (often free for small workloads). See the [cost breakdown](/getting-started/cost) for real-world pricing estimates.
* **Easier Microservice Integration**: You can tie multiple backends or even *other* Cloudflare Workers to a single, config-driven gateway, rather than chaining or deploying separate proxies.

### Next Steps

* Review the full [Configuration Guide](/configuration/overview) to set up routing, CORS, and authentication.
* Follow the [Getting Started](/getting-started/introduction) instructions to clone, configure, and deploy.
* Deploy to Cloudflare Workers using [Wrangler](/deployment/wrangler) or [GitHub Actions](/deployment/github-actions).


# Introduction

Get started with Serverless API Gateway: clone the repo, install dependencies, configure routes and JWT auth, then deploy to Cloudflare Workers in minutes.

To start using the Serverless API Gateway:

1. Clone the repository:

```
git clone https://github.com/irensaltali/serverlessapigateway.git
```

2. Install dependencies:

```
cd serverlessapigateway
npm install
```

3. Configure your routes, CORS settings, and JWT secrets within the provided configuration files.
4. Deploy your worker to Cloudflare using the command:

```
wrangler deploy
```

(For detailed setup and usage instructions, please see the Cloudflare Workers' [documentation](https://developers.cloudflare.com/workers)). You can also deploy via [GitHub Actions](/deployment/github-actions) for automated CI/CD.

Usage Guidelines

* Ensure that each section of the JSON is correctly formatted according to the [schema](https://github.com/irensaltali/serverlessapigateway/blob/main/serverlessapigateway/src/api-config.schema.json).
* Modify the configuration to suit your application's requirements. See the [Configuration Guide](/configuration/overview) for a full reference of all available settings.
* The configuration should be loaded and parsed by your application at startup.
* Use canonical examples from [`serverlessapigateway/docs/config-examples`](https://github.com/irensaltali/serverlessapigateway/tree/main/serverlessapigateway/docs/config-examples) as the source of truth for docs and onboarding.
* Review the [cost breakdown](/getting-started/cost) to understand Cloudflare Workers pricing for your expected traffic.

### Contributing

Your contributions are what make the Serverless API Gateway an even better API management solution! If you have suggestions for new features, notice a bug, or want to improve the code, please take the following steps:

1. Fork the repository.
2. Implement your changes on a new branch.
3. Submit a pull request with a clear description of your improvements.

### Acknowledgments

A shoutout to the contributors, community members, and the maintainers of Cloudflare Workers for their support and inspiration in making this project a reality.

The Serverless API Gateway is not just another API tool; it's created by developers, for developers, with the vision of making API management a breeze. Let's build together.

### Support

I'm always happy to help with any questions or concerns you may have. Feel free to reach out to me from on [Twitter](https://twitter.com/irensaltali) or [LinkedIn](https://www.linkedin.com/in/irensaltali/).

If you need a more extensive support you can always book on [Superpeer](https://superpeer.com/irensaltali/-/serverless-api-gateway)

### Companies that use Serverless API Gateway

[![](https://github.com/irensaltali/serverlessapigateway/raw/main/docs/img/wope.png)](https://wope.com/)

Let us know if you are using Serverless API Gateway and we can add your company here.\\


# Cost

Serverless API Gateway pricing and cost estimates. Free tier details and per-request calculations based on Cloudflare Workers usage.

The Serverless API Gateway is a powerful open-source solution designed to make your API management tasks straightforward and efficient. At its core, the gateway leverages the robust infrastructure of Cloudflare Workers, enabling you to deploy and run your APIs at the edge with unprecedented speed and scalability. While the API Gateway itself is completely free to use, the only costs to consider are those associated with Cloudflare Workers. These costs are typically minimal, especially for smaller applications, thanks to Cloudflare's generous free tier. As you scale your application, Cloudflare Workers offer competitive pricing options to ensure your costs remain manageable.

Serverless API Gateway does not charge a license fee, route fee, seat fee, or hosted control-plane fee. The project is open source; runtime cost comes from the Cloudflare services and upstream APIs you choose to use.

If you want the latest product-level pricing summary, read the main site's [Serverless API Gateway pricing page](https://serverlessapigateway.com/pricing). Use this GitBook page for docs-side cost context and Cloudflare Worker-specific calculations.

## What affects API gateway cost?

The main cost drivers are:

* Monthly request volume.
* Worker CPU time per request.
* Auth work such as JWT validation or Auth0/Supabase calls.
* Config storage, such as KV, when used.
* Upstream APIs, databases, auth providers, or service bindings called by the gateway.

## Quick Cost View

| Question                             | Short answer                                                              |
| ------------------------------------ | ------------------------------------------------------------------------- |
| Does this repo charge a license fee? | No.                                                                       |
| Do you pay per route?                | No.                                                                       |
| What are you billed for?             | Cloudflare runtime and any services you attach around the gateway.        |
| What raises the total bill?          | More traffic, more auth work, more storage, and more supporting services. |

### Cloudflare Workers Cost

You can find details of pricing [here](https://developers.cloudflare.com/workers/platform/pricing/#workers).

<figure><img src="https://3043851474-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F4WupSiXIjnmS3DnnGGGw%2Fuploads%2FiNomS1rLvD1P25VUCTVr%2FCleanShot%202024-03-03%20at%2012.42.58.png?alt=media&amp;token=0cbad03d-fd5b-4c5b-ae71-bc4b8d43f6e2" alt=""><figcaption></figcaption></figure>

### Calculations

Let's calculate the potential cost of a Serverless API Gateway, using real-life metrics from an existing user. Here are the metrics:

<figure><img src="https://3043851474-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F4WupSiXIjnmS3DnnGGGw%2Fuploads%2FVzQKoAeA3p1AO2wQ3n0L%2FCleanShot%202024-03-03%20at%2012.54.12.png?alt=media&amp;token=4aca212f-32ea-412c-9a0e-9b146f68bcd7" alt=""><figcaption></figcaption></figure>

Based the metrics it is safe to say Serverless API Gateway CPU time average is around 2ms. Here is estimated cost based on request per day.

<figure><img src="https://3043851474-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F4WupSiXIjnmS3DnnGGGw%2Fuploads%2FPJFSgIFM791dubvcOzYJ%2FCleanShot%202024-03-03%20at%2013.25.58.png?alt=media&amp;token=491af0e0-3b5a-4974-9df0-733b5ffcdfcf" alt=""><figcaption></figcaption></figure>

You can find the calculation as a Google Sheet [here](https://docs.google.com/spreadsheets/d/1jkIFQmt4Q6XX7J4wmXIYokZIyT6JQui-rjh-yAFQIHo/edit?usp=sharing). Follow our [Serverless API Gateway Blog](https://blog.serverlessapigateway.com/) to check out comparisons with other API Gateway solutions.

### See Also

* [Getting Started](/getting-started/introduction) -- clone the repository and deploy your first gateway.
* [Deploy with Wrangler](/deployment/wrangler) -- deploy to Cloudflare Workers where these costs apply.
* [Configuration Guide](/configuration/overview) -- set up your API gateway configuration before deploying.
* [Authorizer](/configuration/authorizer) -- auth work can materially affect per-request cost.
* [Supabase OTP](/configuration/supabase-otp) -- passwordless auth flows can add service and runtime cost.


# Overview

Complete configuration reference for the Serverless API Gateway. Covers servers, CORS, JWT authorizer, paths, service binding, and wrangler setup.

This guide explains how to configure the Serverless API Gateway with secure practices for different environments.

## 📁 Configuration Files

### Core Configuration Files

* **`src/api-config.json`** – Main API configuration
* **`src/api-config.schema.json`** – JSON schema for validation
* **`wrangler.toml`** – Cloudflare Workers configuration
* **`wrangler.auth.toml`** – Authentication-specific configuration (should be gitignored)
* **`docs/config-examples/*.json`** – Canonical, schema-validated examples used by tests/docs checks

### Environment-Specific Configurations

You can keep separate config files per environment. If you do, validate each one against `src/api-config.schema.json` before deploy.

## 🔧 Configuration Templates

### Basic API Configuration Template

```json
{
  "$schema": "./api-config.schema.json",
  "title": "Your API Title",
  "description": "Description of your API",
  "cors": {
    "allow_origins": ["https://your-domain.com"],
    "allow_methods": ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
    "allow_headers": ["Content-Type", "Authorization"],
    "expose_headers": ["*"],
    "allow_credentials": true,
    "max_age": 3600
  },
  "paths": [
    {
      "method": "GET",
      "path": "/health",
      "response": { "status": "ok", "version": "1.0.0" }
    },
    {
      "method": "GET",
      "path": "/api/v1/public",
      "response": {
        "message": "This is a public endpoint"
      },
      "auth": false
    }
  ]
}
```

### Supabase Configuration Template

```json
{
  "$schema": "./api-config.schema.json",
  "title": "Supabase API Gateway",
  "description": "API Gateway with Supabase authentication",
  "cors": {
    "allow_origins": ["https://app.example.com"],
    "allow_methods": ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
    "allow_headers": ["*"],
    "expose_headers": ["*"],
    "allow_credentials": true,
    "max_age": 3600
  },
  "authorizer": {
    "type": "supabase",
    "jwt_secret": "$env.SUPABASE_JWT_SECRET",
    "issuer": "https://YOUR_PROJECT_ID.supabase.co/auth/v1",
    "audience": "authenticated"
  },
  "paths": [
    { "method": "GET", "path": "/health", "response": { "status": "ok" } },
    { "method": "POST", "path": "/api/v1/supabase/auth", "integration": { "type": "supabase_passwordless_auth" } },
    { "method": "POST", "path": "/api/v1/supabase/verify", "integration": { "type": "supabase_passwordless_verify" } },
    {
      "method": "GET",
      "path": "/api/v1/protected",
      "response": {
        "status": "success",
        "message": "This is a protected endpoint"
      },
      "auth": true
    }
  ]
}
```

### Auth0 Configuration Template

```json
{
  "$schema": "./api-config.schema.json",
  "title": "Auth0 API Gateway",
  "description": "API Gateway with Auth0 authentication",
  "cors": {
    "allow_origins": ["https://app.example.com"],
    "allow_methods": ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
    "allow_headers": ["*"],
    "expose_headers": ["*"],
    "allow_credentials": true,
    "max_age": 3600
  },
  "authorizer": {
    "type": "auth0",
    "domain": "$env.AUTH0_DOMAIN",
    "client_id": "$env.AUTH0_CLIENT_ID",
    "client_secret": "$secrets.AUTH0_CLIENT_SECRET",
    "redirect_uri": "https://your-api.com/api/v1/auth0/callback",
    "callback_uri": "https://your-api.com/api/v1/auth0/callback-redirect",
    "jwks_uri": "https://your-domain.us.auth0.com/.well-known/jwks.json",
    "scope": "openid profile email"
  },
  "paths": [
    { "method": "GET", "path": "/health", "response": { "status": "ok" } },
    { "method": "GET", "path": "/api/v1/auth0/callback", "integration": { "type": "auth0_callback" } },
    { "method": "GET", "path": "/api/v1/auth0/profile", "integration": { "type": "auth0_userinfo" }, "auth": true },
    {
      "method": "GET",
      "path": "/api/v1/protected",
      "response": {
        "status": "success",
        "message": "This is a protected endpoint"
      },
      "auth": true
    }
  ]
}
```

### Wrangler Configuration Template

```toml
# wrangler.toml
name = "your-api-gateway"
main = "src/index.js"
compatibility_date = "2025-01-01"
compatibility_flags = ["nodejs_compat"]
send_metrics = true
minify = true
workers_dev = false

find_additional_modules = true
rules = [
    { type = "ESModule", globs = ["services/*.js"]}
]

# Environment variables (non-sensitive)
[vars]
ENVIRONMENT = "production"
API_VERSION = "1.0.0"
# Add your non-sensitive environment variables here
# SUPABASE_URL = "https://YOUR_PROJECT_ID.supabase.co"
# AUTH0_DOMAIN = "your-domain.us.auth0.com"
# AUTH0_CLIENT_ID = "your_client_id"

# Secrets are set using: wrangler secret put SECRET_NAME
```

## ✅ Canonical Examples

Use these files as the source of truth for configuration examples:

* `serverlessapigateway/docs/config-examples/minimal.json`
* `serverlessapigateway/docs/config-examples/auth0.json`
* `serverlessapigateway/docs/config-examples/supabase.json`

## Configuration Sections

For detailed documentation on each configuration section, see:

* [Servers](/configuration/servers) -- define upstream server aliases and URLs.
* [CORS](/configuration/cors) -- configure cross-origin resource sharing policies.
* [Authorizer](/configuration/authorizer) -- set up JWT-based authentication with HS256 or Auth0.
* [Paths](/configuration/paths) -- define path-based API routing, methods, and integrations.
* [Service Binding](/configuration/service-binding) -- bind API routes to Cloudflare Worker services.
* [Variable Mapping](/configuration/variable-mapping) -- transform request headers and query parameters dynamically.


# Servers

Define upstream server aliases and URLs for the Serverless API Gateway. Route API traffic to backend services via config-driven server entries.

The `servers` section is an array of objects where each object represents a server configuration.

* `alias`: A shorthand name for the server.
* `url`: The full URL to access the server.

**Example**

```
"servers": [
    {
        "alias": "ngrok",
        "url": "https://a8ee-176-88-98-23.ngrok-free.app"
    }
]
```

### See Also

* [Service Binding](/configuration/service-binding) -- bind to Cloudflare Workers instead of external HTTP servers.
* [Paths](/configuration/paths) -- reference server aliases in path integration settings to route requests.
* [Configuration Guide](/configuration/overview) -- full configuration reference including servers, CORS, and authorization.

\\


# Service Binding

Configure Cloudflare Workers service bindings in Serverless API Gateway. Bind API routes to Worker services for modular, edge-native serverless integrations.

### Overview

Service Binding allows you to connect your API to a service as Workers, enabling you to leverage the capabilities of Workers within your API. This feature enhances the flexibility and functionality of your API, allowing for seamless integration with serverless functions.

### Example Service

Here’s a simple example of a service that responds with a message:

```javascript
export default class Service {
  async fetch(request, env, ctx) {
    return new Response("Hello from Worker 1!", {
      headers: { "content-type": "text/plain" },
    });
  }
}
```

### API Configuration

To bind a service to your API, you need to define it in your API configuration. Below is an example of how to configure your API to use the service defined above:

```json
{
    "$schema": "./api-config.schema.json",
    "title": "API Gateway Config",
    "description": "Configuration for the Serverless API Gateway",
    "services": [
        {
            "alias": "endpoint1",
            "entrypoint": "./services/endpoint1"
        }
    ],
    "paths": [
        {
            "method": "GET",
            "path": "/api/v1/endpoint1",
            "integration": {
                "type": "service",
                "binding": "endpoint1"
            }
        }
    ]
}
```

#### Explanation

* **Service Definition**: The service is defined in the `services` array with an alias (`endpoint1`) and an entry point pointing to the service file.
* **Path Integration**: In the `paths` array, a new path is created that uses the service binding. The `integration` type is set to `service`, and the `binding` references the alias of the service.

### How to Use

1. **Create Your Service**: Write your service logic in a JavaScript file and export it as shown in the example above.
2. **Update API Configuration**: Add your service to the `services` array in the API configuration and create a path that integrates with your service.
3. **Deploy Your API**: Once your configuration is set, deploy your API to make the service available.

### Benefits of Service Binding

* **Modularity**: Keep your API logic modular by separating service functionality into distinct files.
* **Scalability**: Easily scale your services independently from your API.
* **Flexibility**: Utilize the full power of Cloudflare Workers to handle requests and responses dynamically.

### Conclusion

Service Binding is a powerful feature of the Serverless API Gateway that allows you to enhance your API's capabilities by integrating with serverless functions. By following the examples and guidelines provided, you can easily set up and manage your services within your API.

### See Also

* [Servers](/configuration/servers) -- use external HTTP servers instead of (or alongside) Worker service bindings.
* [Paths](/configuration/paths) -- configure path routing and set integration type to `service` for bound Workers.
* [Deployment with Wrangler](/deployment/wrangler) -- deploy your gateway and its bound services to Cloudflare.

For more information, visit the [Serverless API Gateway Documentation](http://docs.serverlessapigateway.com/).


# Paths

Configure path-based API routing in the Serverless API Gateway. Define methods, endpoints, auth, mappings, and server integrations per route.

The paths section is an array of objects where each object represents an API endpoint configuration.

* `method`: HTTP method (GET, POST, etc.).
* `path`: URL path of the API endpoint.
* `integration`: Server integration settings.
  * `http` and `http_proxy` are both accepted for HTTP proxy integrations.
* `auth`: Indicates if the path requires authentication.
* `mapping`: Defines mappings for headers and query parameters.
* `variables`: Sets variables used in the endpoint.
* `response`: Specifies the response structure for the endpoint.

### See Also

* [Add and Remove Prefix](/configuration/add-and-remove-prefix) -- manipulate URL prefixes when proxying requests to upstream servers.
* [Servers](/configuration/servers) -- define the upstream servers referenced in path `integration` settings.
* [Variable Mapping](/configuration/variable-mapping) -- transform request headers and query parameters using dynamic templates.


# Add and Remove Prefix

Add or remove URL path prefixes when proxying requests in the Serverless API Gateway. Rewrite or strip path segments before forwarding to upstream servers.

````json
{
    ...
    "servers": [
        {   
            "alias": "prefixing",
            "url": "https://sub.serverlessapigw.com/prefix/"
        },
        ...
    ],
    ...
    "paths": [
        {
            "method": "GET",
            "path": "/{.+}",
            "integration": {
                "type": "http_proxy",
                "server": "prefixing"
            }
        },
```
````

With the above configuration, any GET request to the API will be proxied to `'https://sub.serverlessapigw.com/prefix'`.

For example: `GET https://api.yourdomain.com/path` will be proxied to `GET https://sub.serverlessapigw.com/prefix/path`.

This method can also be used to remove a portion of the path from the beginning:

````
{
    ...
    "servers": [
        {   
            "alias": "prefixing",
            "url": "https://sub.serverlessapigw.com"
        },
        ...
    ],
    ...
    "paths": [
        {
            "method": "GET",
            "path": "/prefix/{.+}",
            "integration": {
                "type": "http_proxy",
                "server": "prefixing"
            }
        },
```
````

With this configuration, `GET https://api.yourdomain.com/prefix/path` will be proxied to `GET https://sub.serverlessapigw.com/path`.

### See Also

* [Paths](/configuration/paths) -- full reference for path-based routing configuration including methods, auth, and mappings.
* [Servers](/configuration/servers) -- define the upstream server aliases used in prefix-based routing.


# Authorizer

Configure JWT authorization with HS256 for the Serverless API Gateway. Includes JOSE JWT error codes, claim validation failures, and fixes for common 401 token errors.

The authorizer section configures how the gateway validates bearer tokens before a protected route reaches its upstream service. If you searched for `ERR_JWS_SIGNATURE_VERIFICATION_FAILED`, `JWT claim validation failed`, or other gateway JWT errors, this page is the starting point.

Serverless API Gateway currently supports JWT (JSON Web Token) based authorization with HS256 and also documents provider-backed flows such as Auth0 and Supabase elsewhere in the docs.

> Serverless API Gateway now support Auth0. Check its integration [page](/configuration/auth0).

Use the authorizer when a route should reject invalid bearer tokens before the request reaches an upstream service. Public routes such as health checks can stay unauthenticated, while private routes opt into authorization through route configuration.

* `type`: Type of authorization (e.g., JWT).
* `secret`: Secret key for authorization.
* `algorithm`: Algorithm used for token validation.
* `audience`: Intended audience of the token.
* `issuer`: The issuer of the token.

**Example**

```
{
    "authorizer": {
        "type": "jwt",
        "secret": "{YOUR_SECRET_KEY}",
        "algorithm": "HS256",
        "audience": "opensourcecommunity",
        "issuer": "serverlessapigw"
    },
}
```

## Quick Fix Checklist

Use this checklist before debugging deeper JWT failures:

| Check                  | What to verify                                 | Why it matters                                         |
| ---------------------- | ---------------------------------------------- | ------------------------------------------------------ |
| Signing secret or key  | Matches the token issuer                       | Prevents signature failures                            |
| `issuer`               | Matches the token `iss` claim exactly          | Prevents claim validation errors                       |
| `audience`             | Matches the token `aud` claim exactly          | Prevents claim validation errors                       |
| Token expiration       | `exp` is still valid                           | Prevents `ERR_JWT_EXPIRED`                             |
| Protected route config | Route actually has `auth: true` where expected | Prevents false assumptions about gateway auth behavior |

### JWT Error

Serverless API Gateway uses [JOSE JWT](https://github.com/panva/jose) and error states implemented with its error types. Example response:

```json
{
    "error": "Signature verification failed",
    "code": "ERR_JWS_SIGNATURE_VERIFICATION_FAILED"
}
```

Most production JWT failures fall into one of four buckets:

| Error code                              | Common cause                                                  | First thing to check                                       |
| --------------------------------------- | ------------------------------------------------------------- | ---------------------------------------------------------- |
| `ERR_JWS_SIGNATURE_VERIFICATION_FAILED` | Token was signed with a different secret or key.              | Confirm the gateway secret matches the issuer.             |
| `ERR_JWT_CLAIM_VALIDATION_FAILED`       | `issuer`, `audience`, or another claim does not match config. | Compare configured issuer/audience with the token payload. |
| `ERR_JWT_EXPIRED`                       | Token `exp` is in the past.                                   | Refresh or mint a new token.                               |
| `ERR_JWKS_NO_MATCHING_KEY`              | JWKS does not contain the token `kid`.                        | Confirm the JWKS URL and key rotation state.               |

Do not debug these errors by disabling validation. The safer path is to decode the token payload, compare it with the gateway authorizer config, and verify the signing key or secret used by the identity provider.

## Most Common 401 Root Causes

| Symptom                                 | Likely cause                                                   | First action                                                    |
| --------------------------------------- | -------------------------------------------------------------- | --------------------------------------------------------------- |
| `ERR_JWS_SIGNATURE_VERIFICATION_FAILED` | Wrong secret, wrong key, or token signed by a different issuer | Compare the gateway secret or key source with the actual issuer |
| `ERR_JWT_CLAIM_VALIDATION_FAILED`       | `iss` or `aud` mismatch                                        | Decode the token and compare values exactly                     |
| `ERR_JWT_EXPIRED`                       | Token expired                                                  | Refresh or mint a new token                                     |
| `AUTH_ERROR`                            | General verification failure                                   | Inspect the token format, issuer, and config together           |

For a route-level walkthrough, see [JWT Common 401 Errors](/security/jwt-hs256-setup/jwt-common-401-errors) and [JWT Issuer and Audience Checks](/security/jwt-hs256-setup/jwt-issuer-and-audience-checks).

### Error Codes and Responses

#### JOSEAlgNotAllowed

An error returns when a JOSE Algorithm is not allowed per developer preference.

Response

```json
{
    "error": "Algorithm not allowed",
    "code": "ERR_JOSE_ALG_NOT_ALLOWED"
}
```

#### JWEDecryptionFailed

An error returns when a JWE ciphertext decryption fails.

**Response**

```json
{
    "error": "Decryption failed",
    "code": "ERR_JWE_DECRYPTION_FAILED"
}
```

#### JWEInvalid

An error returns when the JWE format is invalid.

**Response**

```json
{
    "error": "Invalid JWE",
    "code": "ERR_JWE_INVALID"
}
```

#### JWTExpired

An error returns when a JWT has expired.

**Response**

```json
{
    "error": "Token has expired.",
    "code": "ERR_JWT_EXPIRED"
}
```

This means the token signature may be valid, but the token is no longer usable. Refresh the token or sign in again.

#### JWTClaimValidationFailed

An error returns when validation of a JWT claim fails.

**Response**

```json
{
    "error": "JWT claim validation failed",
    "code": "ERR_JWT_CLAIM_VALIDATION_FAILED"
}
```

This often happens when staging and production use different `issuer` or `audience` values. Keep those values documented next to each environment's gateway config.

#### JWTInvalid

An error returns when the JWT is invalid.

**Response**

```json
{
    "error": "Invalid JWT",
    "code": "ERR_JWT_INVALID"
}
```

#### JWKSNoMatchingKey

An error returns when no matching key is found in the JWKS.

**Response**

```json
{
    "error": "No matching key found in JWKS.",
    "code": "ERR_JWKS_NO_MATCHING_KEY"
}
```

#### JWKSInvalid

An error returns when the JWKS is invalid.

**Response**

```json
{
    "error": "Invalid JWKS",
    "code": "ERR_JWKS_INVALID"
}
```

#### JWKSMultipleMatchingKeys

An error returns when multiple matching keys are found in the JWKS.

**Response**

```json
{
    "error": "Multiple matching keys found in JWKS.",
    "code": "ERR_JWKS_MULTIPLE_MATCHING_KEYS"
}
```

#### JWSInvalid

An error thrown when the JWS is invalid.

**Response**

```json
{
    "error": "Invalid JWS",
    "code": "ERR_JWS_INVALID"
}
```

#### JWSSignatureVerificationFailed

An error returns when JWS signature verification fails.

**Response**

```json
{
    "error": "Signature verification failed",
    "code": "ERR_JWS_SIGNATURE_VERIFICATION_FAILED"
}
```

This is usually the query and error string people search for most. Check the signing secret first, then check whether the token came from the expected environment or identity provider.

#### JWT Verification Failed

An error thrown for any other JWT verification failures not specifically covered by the other errors.

**Response**

```json
{
    "error": "JWT verification failed",
    "code": "AUTH_ERROR"
}
```

### See Also

* [Configuration Guide](/configuration/overview) -- full configuration reference including authorizer, CORS, and server settings.
* [Paths](/configuration/paths) -- define which API endpoints require authentication using the `auth` flag.
* [CORS](/configuration/cors) -- configure cross-origin settings that work alongside your authorization layer.
* [Authentication Guide](/configuration/authentication) -- compare JWT, Auth0, and Supabase authentication flows.
* [JWT Common 401 Errors](/security/jwt-hs256-setup/jwt-common-401-errors) -- troubleshoot common token verification failures.
* [JWT Issuer and Audience Checks](/security/jwt-hs256-setup/jwt-issuer-and-audience-checks) -- debug claim mismatches safely.


# Authentication

Configure API gateway authentication with JWT, Auth0, and Supabase. Supports OAuth 2.0, OTP passwordless login, and token-based auth.

This guide explains how to configure and use authentication with the Serverless API Gateway, supporting JWT, Auth0, and Supabase integrations.

The Serverless API Gateway supports multiple authentication strategies. You can protect any route by setting `"auth": true` in its path configuration, and the gateway will validate incoming tokens using the configured [authorizer](/configuration/authorizer).

## Supported Authentication Providers

| Provider     | Type                       | Use Case                                                                                                             |
| ------------ | -------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| **JWT**      | Token-based (HS256)        | Bring your own identity provider; validate tokens with a shared secret. See [Authorizer](/configuration/authorizer). |
| **Auth0**    | OAuth 2.0 / OpenID Connect | Managed identity with social logins, MFA, and enterprise connections. See [Auth0 Integration](/configuration/auth0). |
| **Supabase** | Passwordless OTP           | Email OTP, phone OTP, and magic link authentication. See [Supabase OTP Integration](/configuration/supabase-otp).    |

## Quick Start

### 1. Configuration Setup

Create your `src/api-config.json` file with one of the authentication providers:

**For Supabase:**

```json
{
  "$schema": "./api-config.schema.json",
  "title": "Supabase Integration",
  "description": "Configuration for Supabase authentication",
  "cors": {
    "allow_origins": ["https://app.example.com"],
    "allow_methods": ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
    "allow_headers": ["*"],
    "expose_headers": ["*"],
    "allow_credentials": true,
    "max_age": 3600
  },
  "authorizer": {
    "type": "supabase",
    "jwt_secret": "$env.SUPABASE_JWT_SECRET",
    "issuer": "https://YOUR_PROJECT_ID.supabase.co/auth/v1",
    "audience": "authenticated"
  },
  "paths": [
    { "method": "GET", "path": "/health", "response": { "status": "ok" } },
    { "method": "POST", "path": "/api/v1/supabase/auth", "integration": { "type": "supabase_passwordless_auth" } },
    { "method": "POST", "path": "/api/v1/supabase/verify", "integration": { "type": "supabase_passwordless_verify" } },
    {
      "method": "GET",
      "path": "/api/v1/protected",
      "response": {
        "status": "protected endpoint",
        "message": "You are successfully authenticated!"
      },
      "auth": true
    }
  ]
}
```

**For Auth0:**

```json
{
  "$schema": "./api-config.schema.json",
  "title": "Auth0 Integration",
  "description": "Configuration for Auth0 authentication",
  "cors": {
    "allow_origins": ["https://app.example.com"],
    "allow_methods": ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
    "allow_headers": ["*"],
    "expose_headers": ["*"],
    "allow_credentials": true,
    "max_age": 3600
  },
  "authorizer": {
    "type": "auth0",
    "domain": "$env.AUTH0_DOMAIN",
    "client_id": "$env.AUTH0_CLIENT_ID",
    "client_secret": "$secrets.AUTH0_CLIENT_SECRET",
    "redirect_uri": "https://your-api.com/api/v1/auth0/callback",
    "callback_uri": "https://your-api.com/api/v1/auth0/callback-redirect",
    "jwks_uri": "https://your-domain.us.auth0.com/.well-known/jwks.json",
    "scope": "openid profile email"
  },
  "paths": [
    { "method": "GET", "path": "/health", "response": { "status": "ok" } },
    { "method": "GET", "path": "/api/v1/auth0/callback", "integration": { "type": "auth0_callback" } },
    { "method": "GET", "path": "/api/v1/auth0/profile", "integration": { "type": "auth0_userinfo" }, "auth": true },
    {
      "method": "GET",
      "path": "/api/v1/protected",
      "response": {
        "status": "protected endpoint",
        "message": "You are successfully authenticated!"
      },
      "auth": true
    }
  ]
}
```

**For JWT (custom provider):**

```json
{
  "authorizer": {
    "type": "jwt",
    "secret": "$env.JWT_SECRET",
    "algorithm": "HS256",
    "audience": "your-audience",
    "issuer": "your-issuer"
  },
  "paths": [
    {
      "method": "GET",
      "path": "/api/v1/protected",
      "response": { "status": "protected" },
      "auth": true
    }
  ]
}
```

See the [Authorizer](/configuration/authorizer) page for all JWT configuration options and supported error codes.

### 2. Environment Variables and Secrets

**For Supabase:**

```bash
# Environment Variables (in wrangler.toml)
SUPABASE_URL=https://YOUR_PROJECT_ID.supabase.co

# Secrets (use wrangler secret put)
wrangler secret put SUPABASE_JWT_SECRET
wrangler secret put SUPABASE_SERVICE_ROLE_KEY
```

**For Auth0:**

```bash
# Environment Variables (in wrangler.toml)
AUTH0_DOMAIN=your-domain.us.auth0.com
AUTH0_CLIENT_ID=your_client_id_here

# Secrets (use wrangler secret put)
wrangler secret put AUTH0_CLIENT_SECRET
## Optional if you use "jwks" instead of "jwks_uri" in authorizer:
wrangler secret put AUTH0_JWKS
```

**For JWT:**

```bash
wrangler secret put JWT_SECRET
```

### 3. Deploy

```bash
wrangler deploy
```

## Authentication Flows

### Supabase OTP Flow

1. **Send OTP**: `POST /api/v1/supabase/auth` with `{"email": "user@example.com"}` or `{"phone": "+1234567890"}`
2. **Verify OTP**: `POST /api/v1/supabase/verify` with the email/phone and the 6-digit token
3. **Use Token**: Include `Bearer YOUR_ACCESS_TOKEN` in the `Authorization` header

For detailed configuration, including magic link vs OTP differences and troubleshooting, see the [Supabase OTP Configuration Guide](/configuration/supabase-otp). If Supabase sends a magic link instead of a numeric code, start there before debugging the verify endpoint.

### Auth0 OAuth Flow

1. **Authorization URL**: Direct users to Auth0 login via the callback-redirect endpoint
2. **Callback**: Auth0 redirects to your callback URL with authorization code
3. **Token Exchange**: Callback endpoint exchanges code for tokens automatically
4. **Use Token**: Include the ID token in the `Authorization` header

For setup steps, required fields, and path configuration, see the [Auth0 Integration Guide](/configuration/auth0).

### JWT Flow

1. **Obtain Token**: Generate a JWT from your own identity provider or auth server
2. **Include Token**: Send it in the `Authorization: Bearer <token>` header
3. **Validation**: The gateway validates the signature, audience, and issuer

For JWT configuration details, see [Authorizer](/configuration/authorizer).

## Protecting Routes

Any path can require authentication by adding `"auth": true`:

```json
{
  "method": "GET",
  "path": "/api/v1/protected-resource",
  "integration": {
    "type": "http_proxy",
    "url": "https://backend.example.com/resource"
  },
  "auth": true
}
```

When `"auth": true` is set, the gateway validates the `Authorization` header using the configured authorizer before forwarding the request. If validation fails, the gateway returns a `401 Unauthorized` response.

## Security Best Practices

* Keep JWT secrets secure by storing them as [Wrangler secrets](https://developers.cloudflare.com/workers/configuration/secrets/)
* Use HTTPS for all callback URLs
* Rotate credentials regularly
* Send access tokens only in the `Authorization: Bearer <token>` header
* Send refresh tokens in `X-Refresh-Token` header or JSON body, never in URL query parameters
* Configure [CORS](/configuration/cors) to restrict allowed origins to your frontend domain

For additional Supabase OTP tips, see the [Supabase OTP Configuration Guide](/configuration/supabase-otp).

For production-ready schema-valid examples, use:

* `serverlessapigateway/docs/config-examples/auth0.json`
* `serverlessapigateway/docs/config-examples/supabase.json`

## Related Pages

* [Authorizer Configuration](/configuration/authorizer) -- JWT validation, error codes, and supported algorithms
* [Auth0 Integration](/configuration/auth0) -- Auth0-specific setup and OAuth flow
* [Supabase OTP Integration](/configuration/supabase-otp) -- Supabase email/phone OTP and magic link configuration
* [Cost](/getting-started/cost) -- estimate how auth work affects your Cloudflare runtime usage
* [CORS Configuration](/configuration/cors) -- cross-origin settings for browser-based auth flows
* [Integrations Overview](/configuration/integrations) -- all available integration types


# CORS

Configure CORS (Cross-Origin Resource Sharing) for the Serverless API Gateway. Set allowed origins, methods, headers, and preflight cache.

The CORS section defines the CORS policy for your application.

* `allow_origins`: Specifies which origins are allowed.
* `allow_methods`: Lists the HTTP methods allowed.
* `allow_headers`: Headers that are allowed in requests.
* `expose_headers`: Headers that are exposed in responses.
* `allow_credentials`: Indicates whether credentials are supported.
* `max_age`: Specifies the cache duration for preflight requests.

**Example**

```
"cors": {
    "allow_origins": [
        "https://example.com",
        "https://example2.com"
    ],
    "allow_methods": [
        "GET",
        "POST",
        "PUT",
        "DELETE"
    ],
    "allow_headers": [
        "Content-Type",
        "Authorization"
    ],
    "expose_headers": [
        "Content-Type",
        "Authorization"
    ],
    "allow_credentials": true,
    "max_age": 86400
}
```

### See Also

* [Authorizer](/configuration/authorizer) -- set up JWT authentication that works alongside your CORS policy.
* [Servers](/configuration/servers) -- define the upstream servers that your CORS-enabled gateway proxies to.
* [Configuration Guide](/configuration/overview) -- full configuration reference including all sections.

\\


# Variable Mapping

Map and transform request headers, query params, and JWT claims in the Serverless API Gateway. Dynamic variable templates for edge routing.

### Overview

Variable mapping in the Serverless API Gateway allows for the transformation of request attributes before they reach the intended endpoint. This process involves modifying request headers and query parameters based on dynamic values derived from the request itself, JWT payload, configuration variables, or global variables. Such transformations are crucial for implementing custom logic, enriching requests with additional data, and ensuring seamless integration between different parts of your API ecosystem.

### How Mapping Works

The mapping functionality is implemented through the `mapping` configs, which takes a request and `variables` and applies specified mappings to its headers and query parameters. This process consists of two main steps: resolving the dynamic values based on the mapping configuration and updating the request with these resolved values.

#### Resolving Dynamic Values

Dynamic values in the mapping configuration are specified with templates that reference different sources, such as request headers, JWT payload, configuration variables, or global variables. The `resolveValue` function parses these templates, extracts the required values from the appropriate sources, and returns the resolved values to be used in the request transformation.

**Template Syntax**

* `$request.header.[headerName]`: Retrieves a value from the request headers.
* `$request.jwt.[claimName]`: Retrieves a value from the decoded JWT payload.
* `$config.[variableName]`: Retrieves a value from the configuration variables defined in the API gateway config.
* `$request.query.[parameterName]`: Retrieves a value from the query parameters of the request.

#### Applying Mappings

Mappings can be applied to both request headers and query parameters:

* **Headers Mapping**: For each entry in the `headers` mapping configuration, the Serverless API Gateway function resolves the specified template to a value and sets this value in the request's headers.
* **Query Parameters Mapping**: Similar to headers, for each entry in the `query` mapping configuration, the Serverless API Gateway resolves the specified template to a value and adds or updates this value in the request's query parameters.

### Configuration Example

The mapping configuration is part of the API gateway configuration file, under the `paths` section. Here is a simplified example showing how mappings can be configured:

```json
"paths": [
    {
        "method": "GET",
        "path": "/api/v1/example",
        "integration": {
            "type": "http_proxy",
            "server": "serverlessapigateway-api"
        },
        "auth": true,
        "mapping": {
            "headers": {
                "x-custom-header": "$request.jwt.customClaim"
            },
            "query": {
                "user": "$request.query.userId"
            }
        },
        "variables": {
            "api_key": "API_KEY_VALUE"
        }
    }
]
```

In this example, a custom header `x-custom-header` is added to the request, with its value set to a custom claim from the JWT payload. Additionally, a query parameter `user` is set based on the `userId` query parameter in the original request.

### Conclusion

The mapping functionality in the Serverless API Gateway offers a powerful mechanism for dynamically manipulating API requests. By utilizing templates to resolve values from various sources, developers can implement sophisticated logic to transform requests on the fly, ensuring that the API gateway can efficiently handle the diverse needs of modern web applications.

### See Also

* [Priority Variables](/configuration/priority-variables) -- understand how local and global variable precedence works in mappings.
* [Paths](/configuration/paths) -- configure the routes where variable mappings are applied.
* [Authorizer](/configuration/authorizer) -- set up JWT authentication to enable `$request.jwt` template values in mappings.


# Priority Variables

Variable resolution priority in Serverless API Gateway mappings. Local config variables override global variables per endpoint.

### Variable Resolution Hierarchy

The Serverless API Gateway uses a specific order of precedence when resolving variables to ensure that the most relevant and specific settings are applied to each request. This order is as follows:

1. **Local (Config) Variables**: These are variables defined within the scope of a specific path in the API gateway configuration. They are intended to be specific to the individual endpoint or set of endpoints defined by that path configuration. When a variable is referenced in a mapping, the system first checks if it exists as a local variable for that path.
2. **Global Variables**: Global variables are defined at a higher level in the API gateway configuration and are intended to provide default values that apply across multiple paths or the entire API. If a variable referenced in a mapping is not found among the local variables, the system then checks the global variables for a match.

#### Why Local Variables Take Precedence

The prioritization of local variables over global ones is designed to provide flexibility and specificity in API configuration. This approach allows developers to:

* **Override Global Settings**: Define specific behaviors or values for certain endpoints without changing the global configuration. This is useful for exceptions or special cases within your API.
* **Maintain Configurational Flexibility**: Easily adjust the behavior of individual endpoints or groups of endpoints without affecting the entire API, making it easier to test changes or roll out endpoint-specific features.
* **Enhance Configuration Clarity**: Keep configurations clear and understandable by allowing endpoint-specific variables to be defined close to where they are used, improving maintainability and readability.

#### Example

Consider an API configuration where a global variable `database-url` is defined to point to a primary database. However, for a specific endpoint, you want to route requests to a different, endpoint-specific database. By defining a local variable `database-url` within the path configuration for that endpoint, the API gateway will use this local variable in preference to the global one for requests to that endpoint, ensuring that requests are routed to the correct database.

```json
"variables": {
    "global_variable": "global_value",
    "database-url": "sqlite://primary-db.sqlite" // Global variable
},
"paths": [
    {
        "method": "GET",
        "path": "/api/v1/special-endpoint",
        "variables": {
            "database-url": "sqlite://special-db.sqlite" // Local variable takes precedence
        }
    }
]
```

In this setup, requests to `/api/v1/special-endpoint` will use `sqlite://special-db.sqlite` for the `database-url`, overriding the global setting of `sqlite://primary-db.sqlite`.

#### Conclusion

The prioritization of local variables over global variables in the Serverless API Gateway's mapping functionality provides a powerful tool for fine-tuning API behavior. It allows developers to create more specific, flexible, and maintainable API configurations, ensuring that each part of the API behaves exactly as needed without unnecessary global changes.

### See Also

* [Variable Mapping](/configuration/variable-mapping) -- full guide to mapping templates, header transformations, and query parameter mappings.
* [Paths](/configuration/paths) -- define path-level variables and mappings within the route configuration.


# Integrations

Serverless API Gateway integrations for authentication, proxying, and service bindings. Connect Auth0, Supabase, HTTP backends, and Cloudflare services.

The Serverless API Gateway provides built-in integrations that handle authentication flows, request proxying, and service bindings with minimal configuration. Each integration is specified in the `paths[].integration.type` field of your `api-config.json`.

For general authentication setup, see the [Authentication Guide](/configuration/authentication). For JWT-based authorization, see [Authorizer](/configuration/authorizer).

## Authentication Integrations

### Auth0

OAuth 2.0 / OpenID Connect integration with [Auth0](https://auth0.com). Supports login redirect, callback handling, token exchange, and user profile retrieval.

* [Auth0 Integration Guide](/configuration/auth0) -- configuration, environment variables, and OAuth flow
* [Auth0 Quickstart](/reader-guides/quickstart-first-proxy/quickstart-auth0-route) -- step-by-step setup

### Supabase OTP

Passwordless authentication via Supabase. Supports email OTP, phone OTP (SMS), and magic links.

* [Supabase OTP Configuration Guide](/configuration/supabase-otp) -- setup, magic link vs OTP, email templates, and troubleshooting
* [Supabase Passwordless Quickstart](/reader-guides/quickstart-first-proxy/quickstart-supabase-passwordless) -- step-by-step setup
* [Authentication Guide](/configuration/authentication) -- compare Supabase with JWT and Auth0 flows

## Integration Type Reference

The `paths[].integration.type` field supports the following values:

### Proxy and Service Integrations

| Type              | Description                                                                  |
| ----------------- | ---------------------------------------------------------------------------- |
| `http`            | Forward the request to an external HTTP endpoint and return the response     |
| `http_proxy`      | Proxy the request to an external HTTP endpoint, preserving headers and path  |
| `service`         | Call an internal service endpoint                                            |
| `service_binding` | Invoke a [Cloudflare Worker service binding](/configuration/service-binding) |

### Auth0 Integrations

| Type                      | Description                                                                        |
| ------------------------- | ---------------------------------------------------------------------------------- |
| `auth0_callback`          | Handle the OAuth callback from Auth0, exchanging the authorization code for tokens |
| `auth0_callback_redirect` | Redirect the user to the Auth0 login page to initiate authentication               |
| `auth0_userinfo`          | Retrieve the authenticated user's profile from Auth0's `/userinfo` endpoint        |
| `auth0_refresh`           | Refresh an expired Auth0 access token using a refresh token                        |

### Supabase Integrations

| Type                             | Description                                                                     |
| -------------------------------- | ------------------------------------------------------------------------------- |
| `supabase_passwordless_auth`     | Send a one-time password (OTP) to an email address or phone number via Supabase |
| `supabase_passwordless_verify`   | Verify the OTP and return JWT access and refresh tokens                         |
| `supabase_passwordless_auth_alt` | Alternative passwordless auth endpoint for custom configurations                |

## Related Pages

* [Authentication Guide](/configuration/authentication) -- configure authentication across providers
* [Authorizer](/configuration/authorizer) -- JWT validation and authorization settings
* [CORS](/configuration/cors) -- cross-origin request configuration
* [Service Binding](/configuration/service-binding) -- Cloudflare Worker service binding setup
* [Paths Configuration](/configuration/paths) -- route and path setup


# Auth0

Configure Auth0 with Serverless API Gateway. Set up Auth0 client ID, client secret, JWKS, callback URLs, and OAuth 2.0 authorization flow.

Integrate [Auth0](https://auth0.com) with the [Serverless API Gateway](/getting-started/introduction) to add OAuth 2.0 / OpenID Connect authentication to your API. This page covers the required configuration parameters, environment variables, path setup, and the authorization flow.

For general authentication concepts and comparison with other providers, see the [Authentication Guide](/configuration/authentication). For JWT-based authorization without a third-party provider, see [Authorizer](/configuration/authorizer).

## Prerequisites

Before configuring the Serverless API Gateway, create an Auth0 application:

1. Log in to your [Auth0 Dashboard](https://manage.auth0.com/)
2. Go to **Applications** and click **Create Application**
3. Choose **Regular Web Application** or **Single Page Application** depending on your use case
4. Note the **Domain**, **Client ID**, and **Client Secret** from the application settings
5. Under **Allowed Callback URLs**, add your gateway callback URL (e.g. `https://your-api-url/api/v1/auth0/callback`)

## Configuration Parameters

```json
{
    "authorizer": {
        "type": "auth0",
        "domain": "your-auth0-domain.auth0.com",
        "client_id": "your-client-id",
        "client_secret": "your-client-secret",
        "redirect_uri": "https://your-api-url/api/v1/auth0/callback",
        "jwks": "{JSON Escaped JWKS}",
        "jwks_uri": "https://your-auth0-domain.auth0.com/.well-known/jwks.json",
        "scope": "openid profile email"
    }
}
```

### Parameters Explained

* **type**: Specifies the type of authorizer being used. In this case, it is set to "auth0".
* **domain**: The Auth0 domain associated with your account. Replace `your-auth0-domain` with your actual Auth0 domain.
* **client\_id**: The unique identifier for your Auth0 application. Found in the Auth0 Dashboard under **Applications** > your app > **Settings**. Replace `your-client-id` with your actual client ID.
* **client\_secret**: The secret key associated with your Auth0 application. This value should be stored as a Wrangler secret, not in plain text. Replace `your-client-secret` with your actual client secret.
* **redirect\_uri**: The URI to which Auth0 will redirect users after authentication. This must match one of the **Allowed Callback URLs** in your Auth0 application settings.
* **jwks**: A JSON Web Key Set (JWKS) containing the public keys used to verify the JWT signatures. Replace the values in the `n`, `kid`, `x5t`, and `x5c` fields with your actual key values. Either `jwks` or `jwks_uri` is required.
* **jwks\_uri**: The URI to retrieve the JWKS from Auth0. Replace `your-auth0-domain` with your actual Auth0 domain. Either `jwks` or `jwks_uri` is required.
* **scope**: The permissions being requested from the user. Common scopes include `openid`, `profile`, and `email`.

## Environment Variables and Secrets

Store sensitive Auth0 credentials securely:

```bash
# Environment variables (in wrangler.toml)
AUTH0_DOMAIN=your-domain.us.auth0.com
AUTH0_CLIENT_ID=your_client_id_here

# Secrets (use wrangler secret put)
wrangler secret put AUTH0_CLIENT_SECRET
# Optional: if you use "jwks" instead of "jwks_uri" in the authorizer config
wrangler secret put AUTH0_JWKS
```

Reference these in your `api-config.json` using the `$env.` and `$secrets.` prefixes:

```json
{
    "authorizer": {
        "type": "auth0",
        "domain": "$env.AUTH0_DOMAIN",
        "client_id": "$env.AUTH0_CLIENT_ID",
        "client_secret": "$secrets.AUTH0_CLIENT_SECRET",
        "redirect_uri": "https://your-api-url/api/v1/auth0/callback",
        "jwks_uri": "https://your-domain.us.auth0.com/.well-known/jwks.json",
        "scope": "openid profile email"
    }
}
```

### Important Notes

* Ensure that sensitive information such as `client_secret` is stored securely using `wrangler secret put` and not exposed in public repositories or logs.
* Update the placeholders in the configuration with your actual Auth0 account details before deployment.
* Test the configuration in a safe environment before moving to production.

## Path Configurations

This section outlines the path configuration for handling the Auth0 OAuth flow. Add these paths to the `paths` array in your `api-config.json`.

### Callback Handler

```json
{
    "method": "GET",
    "path": "/api/v1/auth0/callback",
    "integration": {
        "type": "auth0_callback"
    }
}
```

This integration handles the callback from Auth0, receiving an authorization code. It exchanges this code for access and ID tokens and returns them to the client.

### Login Redirect

```json
{
    "method": "GET",
    "path": "/api/v1/auth0/callback-redirect",
    "integration": {
        "type": "auth0_callback_redirect"
    },
    "auth": false
}
```

This integration facilitates the redirection to the Auth0 login page (`/authorize`), allowing users to authenticate via Auth0. It provides a seamless way to initiate the login process based on the Auth0 configuration.

### User Info

```json
{
    "method": "GET",
    "path": "/api/v1/auth0/profile",
    "integration": {
        "type": "auth0_userinfo"
    },
    "auth": true
}
```

This integration retrieves user information from Auth0 using the `/userinfo` endpoint. It allows applications to access user profile data after successful authentication.

## Auth0 OAuth Flow

The complete authorization flow with Serverless API Gateway and Auth0 works as follows:

1. **Initiate Login** -- Direct the user to your `/api/v1/auth0/callback-redirect` endpoint. This redirects them to the Auth0 login page.
2. **User Authenticates** -- The user logs in through Auth0 (username/password, social login, etc.).
3. **Callback** -- Auth0 redirects back to your `/api/v1/auth0/callback` endpoint with an authorization code.
4. **Token Exchange** -- The gateway exchanges the authorization code for access and ID tokens automatically.
5. **Access Protected Routes** -- Use the returned token in the `Authorization: Bearer <token>` header to call endpoints that have `"auth": true`.

## CORS Configuration

If your frontend calls the Auth0 endpoints from a browser, configure [CORS](/configuration/cors) in your `api-config.json`:

```json
{
  "cors": {
    "allow_origins": ["https://your-frontend.example.com"],
    "allow_methods": ["GET", "POST", "OPTIONS"],
    "allow_headers": ["Authorization", "Content-Type"],
    "allow_credentials": true,
    "max_age": 3600
  }
}
```

## Related Pages

* [Authentication Guide](/configuration/authentication) -- full authentication setup overview
* [Authorizer Configuration](/configuration/authorizer) -- JWT and provider-based authorization details
* [CORS Configuration](/configuration/cors) -- cross-origin request settings
* [Supabase OTP Integration](/configuration/supabase-otp) -- alternative authentication with Supabase
* [Auth0 Quickstart](/reader-guides/quickstart-first-proxy/quickstart-auth0-route) -- step-by-step Auth0 quickstart
* [Auth0 Documentation](https://auth0.com/docs) -- official Auth0 docs


# Supabase OTP

Supabase OTP for Serverless API Gateway. Fix magic link vs OTP issues, configure signInWithOtp, email templates, phone OTP, and verify flows on Cloudflare Workers.

This guide explains how to configure Supabase OTP (one-time password) authentication with the [Serverless API Gateway](/getting-started/introduction). It covers email OTP, phone OTP, `signInWithOtp`, magic link vs OTP behavior, environment variables, email templates, and troubleshooting.

If Supabase is sending magic links instead of 6-digit OTP codes, the short answer is:

* Make sure your Supabase email template renders `{{ .Token }}` instead of `{{ .ConfirmationURL }}`.
* Do not pass `emailRedirectTo` when you want numeric OTP delivery.
* Re-test the flow through the gateway's `supabase_passwordless_auth` and `supabase_passwordless_verify` endpoints.

If you are new to Serverless API Gateway, see the [Introduction](/getting-started/introduction) and the [Supabase Passwordless Quickstart](/reader-guides/quickstart-first-proxy/quickstart-supabase-passwordless) for a step-by-step walkthrough.

## Supabase signInWithOtp Overview

Supabase provides the `signInWithOtp` method for passwordless authentication. It supports two channels:

* **Email OTP** -- sends a 6-digit numeric code to the user's email address.
* **Phone OTP** -- sends a 6-digit code via SMS using a configured SMS provider (Twilio, MessageBird, Vonage, etc.).

When properly configured, the Serverless API Gateway exposes two endpoints that wrap `signInWithOtp` and its verification counterpart:

| Endpoint                       | Integration Type               | Purpose                              |
| ------------------------------ | ------------------------------ | ------------------------------------ |
| `POST /api/v1/supabase/auth`   | `supabase_passwordless_auth`   | Send OTP to email or phone           |
| `POST /api/v1/supabase/verify` | `supabase_passwordless_verify` | Verify the OTP and return JWT tokens |

For authorizer configuration details, see [Authorizer](/configuration/authorizer). For CORS settings when calling these endpoints from a browser, see [CORS](/configuration/cors).

## Quick Fix Checklist

Use this checklist before reading the full guide:

| Check                              | Correct value for OTP code flow | Why it matters                                         |
| ---------------------------------- | ------------------------------- | ------------------------------------------------------ |
| Email template variable            | `{{ .Token }}`                  | Sends a numeric OTP code instead of a link             |
| Redirect option in `signInWithOtp` | Omit `emailRedirectTo`          | Redirect URLs usually push the flow toward magic links |
| Gateway send endpoint              | `POST /api/v1/supabase/auth`    | Triggers the OTP send flow through the Worker          |
| Gateway verify endpoint            | `POST /api/v1/supabase/verify`  | Expects a numeric token, not a clicked link            |
| Supabase project settings          | Email OTP enabled               | Required for email code delivery                       |

## Magic Link vs OTP

A common point of confusion is the difference between magic links and OTP codes in Supabase:

| Behavior                               | Magic Link                         | OTP Code                                                                 |
| -------------------------------------- | ---------------------------------- | ------------------------------------------------------------------------ |
| **Delivery**                           | Email only                         | Email or SMS                                                             |
| **User action**                        | Click a link in the email          | Enter a 6-digit code in your app                                         |
| **Template variable**                  | `{{ .ConfirmationURL }}`           | `{{ .Token }}`                                                           |
| **Requires redirect URL**              | Yes                                | No                                                                       |
| **Use case**                           | Web apps that can handle redirects | Mobile apps, SPAs, or any app where you want an in-app verification flow |
| **Works with gateway verify endpoint** | Not directly                       | Yes                                                                      |

By default, Supabase may send a magic link even when you call `signInWithOtp`. The sections below explain how to force OTP code delivery instead.

## What `signInWithOtp` Creates

Supabase `signInWithOtp` starts a passwordless sign-in flow. For email, the user may receive either a magic link or a numeric OTP depending on the project settings, redirect options, and email template. For phone, the user receives an SMS OTP when SMS auth is configured.

In a typical Serverless API Gateway flow:

1. The client calls the gateway's Supabase auth endpoint with an email or phone number.
2. The gateway calls Supabase to request the OTP.
3. The user submits the OTP to the gateway's verify endpoint.
4. Supabase verifies the OTP and returns tokens.
5. Protected gateway routes validate the resulting Supabase JWT.

The important distinction is that the gateway does not replace Supabase Auth. It brokers the send and verify calls, then validates the resulting JWT on protected routes.

## Issue: Receiving Magic Links Instead of OTP Codes

When you request an email OTP, Supabase sends a magic link instead of a 6-digit OTP code. This happens because the default configuration prioritizes magic links over OTP codes.

## Why This Happens in Gateway Flows

Serverless API Gateway expects the client to:

1. Call the auth endpoint to send a code.
2. Receive a numeric OTP by email or SMS.
3. POST that token to the verify endpoint.

If Supabase sends a magic link instead, the user never receives the numeric code that `supabase_passwordless_verify` expects. The result usually looks like a broken verify step or an `invalid token` response.

## Solution: Configure Supabase Project Settings

### Step 1: Access Supabase Dashboard

1. Go to <https://supabase.com/dashboard>
2. Select your project.
3. Navigate to **Authentication** then **Settings**

### Step 2: Configure Email Auth Settings

In the **Auth Settings** section:

1. **Find "Email OTP" Settings**:
   * Look for **"Email OTP"** configuration
   * Enable **"Email OTP"** if it's disabled
2. **Disable Magic Links** (if needed):
   * Look for **"Magic Link"** settings
   * Consider disabling magic links to force OTP usage
3. **Email Template Settings**:
   * Go to **Authentication** then **Email Templates**
   * Select **"Magic Link"** template
   * Change the template type or configure it for OTP

### Step 3: Use Explicit OTP Configuration in signInWithOtp

```javascript
// In your API call, specify the type explicitly
const { data, error } = await supabase.auth.signInWithOtp({
    email: 'user@example.com',
    options: {
        emailRedirectTo: undefined, // Don't set redirect URL for magic links
        shouldCreateUser: true
    }
});
```

When `emailRedirectTo` is omitted or set to `undefined`, Supabase treats the request as an OTP request rather than a magic link request. This is the most reliable way to ensure OTP code delivery.

`shouldCreateUser` controls whether Supabase should create a new user when the email or phone does not already exist. Use `true` for sign-up or mixed sign-in/sign-up flows. Use `false` when only existing users should be allowed to request an OTP.

## signInWithOtp Options That Matter

| Option             | Recommended value for OTP code flow              | Effect                                            |
| ------------------ | ------------------------------------------------ | ------------------------------------------------- |
| `email`            | User email address                               | Sends a code by email                             |
| `phone`            | User phone number                                | Sends a code by SMS                               |
| `emailRedirectTo`  | Omit it                                          | Helps avoid magic-link behavior                   |
| `shouldCreateUser` | `true` or `false`, depending on your auth policy | Controls whether unknown users can start the flow |

Use `emailRedirectTo` only when you explicitly want a magic link flow. For numeric OTP verification behind the gateway, leave it out.

## Environment Variables

The Serverless API Gateway requires the following environment variables for Supabase OTP integration:

| Variable                    | Storage Method          | Description                                                                                                             |
| --------------------------- | ----------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `SUPABASE_URL`              | `wrangler.toml` env var | Your Supabase project URL, e.g. `https://YOUR_PROJECT_ID.supabase.co`                                                   |
| `SUPABASE_JWT_SECRET`       | `wrangler secret put`   | JWT secret from your Supabase project settings (used by the [authorizer](/configuration/authorizer) to validate tokens) |
| `SUPABASE_SERVICE_ROLE_KEY` | `wrangler secret put`   | Service role key from your Supabase project settings (used server-side to call Supabase Auth API)                       |

If OTP sending fails at the gateway layer, verify these values first before debugging templates or client code.

Set environment variables in `wrangler.toml`:

```toml
[vars]
SUPABASE_URL = "https://YOUR_PROJECT_ID.supabase.co"
```

Set secrets using Wrangler:

```bash
wrangler secret put SUPABASE_JWT_SECRET
wrangler secret put SUPABASE_SERVICE_ROLE_KEY
```

## API Gateway Configuration

Add the Supabase authorizer and passwordless auth paths to your `api-config.json`:

```json
{
  "authorizer": {
    "type": "supabase",
    "jwt_secret": "$env.SUPABASE_JWT_SECRET",
    "issuer": "https://YOUR_PROJECT_ID.supabase.co/auth/v1",
    "audience": "authenticated"
  },
  "paths": [
    {
      "method": "POST",
      "path": "/api/v1/supabase/auth",
      "integration": { "type": "supabase_passwordless_auth" }
    },
    {
      "method": "POST",
      "path": "/api/v1/supabase/verify",
      "integration": { "type": "supabase_passwordless_verify" }
    },
    {
      "method": "GET",
      "path": "/api/v1/protected",
      "response": { "status": "protected endpoint" },
      "auth": true
    }
  ]
}
```

For a full configuration example including CORS, see the [Authentication Guide](/configuration/authentication).

## Email OTP Template Configuration

### Configure Email OTP Template

1. Go to **Authentication** then **Email Templates** in the Supabase Dashboard
2. Select **"Magic Link"** or find **"OTP"** template
3. Ensure the template contains `{{ .Token }}` instead of `{{ .ConfirmationURL }}`

Example OTP email template:

```html
<h2>Your verification code</h2>
<p>Enter this code to verify your email:</p>
<h1>{{ .Token }}</h1>
<p>This code expires in 5 minutes.</p>
```

If your template uses `{{ .ConfirmationURL }}`, the user will receive a clickable magic link. If it uses `{{ .Token }}`, the user will receive a 6-digit numeric OTP code.

## Flow Summary

| Step | Client action                                         | Gateway behavior                          | Supabase behavior                  |
| ---- | ----------------------------------------------------- | ----------------------------------------- | ---------------------------------- |
| 1    | POST email or phone to `/api/v1/supabase/auth`        | Calls `supabase_passwordless_auth`        | Sends OTP or magic link            |
| 2    | User reads email or SMS                               | No gateway step                           | Delivers the code or link          |
| 3    | POST email/phone + token to `/api/v1/supabase/verify` | Calls `supabase_passwordless_verify`      | Verifies token and returns session |
| 4    | Client uses `access_token`                            | Gateway validates JWT on protected routes | Issues tokens                      |

## Supabase Email OTP: Sending and Verifying

### Send Email OTP

```bash
curl -X POST "https://your-gateway.example.com/api/v1/supabase/auth" \
  -H "Content-Type: application/json" \
  -d '{"email": "user@example.com"}'
```

A successful response indicates the OTP was sent. The user should receive a 6-digit code in their inbox.

If the user receives a link instead of a code, check the email template first. The template must render `{{ .Token }}` for an OTP-code experience.

### Verify Email OTP

```bash
curl -X POST "https://your-gateway.example.com/api/v1/supabase/verify" \
  -H "Content-Type: application/json" \
  -d '{"email": "user@example.com", "token": "123456"}'
```

On success, the response includes an `access_token` (JWT) and a `refresh_token`. Use the access token in the `Authorization: Bearer <token>` header when calling protected endpoints.

## Supabase Phone OTP

Phone OTP sends a 6-digit code via SMS instead of email. This is useful for mobile apps or when email deliverability is a concern.

### Prerequisites for Phone OTP

1. Go to **Authentication** then **Settings** in the Supabase Dashboard
2. Find the **"Phone Auth"** section
3. Enable phone authentication
4. Configure your SMS provider (Twilio, MessageBird, Vonage, etc.)
5. Enter the required credentials for your SMS provider

### Send Phone OTP

```bash
curl -X POST "https://your-gateway.example.com/api/v1/supabase/auth" \
  -H "Content-Type: application/json" \
  -d '{"phone": "+1234567890"}'
```

### Verify Phone OTP

```bash
curl -X POST "https://your-gateway.example.com/api/v1/supabase/verify" \
  -H "Content-Type: application/json" \
  -d '{"phone": "+1234567890", "token": "123456"}'
```

The verification response is identical in structure to email OTP verification: you receive a JWT access token and refresh token.

## Troubleshooting

### Still Receiving Magic Links Instead of OTP Codes

Check these in order:

1. **Email template**: Verify the template uses `{{ .Token }}` and not `{{ .ConfirmationURL }}`.
2. **Project settings**: Ensure Email OTP is enabled in Supabase Auth settings.
3. **`emailRedirectTo`**: Remove it from `signInWithOtp`. If it is set, Supabase can switch to a link-based flow.
4. **Gateway flow**: Make sure the client is using `/api/v1/supabase/auth` and `/api/v1/supabase/verify`, not mixing direct Supabase calls with gateway endpoints.
5. **Retest with a fresh email**: This helps rule out template caching or rate-limit noise.

### OTP Code Not Arriving

Check these in order:

1. Look in spam or junk folders.
2. Verify the email address or phone number is correct.
3. Check Supabase Dashboard logs for delivery errors.
4. Confirm your project has not exceeded email or SMS sending limits.
5. For phone OTP, verify the SMS provider credentials and provider logs.

### Token Verification Fails

Check these in order:

1. Confirm the OTP code has not expired.
2. Confirm the client is POSTing to `/api/v1/supabase/verify`.
3. Check that the token is a numeric OTP code, not a clicked magic-link flow.
4. Verify `SUPABASE_JWT_SECRET` and `SUPABASE_SERVICE_ROLE_KEY`.
5. Verify the `issuer` field in the authorizer matches your Supabase project URL.
6. Re-test after sending a brand new code so you are not verifying an old token.

### Code-Level Fix (If Dashboard Configuration Does Not Work)

If the dashboard configuration does not resolve the issue, try using the admin client with explicit OTP type:

```javascript
// Try using admin client with explicit OTP type
const supabase = createClient(
    process.env.SUPABASE_URL, 
    process.env.SUPABASE_SERVICE_ROLE_KEY  // Use service role key
);

const { data, error } = await supabase.auth.admin.generateLink({
    type: 'signup',  // or 'signin'
    email: email,
    options: {
        redirectTo: undefined  // No redirect for OTP
    }
});
```

## Expected Behavior After Configuration

After proper configuration:

* **Email OTP**: You receive a 6-digit code like `123456` in your email.
* **Phone OTP**: You receive a 6-digit code via SMS.
* **Send response**: The auth endpoint confirms that Supabase accepted the OTP request.
* **Verification response**: The verify endpoint returns `access_token` and `refresh_token`.

The key is ensuring your Supabase project is configured to prioritize OTP codes over magic links in the authentication flow.

## Related Pages

* [Authentication Guide](/configuration/authentication) -- full authentication setup for Serverless API Gateway
* [Authorizer Configuration](/configuration/authorizer) -- JWT and provider-based authorization
* [CORS Configuration](/configuration/cors) -- configure cross-origin requests for browser-based OTP flows
* [Auth0 Integration](/configuration/auth0) -- alternative authentication provider
* [Supabase Passwordless Quickstart](/reader-guides/quickstart-first-proxy/quickstart-supabase-passwordless) -- step-by-step quickstart guide
* [Introduction](/getting-started/introduction) -- overview of Serverless API Gateway


# Wrangler

Deploy Serverless API Gateway to Cloudflare Workers using Wrangler CLI. Steps for local dev, environment configs, and production deployment.

[Wrangler](https://developers.cloudflare.com/workers/wrangler/) is the official Cloudflare CLI for building and deploying Workers. The Serverless API Gateway uses Wrangler to push your gateway configuration and worker code to Cloudflare's edge network.

### Prerequisites

1. Install Wrangler globally or as a project dependency:

```bash
npm install -g wrangler
```

2. Authenticate with your Cloudflare account:

```bash
wrangler login
```

3. Ensure your [API configuration](/configuration/overview) (`src/api-config.json`) and `wrangler.toml` are set up correctly.

### Deploying

Deploy the gateway to Cloudflare Workers with a single command:

```bash
wrangler deploy
```

This reads your `wrangler.toml`, bundles the worker code along with your API configuration, and publishes it to Cloudflare's global network.

### Environment-Specific Deploys

Use separate configuration files for different environments (staging, production, auth-specific):

```bash
wrangler deploy --config wrangler.toml
wrangler deploy --config wrangler.auth.toml
```

Keep sensitive configuration files like `wrangler.auth.toml` out of version control by adding them to `.gitignore`.

### Local Development

Test your gateway locally before deploying:

```bash
wrangler dev
```

This starts a local development server that simulates the Cloudflare Workers runtime, allowing you to test routing, CORS, and authorization without deploying.

### Setting Secrets

Store sensitive values like JWT secrets or API keys as encrypted Wrangler secrets rather than placing them in configuration files:

```bash
wrangler secret put JWT_SECRET
```

### See Also

* [Configuration Guide](/configuration/overview) -- set up routing, CORS, authorizer, and server definitions before deploying.
* [GitHub Actions](/deployment/github-actions) -- automate deployments with CI/CD instead of manual Wrangler commands.
* [Getting Started](/getting-started/introduction) -- clone the repository and install dependencies before your first deploy.


# GitHub Actions

Deploy Serverless API Gateway with GitHub Actions. CI/CD workflow using the serverlessapigateway-action and Cloudflare Wrangler action.

You can prepare and deploy the gateway from CI.

## Repository layout

```
.github/
  workflows/
    deploy-serverless-api-gateway.yml
api-config.json
wrangler.toml
```

## Example workflow

```yaml
name: Deploy Serverless API Gateway

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Prepare gateway worker
        uses: irensaltali/serverlessapigateway-action@main
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          configJson: ./api-config.json
          wranglerToml: ./wrangler.toml
          versionTag: v1.0.1

      - name: Deploy to Cloudflare Workers
        uses: cloudflare/wrangler-action@v3
        with:
          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          workingDirectory: worker
```

### Notes

* Store your `CLOUDFLARE_API_TOKEN` as a GitHub Actions secret. Never commit API tokens to the repository.
* The `configJson` parameter should point to your [API configuration file](/configuration/overview), which defines routing, CORS, authorizer, and server settings.
* For local development and manual deploys, see the [Wrangler deployment guide](/deployment/wrangler).


# Getting Started Guides

Build your first HTTP proxy route and confirm that the gateway rewrites and forwards traffic correctly. This guide covers defining a server alias, creating a

Build your first HTTP proxy route and confirm that the gateway rewrites and forwards traffic correctly. This guide covers defining a server alias, creating a wildcard proxy path, and verifying the round-trip response. Start here if you have an existing backend and want to front it with the gateway.

**Last reviewed:** 2026-03-06

## When to use this

Use these quickstart guides when you are setting up Serverless API Gateway for the first time or adding a new integration pattern. Each guide walks through one isolated concern so you can deploy incrementally instead of configuring everything at once.

## Key concepts

* Every quickstart produces a deployable `wrangler.toml` and JSON config pair -- you can run `wrangler deploy` at the end of each guide.
* Guides are ordered from simplest (health endpoint) to most complex (Auth0/Supabase passwordless), so earlier guides serve as prerequisites for later ones.
* Config can come from a local file, Cloudflare KV, or the `SAG_API_CONFIG_JSON` environment variable -- choose based on your deploy workflow.
* All guides use the same JSON config schema, so patterns you learn in one guide transfer directly to others.

## Repo-grounded example

```json
{
  "servers": [
    { "alias": "upstream", "url": "https://api.example.com/base" }
  ],
  "paths": [
    {
      "method": "GET",
      "path": "/proxy/{.+}",
      "integration": {
        "type": "http_proxy",
        "server": "upstream"
      }
    }
  ]
}
```

This snippet defines a single upstream server and a wildcard proxy route. The `server` field references the alias defined in the `servers` array, and the `{.+}` pattern forwards any subpath to the upstream URL.

## Troubleshooting

* If `wrangler deploy` fails with a config error, validate your JSON against the schema file (`api-config.schema.json`) before investigating further.
* If the health endpoint returns 404, confirm that your `wrangler.toml` points to the correct main entrypoint and that the config file is being loaded.
* If JWT or Auth0 routes return 500, check that all required environment variables and secrets are set in your Cloudflare dashboard or `.dev.vars` file.
* Use `wrangler tail` to stream live logs from the deployed worker and see the exact error message the gateway produces.

## Related docs

* [introduction](/getting-started/introduction)
* [overview](/configuration/overview)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Quickstart: Health Endpoint

Ship a minimal health endpoint before you add upstream integrations so deploys are observable from day one. The config returns a static JSON response with no

Ship a minimal health endpoint before you add upstream integrations so deploys are observable from day one. The config returns a static JSON response with no upstream dependency, making it ideal for load balancer checks. Use this as your first route when bootstrapping a new gateway.

**Last reviewed:** 2026-03-06

## When to use this

Use these quickstart guides when you are setting up Serverless API Gateway for the first time or adding a new integration pattern. Each guide walks through one isolated concern so you can deploy incrementally instead of configuring everything at once.

## Key concepts

* Every quickstart produces a deployable `wrangler.toml` and JSON config pair -- you can run `wrangler deploy` at the end of each guide.
* Guides are ordered from simplest (health endpoint) to most complex (Auth0/Supabase passwordless), so earlier guides serve as prerequisites for later ones.
* Config can come from a local file, Cloudflare KV, or the `SAG_API_CONFIG_JSON` environment variable -- choose based on your deploy workflow.
* All guides use the same JSON config schema, so patterns you learn in one guide transfer directly to others.

## Repo-grounded example

```json
{
  "$schema": "./api-config.schema.json",
  "title": "Minimal Gateway",
  "cors": {
    "allow_origins": ["https://app.example.com"],
    "allow_methods": ["GET", "POST", "OPTIONS"],
    "allow_headers": ["Content-Type", "Authorization"],
    "expose_headers": ["X-Request-Id"],
    "allow_credentials": true,
    "max_age": 300
  },
  "paths": [
    {
      "method": "GET",
      "path": "/health",
      "response": { "status": "ok" }
    }
  ]
}
```

This snippet shows the smallest valid gateway config: a CORS policy and a single GET route that returns a static JSON object. The `response` field replaces the need for an upstream service or integration.

## Troubleshooting

* If `wrangler deploy` fails with a config error, validate your JSON against the schema file (`api-config.schema.json`) before investigating further.
* If the health endpoint returns 404, confirm that your `wrangler.toml` points to the correct main entrypoint and that the config file is being loaded.
* If JWT or Auth0 routes return 500, check that all required environment variables and secrets are set in your Cloudflare dashboard or `.dev.vars` file.
* Use `wrangler tail` to stream live logs from the deployed worker and see the exact error message the gateway produces.

## Related docs

* [introduction](/getting-started/introduction)
* [overview](/configuration/overview)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Quickstart: JWT-Protected Route

Protect a single route with HS256 JWT validation without forcing authentication on every endpoint. This guide shows how to add an authorizer block and flag

Protect a single route with HS256 JWT validation without forcing authentication on every endpoint. This guide shows how to add an authorizer block and flag individual paths with `auth: true`. Use this when you control the JWT signing secret and need per-route protection.

**Last reviewed:** 2026-03-06

## When to use this

Use these quickstart guides when you are setting up Serverless API Gateway for the first time or adding a new integration pattern. Each guide walks through one isolated concern so you can deploy incrementally instead of configuring everything at once.

## Key concepts

* Every quickstart produces a deployable `wrangler.toml` and JSON config pair -- you can run `wrangler deploy` at the end of each guide.
* Guides are ordered from simplest (health endpoint) to most complex (Auth0/Supabase passwordless), so earlier guides serve as prerequisites for later ones.
* Config can come from a local file, Cloudflare KV, or the `SAG_API_CONFIG_JSON` environment variable -- choose based on your deploy workflow.
* All guides use the same JSON config schema, so patterns you learn in one guide transfer directly to others.

## Repo-grounded example

```json
{
  "authorizer": {
    "type": "jwt",
    "secret": "$env.JWT_SECRET",
    "algorithm": "HS256",
    "issuer": "https://issuer.example.com",
    "audience": "api-audience"
  },
  "paths": [
    {
      "method": "GET",
      "path": "/private",
      "auth": true,
      "response": { "private": true }
    }
  ]
}
```

This snippet configures the `authorizer` block with HS256 signing, an issuer check, and an audience check. The `auth: true` flag on the `/private` path tells the gateway to require a valid bearer token for that route only.

## Troubleshooting

* If `wrangler deploy` fails with a config error, validate your JSON against the schema file (`api-config.schema.json`) before investigating further.
* If the health endpoint returns 404, confirm that your `wrangler.toml` points to the correct main entrypoint and that the config file is being loaded.
* If JWT or Auth0 routes return 500, check that all required environment variables and secrets are set in your Cloudflare dashboard or `.dev.vars` file.
* Use `wrangler tail` to stream live logs from the deployed worker and see the exact error message the gateway produces.

## Related docs

* [introduction](/getting-started/introduction)
* [overview](/configuration/overview)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Quickstart: Auth0-Protected Route

Stand up an Auth0-backed route when you need hosted identity and token validation at the edge. This guide covers the authorizer block for Auth0, the callback

Stand up an Auth0-backed route when you need hosted identity and token validation at the edge. This guide covers the authorizer block for Auth0, the callback integration, and the environment variables you need to set. Refer to the Auth0 cluster for deeper coverage of JWKS, refresh tokens, and userinfo.

**Last reviewed:** 2026-03-06

## When to use this

Use these quickstart guides when you are setting up Serverless API Gateway for the first time or adding a new integration pattern. Each guide walks through one isolated concern so you can deploy incrementally instead of configuring everything at once.

## Key concepts

* Every quickstart produces a deployable `wrangler.toml` and JSON config pair -- you can run `wrangler deploy` at the end of each guide.
* Guides are ordered from simplest (health endpoint) to most complex (Auth0/Supabase passwordless), so earlier guides serve as prerequisites for later ones.
* Config can come from a local file, Cloudflare KV, or the `SAG_API_CONFIG_JSON` environment variable -- choose based on your deploy workflow.
* All guides use the same JSON config schema, so patterns you learn in one guide transfer directly to others.

## Repo-grounded example

```json
{
  "authorizer": {
    "type": "auth0",
    "domain": "$env.AUTH0_DOMAIN",
    "client_id": "$env.AUTH0_CLIENT_ID",
    "client_secret": "$secrets.AUTH0_CLIENT_SECRET",
    "redirect_uri": "https://api.example.com/api/v1/auth0/callback",
    "callback_uri": "https://app.example.com/auth/callback",
    "jwks_uri": "https://tenant.us.auth0.com/.well-known/jwks.json",
    "scope": "openid profile email"
  },
  "paths": [
    {
      "method": "GET",
      "path": "/api/v1/auth0/callback",
      "integration": { "type": "auth0_callback" }
    }
  ]
}
```

This snippet sets up the Auth0 authorizer with domain, client credentials, JWKS URI, and redirect/callback URIs. The callback path uses the `auth0_callback` integration type, which exchanges the authorization code for tokens at the edge.

## Troubleshooting

* If `wrangler deploy` fails with a config error, validate your JSON against the schema file (`api-config.schema.json`) before investigating further.
* If the health endpoint returns 404, confirm that your `wrangler.toml` points to the correct main entrypoint and that the config file is being loaded.
* If JWT or Auth0 routes return 500, check that all required environment variables and secrets are set in your Cloudflare dashboard or `.dev.vars` file.
* Use `wrangler tail` to stream live logs from the deployed worker and see the exact error message the gateway produces.

## Related docs

* [introduction](/getting-started/introduction)
* [overview](/configuration/overview)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Quickstart: Supabase Passwordless API

Use Supabase OTP flows when your product needs passwordless auth routes behind one Worker gateway. This guide covers both the auth request and verify endpoints.

Use Supabase OTP flows when your product needs passwordless auth routes behind one Worker gateway. This guide covers both the auth request and verify endpoints. If your app already uses Supabase Auth, this is the fastest path to edge-managed passwordless login.

**Last reviewed:** 2026-03-06

## When to use this

Use these quickstart guides when you are setting up Serverless API Gateway for the first time or adding a new integration pattern. Each guide walks through one isolated concern so you can deploy incrementally instead of configuring everything at once.

## Key concepts

* Every quickstart produces a deployable `wrangler.toml` and JSON config pair -- you can run `wrangler deploy` at the end of each guide.
* Guides are ordered from simplest (health endpoint) to most complex (Auth0/Supabase passwordless), so earlier guides serve as prerequisites for later ones.
* Config can come from a local file, Cloudflare KV, or the `SAG_API_CONFIG_JSON` environment variable -- choose based on your deploy workflow.
* All guides use the same JSON config schema, so patterns you learn in one guide transfer directly to others.

## Repo-grounded example

```json
{
  "authorizer": {
    "type": "supabase",
    "jwt_secret": "$env.SUPABASE_JWT_SECRET",
    "issuer": "https://project.supabase.co/auth/v1",
    "audience": "authenticated"
  },
  "paths": [
    {
      "method": "POST",
      "path": "/api/v1/supabase/auth",
      "integration": { "type": "supabase_passwordless_auth" }
    },
    {
      "method": "POST",
      "path": "/api/v1/supabase/verify",
      "integration": { "type": "supabase_passwordless_verify" }
    }
  ]
}
```

This snippet configures the Supabase authorizer with the project JWT secret, issuer, and audience. The two paths use `supabase_passwordless_auth` and `supabase_passwordless_verify` integration types to handle OTP send and verify flows.

## Troubleshooting

* If `wrangler deploy` fails with a config error, validate your JSON against the schema file (`api-config.schema.json`) before investigating further.
* If the health endpoint returns 404, confirm that your `wrangler.toml` points to the correct main entrypoint and that the config file is being loaded.
* If JWT or Auth0 routes return 500, check that all required environment variables and secrets are set in your Cloudflare dashboard or `.dev.vars` file.
* Use `wrangler tail` to stream live logs from the deployed worker and see the exact error message the gateway produces.

## Related docs

* [introduction](/getting-started/introduction)
* [overview](/configuration/overview)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Quickstart: Inline Config with SAG\_API\_CONFIG\_JSON

Use inline config for demos, tests, and disposable environments where a separate config file is unnecessary. The entire gateway definition lives in a single

Use inline config for demos, tests, and disposable environments where a separate config file is unnecessary. The entire gateway definition lives in a single environment variable, which the worker reads at startup. This approach is useful for CI pipelines and preview deployments where you generate config dynamically.

**Last reviewed:** 2026-03-06

## When to use this

Use these quickstart guides when you are setting up Serverless API Gateway for the first time or adding a new integration pattern. Each guide walks through one isolated concern so you can deploy incrementally instead of configuring everything at once.

## Key concepts

* Every quickstart produces a deployable `wrangler.toml` and JSON config pair -- you can run `wrangler deploy` at the end of each guide.
* Guides are ordered from simplest (health endpoint) to most complex (Auth0/Supabase passwordless), so earlier guides serve as prerequisites for later ones.
* Config can come from a local file, Cloudflare KV, or the `SAG_API_CONFIG_JSON` environment variable -- choose based on your deploy workflow.
* All guides use the same JSON config schema, so patterns you learn in one guide transfer directly to others.

## Repo-grounded example

```bash
export SAG_API_CONFIG_JSON='{"paths":[{"method":"GET","path":"/health","response":{"status":"ok"}}]}'
wrangler deploy
```

This snippet shows how to export the full JSON config as the `SAG_API_CONFIG_JSON` environment variable and deploy with Wrangler. The gateway reads this variable at startup when no local config file or KV binding is found.

## Troubleshooting

* If `wrangler deploy` fails with a config error, validate your JSON against the schema file (`api-config.schema.json`) before investigating further.
* If the health endpoint returns 404, confirm that your `wrangler.toml` points to the correct main entrypoint and that the config file is being loaded.
* If JWT or Auth0 routes return 500, check that all required environment variables and secrets are set in your Cloudflare dashboard or `.dev.vars` file.
* Use `wrangler tail` to stream live logs from the deployed worker and see the exact error message the gateway produces.

## Related docs

* [introduction](/getting-started/introduction)
* [overview](/configuration/overview)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Quickstart: KV-Backed Config

Move config into Cloudflare KV when you want the gateway to load its routing definition at runtime. This decouples config updates from worker deploys, so you

Move config into Cloudflare KV when you want the gateway to load its routing definition at runtime. This decouples config updates from worker deploys, so you can change routes without redeploying the worker. Use this when your operations team needs to update routing independently.

**Last reviewed:** 2026-03-06

## When to use this

Use these quickstart guides when you are setting up Serverless API Gateway for the first time or adding a new integration pattern. Each guide walks through one isolated concern so you can deploy incrementally instead of configuring everything at once.

## Key concepts

* Every quickstart produces a deployable `wrangler.toml` and JSON config pair -- you can run `wrangler deploy` at the end of each guide.
* Guides are ordered from simplest (health endpoint) to most complex (Auth0/Supabase passwordless), so earlier guides serve as prerequisites for later ones.
* Config can come from a local file, Cloudflare KV, or the `SAG_API_CONFIG_JSON` environment variable -- choose based on your deploy workflow.
* All guides use the same JSON config schema, so patterns you learn in one guide transfer directly to others.

## Repo-grounded example

```bash
wrangler kv:key put --binding=CONFIG api-config.json ./src/api-config.json
wrangler deploy
```

This snippet uses the Wrangler CLI to write the local JSON config file into a KV namespace bound as `CONFIG`. The gateway reads the `api-config.json` key from KV at startup and falls back to other sources if the key is missing.

## Troubleshooting

* If `wrangler deploy` fails with a config error, validate your JSON against the schema file (`api-config.schema.json`) before investigating further.
* If the health endpoint returns 404, confirm that your `wrangler.toml` points to the correct main entrypoint and that the config file is being loaded.
* If JWT or Auth0 routes return 500, check that all required environment variables and secrets are set in your Cloudflare dashboard or `.dev.vars` file.
* Use `wrangler tail` to stream live logs from the deployed worker and see the exact error message the gateway produces.

## Related docs

* [introduction](/getting-started/introduction)
* [overview](/configuration/overview)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Routing

Use this page to choose the right route shape and avoid accidental matches when multiple patterns overlap. The gateway evaluates exact paths first, then

Use this page to choose the right route shape and avoid accidental matches when multiple patterns overlap. The gateway evaluates exact paths first, then parameterized paths, then wildcard paths. Understanding this order prevents subtle routing bugs where a broad wildcard swallows requests intended for a specific endpoint.

**Last reviewed:** 2026-03-06

## When to use this

Use the routing guides when you need to understand how the gateway matches incoming requests to configured paths. Routing is the core behavior of the gateway -- every request passes through the path matcher before reaching an integration, auth check, or static response.

## Key concepts

* The gateway supports three route shapes: exact paths (`/health`), parameterized paths (`/users/:id`), and wildcard paths (`/proxy/{.+}`). Exact matches take highest priority.
* When multiple routes could match a request, the gateway uses a fixed priority order: exact > parameterized > wildcard. This is not configurable.
* The `method` field accepts standard HTTP methods (`GET`, `POST`, etc.) as well as `ANY`, which matches all methods on that path.
* Prefix add/remove rules transform the path before forwarding to the upstream, letting you decouple public API structure from backend path layout.
* Static response routes skip integration entirely and return the `response` field directly, which is useful for health checks and feature flags.

## Repo-grounded example

```json
{
  "servers": [
    { "alias": "upstream", "url": "https://api.example.com/base" }
  ],
  "paths": [
    {
      "method": "GET",
      "path": "/proxy/{.+}",
      "integration": {
        "type": "http_proxy",
        "server": "upstream"
      }
    }
  ]
}
```

This snippet uses a wildcard pattern `{.+}` to forward all subpaths under `/proxy/` to an upstream server. To add an exact or parameterized route that takes precedence, define it as a separate entry with a concrete path.

## Troubleshooting

* If a request hits the wrong route, check whether a wildcard pattern is matching before your intended exact or parameterized route -- exact always wins over wildcard.
* If an OPTIONS request returns unexpected results, verify whether you have an explicit OPTIONS handler for that path or are relying on the default CORS 204 behavior.
* If prefix removal produces a double-slash in the upstream URL, confirm that both the `remove_prefix` and the upstream `url` do not include trailing/leading slashes that conflict.
* Use `wrangler tail` and look at the matched path in the log output to confirm which route config entry the gateway selected.

## Related docs

* [README](/configuration/paths)
* [add and remove prefix](/configuration/add-and-remove-prefix)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Routing: ANY Method

Use ANY when the backend accepts the same behavior for multiple verbs and you want one config entry. This reduces duplication when a single upstream endpoint

Use ANY when the backend accepts the same behavior for multiple verbs and you want one config entry. This reduces duplication when a single upstream endpoint handles GET, POST, PUT, and DELETE identically. If you need different behavior per method, define separate route entries instead.

**Last reviewed:** 2026-03-06

## When to use this

Use the routing guides when you need to understand how the gateway matches incoming requests to configured paths. Routing is the core behavior of the gateway -- every request passes through the path matcher before reaching an integration, auth check, or static response.

## Key concepts

* The gateway supports three route shapes: exact paths (`/health`), parameterized paths (`/users/:id`), and wildcard paths (`/proxy/{.+}`). Exact matches take highest priority.
* When multiple routes could match a request, the gateway uses a fixed priority order: exact > parameterized > wildcard. This is not configurable.
* The `method` field accepts standard HTTP methods (`GET`, `POST`, etc.) as well as `ANY`, which matches all methods on that path.
* Prefix add/remove rules transform the path before forwarding to the upstream, letting you decouple public API structure from backend path layout.
* Static response routes skip integration entirely and return the `response` field directly, which is useful for health checks and feature flags.

## Repo-grounded example

```json
{
  "servers": [
    { "alias": "upstream", "url": "https://api.example.com/base" }
  ],
  "paths": [
    {
      "method": "GET",
      "path": "/proxy/{.+}",
      "integration": {
        "type": "http_proxy",
        "server": "upstream"
      }
    }
  ]
}
```

This snippet defines a proxy route with a specific method. To use ANY, replace the `method` value with `"ANY"` so the gateway forwards all HTTP methods on that path to the upstream.

## Troubleshooting

* If a request hits the wrong route, check whether a wildcard pattern is matching before your intended exact or parameterized route -- exact always wins over wildcard.
* If an OPTIONS request returns unexpected results, verify whether you have an explicit OPTIONS handler for that path or are relying on the default CORS 204 behavior.
* If prefix removal produces a double-slash in the upstream URL, confirm that both the `remove_prefix` and the upstream `url` do not include trailing/leading slashes that conflict.
* Use `wrangler tail` and look at the matched path in the log output to confirm which route config entry the gateway selected.

## Related docs

* [README](/configuration/paths)
* [add and remove prefix](/configuration/add-and-remove-prefix)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Routing: Explicit OPTIONS Handlers

Add explicit OPTIONS routes when a path needs custom preflight behavior instead of the default CORS 204 response. By default, the gateway handles OPTIONS

Add explicit OPTIONS routes when a path needs custom preflight behavior instead of the default CORS 204 response. By default, the gateway handles OPTIONS automatically using the global CORS config. Define an explicit OPTIONS entry only when a specific path requires different allowed headers, methods, or origins.

**Last reviewed:** 2026-03-06

## When to use this

Use the routing guides when you need to understand how the gateway matches incoming requests to configured paths. Routing is the core behavior of the gateway -- every request passes through the path matcher before reaching an integration, auth check, or static response.

## Key concepts

* The gateway supports three route shapes: exact paths (`/health`), parameterized paths (`/users/:id`), and wildcard paths (`/proxy/{.+}`). Exact matches take highest priority.
* When multiple routes could match a request, the gateway uses a fixed priority order: exact > parameterized > wildcard. This is not configurable.
* The `method` field accepts standard HTTP methods (`GET`, `POST`, etc.) as well as `ANY`, which matches all methods on that path.
* Prefix add/remove rules transform the path before forwarding to the upstream, letting you decouple public API structure from backend path layout.
* Static response routes skip integration entirely and return the `response` field directly, which is useful for health checks and feature flags.

## Repo-grounded example

```json
{
  "cors": {
    "allow_origins": ["https://app.example.com"],
    "allow_methods": ["GET", "POST", "OPTIONS"],
    "allow_headers": ["Content-Type", "Authorization", "X-Refresh-Token"],
    "expose_headers": ["X-Request-Id"],
    "allow_credentials": true,
    "max_age": 300
  }
}
```

This snippet shows the global CORS block that drives the default OPTIONS response. To override this for a specific path, add a route entry with `"method": "OPTIONS"` and a custom `response` or integration.

## Troubleshooting

* If a request hits the wrong route, check whether a wildcard pattern is matching before your intended exact or parameterized route -- exact always wins over wildcard.
* If an OPTIONS request returns unexpected results, verify whether you have an explicit OPTIONS handler for that path or are relying on the default CORS 204 behavior.
* If prefix removal produces a double-slash in the upstream URL, confirm that both the `remove_prefix` and the upstream `url` do not include trailing/leading slashes that conflict.
* Use `wrangler tail` and look at the matched path in the log output to confirm which route config entry the gateway selected.

## Related docs

* [README](/configuration/paths)
* [add and remove prefix](/configuration/add-and-remove-prefix)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Routing: Prefix Add and Remove

Map public paths to upstream paths cleanly when the origin and public API use different prefixes. The gateway can strip a prefix from the incoming path before

Map public paths to upstream paths cleanly when the origin and public API use different prefixes. The gateway can strip a prefix from the incoming path before forwarding, or add a prefix that the upstream expects. This keeps your public API structure independent from backend path conventions.

**Last reviewed:** 2026-03-06

## When to use this

Use the routing guides when you need to understand how the gateway matches incoming requests to configured paths. Routing is the core behavior of the gateway -- every request passes through the path matcher before reaching an integration, auth check, or static response.

## Key concepts

* The gateway supports three route shapes: exact paths (`/health`), parameterized paths (`/users/:id`), and wildcard paths (`/proxy/{.+}`). Exact matches take highest priority.
* When multiple routes could match a request, the gateway uses a fixed priority order: exact > parameterized > wildcard. This is not configurable.
* The `method` field accepts standard HTTP methods (`GET`, `POST`, etc.) as well as `ANY`, which matches all methods on that path.
* Prefix add/remove rules transform the path before forwarding to the upstream, letting you decouple public API structure from backend path layout.
* Static response routes skip integration entirely and return the `response` field directly, which is useful for health checks and feature flags.

## Repo-grounded example

```json
{
  "servers": [
    { "alias": "upstream", "url": "https://api.example.com/base" }
  ],
  "paths": [
    {
      "method": "GET",
      "path": "/proxy/{.+}",
      "integration": {
        "type": "http_proxy",
        "server": "upstream"
      }
    }
  ]
}
```

This snippet proxies all subpaths to an upstream server. To add prefix manipulation, include `"remove_prefix": "/api/v1"` or `"add_prefix": "/internal"` fields in the path entry alongside the integration.

## Troubleshooting

* If a request hits the wrong route, check whether a wildcard pattern is matching before your intended exact or parameterized route -- exact always wins over wildcard.
* If an OPTIONS request returns unexpected results, verify whether you have an explicit OPTIONS handler for that path or are relying on the default CORS 204 behavior.
* If prefix removal produces a double-slash in the upstream URL, confirm that both the `remove_prefix` and the upstream `url` do not include trailing/leading slashes that conflict.
* Use `wrangler tail` and look at the matched path in the log output to confirm which route config entry the gateway selected.

## Related docs

* [README](/configuration/paths)
* [add and remove prefix](/configuration/add-and-remove-prefix)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Routing: Multiple Upstreams Behind One Domain

Split one public API domain across several backends while keeping routing rules readable. Define multiple server aliases in the \`servers\` array and reference

Split one public API domain across several backends while keeping routing rules readable. Define multiple server aliases in the `servers` array and reference each one from the appropriate path entry. This pattern is common when migrating from a monolith to microservices behind a single gateway.

**Last reviewed:** 2026-03-06

## When to use this

Use the routing guides when you need to understand how the gateway matches incoming requests to configured paths. Routing is the core behavior of the gateway -- every request passes through the path matcher before reaching an integration, auth check, or static response.

## Key concepts

* The gateway supports three route shapes: exact paths (`/health`), parameterized paths (`/users/:id`), and wildcard paths (`/proxy/{.+}`). Exact matches take highest priority.
* When multiple routes could match a request, the gateway uses a fixed priority order: exact > parameterized > wildcard. This is not configurable.
* The `method` field accepts standard HTTP methods (`GET`, `POST`, etc.) as well as `ANY`, which matches all methods on that path.
* Prefix add/remove rules transform the path before forwarding to the upstream, letting you decouple public API structure from backend path layout.
* Static response routes skip integration entirely and return the `response` field directly, which is useful for health checks and feature flags.

## Repo-grounded example

```json
{
  "servers": [
    { "alias": "upstream", "url": "https://api.example.com/base" }
  ],
  "paths": [
    {
      "method": "GET",
      "path": "/proxy/{.+}",
      "integration": {
        "type": "http_proxy",
        "server": "upstream"
      }
    }
  ]
}
```

This snippet shows a single upstream server definition. To route different paths to different backends, add more entries to the `servers` array with distinct aliases and reference them in each path's `integration.server` field.

## Troubleshooting

* If a request hits the wrong route, check whether a wildcard pattern is matching before your intended exact or parameterized route -- exact always wins over wildcard.
* If an OPTIONS request returns unexpected results, verify whether you have an explicit OPTIONS handler for that path or are relying on the default CORS 204 behavior.
* If prefix removal produces a double-slash in the upstream URL, confirm that both the `remove_prefix` and the upstream `url` do not include trailing/leading slashes that conflict.
* Use `wrangler tail` and look at the matched path in the log output to confirm which route config entry the gateway selected.

## Related docs

* [README](/configuration/paths)
* [add and remove prefix](/configuration/add-and-remove-prefix)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Routing: Static Response Routes

Return fixed JSON or simple values directly from config for health checks and low-risk utility endpoints. Static response routes bypass integration entirely, so

Return fixed JSON or simple values directly from config for health checks and low-risk utility endpoints. Static response routes bypass integration entirely, so they have no upstream dependency and respond in sub-millisecond time. Use them for health probes, feature flags, and version endpoints.

**Last reviewed:** 2026-03-06

## When to use this

Use the routing guides when you need to understand how the gateway matches incoming requests to configured paths. Routing is the core behavior of the gateway -- every request passes through the path matcher before reaching an integration, auth check, or static response.

## Key concepts

* The gateway supports three route shapes: exact paths (`/health`), parameterized paths (`/users/:id`), and wildcard paths (`/proxy/{.+}`). Exact matches take highest priority.
* When multiple routes could match a request, the gateway uses a fixed priority order: exact > parameterized > wildcard. This is not configurable.
* The `method` field accepts standard HTTP methods (`GET`, `POST`, etc.) as well as `ANY`, which matches all methods on that path.
* Prefix add/remove rules transform the path before forwarding to the upstream, letting you decouple public API structure from backend path layout.
* Static response routes skip integration entirely and return the `response` field directly, which is useful for health checks and feature flags.

## Repo-grounded example

```json
{
  "$schema": "./api-config.schema.json",
  "title": "Minimal Gateway",
  "cors": {
    "allow_origins": ["https://app.example.com"],
    "allow_methods": ["GET", "POST", "OPTIONS"],
    "allow_headers": ["Content-Type", "Authorization"],
    "expose_headers": ["X-Request-Id"],
    "allow_credentials": true,
    "max_age": 300
  },
  "paths": [
    {
      "method": "GET",
      "path": "/health",
      "response": { "status": "ok" }
    }
  ]
}
```

This snippet returns a static JSON object from the `/health` path. The `response` field can be a JSON object, a string, a boolean, or null -- whatever the route needs to return without calling an upstream service.

## Troubleshooting

* If a request hits the wrong route, check whether a wildcard pattern is matching before your intended exact or parameterized route -- exact always wins over wildcard.
* If an OPTIONS request returns unexpected results, verify whether you have an explicit OPTIONS handler for that path or are relying on the default CORS 204 behavior.
* If prefix removal produces a double-slash in the upstream URL, confirm that both the `remove_prefix` and the upstream `url` do not include trailing/leading slashes that conflict.
* Use `wrangler tail` and look at the matched path in the log output to confirm which route config entry the gateway selected.

## Related docs

* [README](/configuration/paths)
* [add and remove prefix](/configuration/add-and-remove-prefix)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Routing: Match Priority Explained

Understand why exact matches beat parameterized routes and why parameterized routes beat wildcard routes. The gateway evaluates all defined paths against the

Understand why exact matches beat parameterized routes and why parameterized routes beat wildcard routes. The gateway evaluates all defined paths against the incoming request and selects the most specific match. This page explains the priority algorithm so you can predict which route handles any given request.

**Last reviewed:** 2026-03-06

## When to use this

Use the routing guides when you need to understand how the gateway matches incoming requests to configured paths. Routing is the core behavior of the gateway -- every request passes through the path matcher before reaching an integration, auth check, or static response.

## Key concepts

* The gateway supports three route shapes: exact paths (`/health`), parameterized paths (`/users/:id`), and wildcard paths (`/proxy/{.+}`). Exact matches take highest priority.
* When multiple routes could match a request, the gateway uses a fixed priority order: exact > parameterized > wildcard. This is not configurable.
* The `method` field accepts standard HTTP methods (`GET`, `POST`, etc.) as well as `ANY`, which matches all methods on that path.
* Prefix add/remove rules transform the path before forwarding to the upstream, letting you decouple public API structure from backend path layout.
* Static response routes skip integration entirely and return the `response` field directly, which is useful for health checks and feature flags.

## Repo-grounded example

```json
{
  "servers": [
    { "alias": "upstream", "url": "https://api.example.com/base" }
  ],
  "paths": [
    {
      "method": "GET",
      "path": "/proxy/{.+}",
      "integration": {
        "type": "http_proxy",
        "server": "upstream"
      }
    }
  ]
}
```

This snippet defines a wildcard route, which has the lowest priority. If you add an exact path like `"/proxy/health"` in a separate entry, it will always match before this wildcard, regardless of definition order in the config.

## Troubleshooting

* If a request hits the wrong route, check whether a wildcard pattern is matching before your intended exact or parameterized route -- exact always wins over wildcard.
* If an OPTIONS request returns unexpected results, verify whether you have an explicit OPTIONS handler for that path or are relying on the default CORS 204 behavior.
* If prefix removal produces a double-slash in the upstream URL, confirm that both the `remove_prefix` and the upstream `url` do not include trailing/leading slashes that conflict.
* Use `wrangler tail` and look at the matched path in the log output to confirm which route config entry the gateway selected.

## Related docs

* [README](/configuration/paths)
* [add and remove prefix](/configuration/add-and-remove-prefix)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Config

Use the schema as the contract for valid gateway behavior before you deploy any routing changes. The schema defines every field the gateway accepts, including

Use the schema as the contract for valid gateway behavior before you deploy any routing changes. The schema defines every field the gateway accepts, including `paths`, `servers`, `authorizer`, `cors`, `variables`, `services`, and `serviceBindings`. Start here if you want a top-level map of what the config can express.

**Last reviewed:** 2026-03-06

## When to use this

Use the config reference when you need to understand the shape, source, or validation behavior of the gateway JSON configuration. The config file is the single source of truth for all routing, auth, CORS, and integration behavior in the gateway.

## Key concepts

* The config schema (`api-config.schema.json`) defines every valid field, type, and default. Use it with your editor for autocompletion and validation before deploying.
* Config can be loaded from three sources: a local JSON file bundled with the worker, a Cloudflare KV namespace, or the `SAG_API_CONFIG_JSON` environment variable. The gateway checks them in that order.
* Strict mode rejects any config with unknown fields or type mismatches at startup, returning a 500 error. Compatibility mode logs warnings but allows the worker to start.
* Legacy key normalization automatically converts old field names (like `http` to `paths` and `servicesBindings` to `serviceBindings`) so older configs continue to work during migration.

## Repo-grounded example

```json
{
  "$schema": "./api-config.schema.json",
  "title": "Minimal Gateway",
  "cors": {
    "allow_origins": ["https://app.example.com"],
    "allow_methods": ["GET", "POST", "OPTIONS"],
    "allow_headers": ["Content-Type", "Authorization"],
    "expose_headers": ["X-Request-Id"],
    "allow_credentials": true,
    "max_age": 300
  },
  "paths": [
    {
      "method": "GET",
      "path": "/health",
      "response": { "status": "ok" }
    }
  ]
}
```

This snippet shows a minimal valid config with a CORS block and a single path. Every field in this example is defined in the schema -- `$schema` enables editor validation, `title` is metadata, and `paths` is the required routing array.

## Troubleshooting

* If the worker starts but routes return 404, check which config source the gateway loaded -- add a health route to each source so you can identify which one is active.
* If strict mode rejects your config, run the JSON against `api-config.schema.json` locally with a JSON schema validator to see the exact validation errors.
* If legacy key normalization is not converting a field, confirm you are running a version of the gateway that supports that alias -- check the CHANGELOG for the normalization version.
* If KV config changes are not reflected after updating, remember that Workers cache KV reads. Redeploy the worker or wait for the cache TTL to expire.

## Related docs

* [overview](/configuration/overview)
* [wrangler](/deployment/wrangler)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Config Source: Local File

Start with a local file when you are iterating in the repo and want simple, inspectable config. The gateway looks for the config file relative to the worker

Start with a local file when you are iterating in the repo and want simple, inspectable config. The gateway looks for the config file relative to the worker entrypoint at build time. This is the default source and the easiest to version-control alongside your worker code.

**Last reviewed:** 2026-03-06

## When to use this

Use the config reference when you need to understand the shape, source, or validation behavior of the gateway JSON configuration. The config file is the single source of truth for all routing, auth, CORS, and integration behavior in the gateway.

## Key concepts

* The config schema (`api-config.schema.json`) defines every valid field, type, and default. Use it with your editor for autocompletion and validation before deploying.
* Config can be loaded from three sources: a local JSON file bundled with the worker, a Cloudflare KV namespace, or the `SAG_API_CONFIG_JSON` environment variable. The gateway checks them in that order.
* Strict mode rejects any config with unknown fields or type mismatches at startup, returning a 500 error. Compatibility mode logs warnings but allows the worker to start.
* Legacy key normalization automatically converts old field names (like `http` to `paths` and `servicesBindings` to `serviceBindings`) so older configs continue to work during migration.

## Repo-grounded example

```json
{
  "$schema": "./api-config.schema.json",
  "title": "Minimal Gateway",
  "cors": {
    "allow_origins": ["https://app.example.com"],
    "allow_methods": ["GET", "POST", "OPTIONS"],
    "allow_headers": ["Content-Type", "Authorization"],
    "expose_headers": ["X-Request-Id"],
    "allow_credentials": true,
    "max_age": 300
  },
  "paths": [
    {
      "method": "GET",
      "path": "/health",
      "response": { "status": "ok" }
    }
  ]
}
```

This snippet is a local JSON config file that gets bundled with the worker during `wrangler deploy`. The gateway reads it at startup as the primary config source, before checking KV or environment variables.

## Troubleshooting

* If the worker starts but routes return 404, check which config source the gateway loaded -- add a health route to each source so you can identify which one is active.
* If strict mode rejects your config, run the JSON against `api-config.schema.json` locally with a JSON schema validator to see the exact validation errors.
* If legacy key normalization is not converting a field, confirm you are running a version of the gateway that supports that alias -- check the CHANGELOG for the normalization version.
* If KV config changes are not reflected after updating, remember that Workers cache KV reads. Redeploy the worker or wait for the cache TTL to expire.

## Related docs

* [overview](/configuration/overview)
* [wrangler](/deployment/wrangler)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Config Source: Cloudflare KV

Load config from KV when you need runtime-managed routing without baking config into the bundle. This lets you update routing rules, add paths, or change

Load config from KV when you need runtime-managed routing without baking config into the bundle. This lets you update routing rules, add paths, or change integrations without redeploying the worker. Use KV config when your team needs to ship routing changes independently from code changes.

**Last reviewed:** 2026-03-06

## When to use this

Use the config reference when you need to understand the shape, source, or validation behavior of the gateway JSON configuration. The config file is the single source of truth for all routing, auth, CORS, and integration behavior in the gateway.

## Key concepts

* The config schema (`api-config.schema.json`) defines every valid field, type, and default. Use it with your editor for autocompletion and validation before deploying.
* Config can be loaded from three sources: a local JSON file bundled with the worker, a Cloudflare KV namespace, or the `SAG_API_CONFIG_JSON` environment variable. The gateway checks them in that order.
* Strict mode rejects any config with unknown fields or type mismatches at startup, returning a 500 error. Compatibility mode logs warnings but allows the worker to start.
* Legacy key normalization automatically converts old field names (like `http` to `paths` and `servicesBindings` to `serviceBindings`) so older configs continue to work during migration.

## Repo-grounded example

```bash
wrangler kv:key put --binding=CONFIG api-config.json ./src/api-config.json
wrangler deploy
```

This snippet writes the local config file into a KV namespace using the Wrangler CLI. The `--binding=CONFIG` flag must match the KV namespace binding in your `wrangler.toml`, and the key `api-config.json` is the default key the gateway reads.

## Troubleshooting

* If the worker starts but routes return 404, check which config source the gateway loaded -- add a health route to each source so you can identify which one is active.
* If strict mode rejects your config, run the JSON against `api-config.schema.json` locally with a JSON schema validator to see the exact validation errors.
* If legacy key normalization is not converting a field, confirm you are running a version of the gateway that supports that alias -- check the CHANGELOG for the normalization version.
* If KV config changes are not reflected after updating, remember that Workers cache KV reads. Redeploy the worker or wait for the cache TTL to expire.

## Related docs

* [overview](/configuration/overview)
* [wrangler](/deployment/wrangler)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Config Source: SAG\_API\_CONFIG\_JSON

Use the inline JSON env var for tests, previews, and CI flows that need an isolated config payload. The entire config is passed as a single environment

Use the inline JSON env var for tests, previews, and CI flows that need an isolated config payload. The entire config is passed as a single environment variable, which is useful when you generate config dynamically in a pipeline. This source has the lowest priority -- the gateway only reads it if no local file or KV config is found.

**Last reviewed:** 2026-03-06

## When to use this

Use the config reference when you need to understand the shape, source, or validation behavior of the gateway JSON configuration. The config file is the single source of truth for all routing, auth, CORS, and integration behavior in the gateway.

## Key concepts

* The config schema (`api-config.schema.json`) defines every valid field, type, and default. Use it with your editor for autocompletion and validation before deploying.
* Config can be loaded from three sources: a local JSON file bundled with the worker, a Cloudflare KV namespace, or the `SAG_API_CONFIG_JSON` environment variable. The gateway checks them in that order.
* Strict mode rejects any config with unknown fields or type mismatches at startup, returning a 500 error. Compatibility mode logs warnings but allows the worker to start.
* Legacy key normalization automatically converts old field names (like `http` to `paths` and `servicesBindings` to `serviceBindings`) so older configs continue to work during migration.

## Repo-grounded example

```bash
export SAG_API_CONFIG_JSON='{"paths":[{"method":"GET","path":"/health","response":{"status":"ok"}}]}'
wrangler deploy
```

This snippet exports the full gateway config as the `SAG_API_CONFIG_JSON` environment variable. The JSON must be valid and complete -- the gateway parses it at startup and uses it as the sole routing definition for that worker instance.

## Troubleshooting

* If the worker starts but routes return 404, check which config source the gateway loaded -- add a health route to each source so you can identify which one is active.
* If strict mode rejects your config, run the JSON against `api-config.schema.json` locally with a JSON schema validator to see the exact validation errors.
* If legacy key normalization is not converting a field, confirm you are running a version of the gateway that supports that alias -- check the CHANGELOG for the normalization version.
* If KV config changes are not reflected after updating, remember that Workers cache KV reads. Redeploy the worker or wait for the cache TTL to expire.

## Related docs

* [overview](/configuration/overview)
* [wrangler](/deployment/wrangler)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Config Validation: Strict Mode

Enable strict mode when you want invalid config to fail the worker early instead of logging compatibility warnings. In strict mode, any unknown field, type

Enable strict mode when you want invalid config to fail the worker early instead of logging compatibility warnings. In strict mode, any unknown field, type mismatch, or missing required field causes the worker to return a 500 error at startup. Use this in production to catch config errors before they affect traffic.

**Last reviewed:** 2026-03-06

## When to use this

Use the config reference when you need to understand the shape, source, or validation behavior of the gateway JSON configuration. The config file is the single source of truth for all routing, auth, CORS, and integration behavior in the gateway.

## Key concepts

* The config schema (`api-config.schema.json`) defines every valid field, type, and default. Use it with your editor for autocompletion and validation before deploying.
* Config can be loaded from three sources: a local JSON file bundled with the worker, a Cloudflare KV namespace, or the `SAG_API_CONFIG_JSON` environment variable. The gateway checks them in that order.
* Strict mode rejects any config with unknown fields or type mismatches at startup, returning a 500 error. Compatibility mode logs warnings but allows the worker to start.
* Legacy key normalization automatically converts old field names (like `http` to `paths` and `servicesBindings` to `serviceBindings`) so older configs continue to work during migration.

## Repo-grounded example

```bash
export SAG_API_CONFIG_JSON='{"paths":[{"method":"GET","path":"/health","response":{"status":"ok"}}]}'
wrangler deploy
```

This snippet shows a config deployed via environment variable. To enable strict mode, add `"strict": true` at the top level of your config JSON. The gateway will then reject any config that does not pass schema validation.

## Troubleshooting

* If the worker starts but routes return 404, check which config source the gateway loaded -- add a health route to each source so you can identify which one is active.
* If strict mode rejects your config, run the JSON against `api-config.schema.json` locally with a JSON schema validator to see the exact validation errors.
* If legacy key normalization is not converting a field, confirm you are running a version of the gateway that supports that alias -- check the CHANGELOG for the normalization version.
* If KV config changes are not reflected after updating, remember that Workers cache KV reads. Redeploy the worker or wait for the cache TTL to expire.

## Related docs

* [overview](/configuration/overview)
* [wrangler](/deployment/wrangler)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Config Validation: Compatibility Mode

Stay in compatibility mode when you are normalizing legacy config and cannot block traffic on validation warnings yet. Compatibility mode logs warnings for

Stay in compatibility mode when you are normalizing legacy config and cannot block traffic on validation warnings yet. Compatibility mode logs warnings for unknown fields and legacy key names but still starts the worker. This is the default behavior when `strict` is not set or is set to `false`.

**Last reviewed:** 2026-03-06

## When to use this

Use the config reference when you need to understand the shape, source, or validation behavior of the gateway JSON configuration. The config file is the single source of truth for all routing, auth, CORS, and integration behavior in the gateway.

## Key concepts

* The config schema (`api-config.schema.json`) defines every valid field, type, and default. Use it with your editor for autocompletion and validation before deploying.
* Config can be loaded from three sources: a local JSON file bundled with the worker, a Cloudflare KV namespace, or the `SAG_API_CONFIG_JSON` environment variable. The gateway checks them in that order.
* Strict mode rejects any config with unknown fields or type mismatches at startup, returning a 500 error. Compatibility mode logs warnings but allows the worker to start.
* Legacy key normalization automatically converts old field names (like `http` to `paths` and `servicesBindings` to `serviceBindings`) so older configs continue to work during migration.

## Repo-grounded example

```json
{
  "$schema": "./api-config.schema.json",
  "title": "Minimal Gateway",
  "cors": {
    "allow_origins": ["https://app.example.com"],
    "allow_methods": ["GET", "POST", "OPTIONS"],
    "allow_headers": ["Content-Type", "Authorization"],
    "expose_headers": ["X-Request-Id"],
    "allow_credentials": true,
    "max_age": 300
  },
  "paths": [
    {
      "method": "GET",
      "path": "/health",
      "response": { "status": "ok" }
    }
  ]
}
```

This snippet works in compatibility mode by default because it does not include `"strict": true`. The gateway will accept this config even if it contains legacy field names or minor schema mismatches, logging warnings instead of failing.

## Troubleshooting

* If the worker starts but routes return 404, check which config source the gateway loaded -- add a health route to each source so you can identify which one is active.
* If strict mode rejects your config, run the JSON against `api-config.schema.json` locally with a JSON schema validator to see the exact validation errors.
* If legacy key normalization is not converting a field, confirm you are running a version of the gateway that supports that alias -- check the CHANGELOG for the normalization version.
* If KV config changes are not reflected after updating, remember that Workers cache KV reads. Redeploy the worker or wait for the cache TTL to expire.

## Related docs

* [overview](/configuration/overview)
* [wrangler](/deployment/wrangler)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Config Normalization: Legacy Keys

Understand how legacy aliases like \`http\` and \`servicesBindings\` are normalized before routing begins. The gateway automatically converts old field names to

Understand how legacy aliases like `http` and `servicesBindings` are normalized before routing begins. The gateway automatically converts old field names to their current equivalents during config parsing. This page documents every legacy alias so you can plan your migration from older config formats.

**Last reviewed:** 2026-03-06

## When to use this

Use the config reference when you need to understand the shape, source, or validation behavior of the gateway JSON configuration. The config file is the single source of truth for all routing, auth, CORS, and integration behavior in the gateway.

## Key concepts

* The config schema (`api-config.schema.json`) defines every valid field, type, and default. Use it with your editor for autocompletion and validation before deploying.
* Config can be loaded from three sources: a local JSON file bundled with the worker, a Cloudflare KV namespace, or the `SAG_API_CONFIG_JSON` environment variable. The gateway checks them in that order.
* Strict mode rejects any config with unknown fields or type mismatches at startup, returning a 500 error. Compatibility mode logs warnings but allows the worker to start.
* Legacy key normalization automatically converts old field names (like `http` to `paths` and `servicesBindings` to `serviceBindings`) so older configs continue to work during migration.

## Repo-grounded example

```json
{
  "serviceBindings": [
    { "alias": "hooks", "binding": "HOOKS" },
    { "alias": "target", "binding": "TARGET" }
  ],
  "paths": [
    {
      "method": "POST",
      "path": "/orders",
      "pre_process": { "binding": "hooks", "function": "before" },
      "integration": {
        "type": "service_binding",
        "binding": "target",
        "function": "run"
      }
    }
  ]
}
```

This snippet uses the current field names `serviceBindings` and `paths`. If your config uses the legacy aliases `servicesBindings` or `http`, the gateway normalizes them to these canonical names before processing routes.

## Troubleshooting

* If the worker starts but routes return 404, check which config source the gateway loaded -- add a health route to each source so you can identify which one is active.
* If strict mode rejects your config, run the JSON against `api-config.schema.json` locally with a JSON schema validator to see the exact validation errors.
* If legacy key normalization is not converting a field, confirm you are running a version of the gateway that supports that alias -- check the CHANGELOG for the normalization version.
* If KV config changes are not reflected after updating, remember that Workers cache KV reads. Redeploy the worker or wait for the cache TTL to expire.

## Related docs

* [overview](/configuration/overview)
* [wrangler](/deployment/wrangler)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# CORS And Responses

Use the gateway CORS block to centralize browser access policy instead of reimplementing it in every upstream. The CORS config defines which origins, methods,

Use the gateway CORS block to centralize browser access policy instead of reimplementing it in every upstream. The CORS config defines which origins, methods, and headers are allowed for cross-origin requests. This page explains every CORS field and how the gateway applies them to responses.

**Last reviewed:** 2026-03-06

## When to use this

Use the CORS and response reference when you need to control how the gateway handles browser cross-origin requests or what shape responses take for static, error, and operational endpoints. CORS is configured globally and applies to all routes unless overridden by an explicit OPTIONS handler.

## Key concepts

* The CORS block is global -- it applies the same origin, method, and header policy to all routes. Per-route CORS overrides require explicit OPTIONS path entries.
* The gateway returns a 204 No Content response for OPTIONS preflight requests automatically. You only need an explicit OPTIONS route if a specific path requires different CORS headers.
* Static response routes can return JSON objects, strings, booleans, or null. The gateway serializes the `response` field as-is and sets `Content-Type: application/json`.
* Error responses follow a consistent JSON shape with `error` and `message` fields. 401 errors include details about which JWT check failed (expiry, issuer, audience).
* The gateway adds a `powered-by` response header by default. This can be useful for debugging which gateway version handled a request.

## Repo-grounded example

```json
{
  "cors": {
    "allow_origins": ["https://app.example.com"],
    "allow_methods": ["GET", "POST", "OPTIONS"],
    "allow_headers": ["Content-Type", "Authorization", "X-Refresh-Token"],
    "expose_headers": ["X-Request-Id"],
    "allow_credentials": true,
    "max_age": 300
  }
}
```

This snippet defines a complete CORS block with `allow_origins`, `allow_methods`, `allow_headers`, `expose_headers`, `allow_credentials`, and `max_age`. Each field maps to a specific CORS response header that the gateway attaches to every response.

## Troubleshooting

* If the browser shows a CORS error, check that `allow_origins` includes the exact origin (scheme + domain + port) your frontend uses -- wildcards are not supported when `allow_credentials` is true.
* If preflight requests return 404 instead of 204, verify that the global CORS block is present in your config and that no explicit OPTIONS route is shadowing the default behavior.
* If a static response returns `null` as a string instead of JSON null, make sure the `response` field is set to `null` (no quotes) in the config JSON.
* If error responses do not include the expected `message` field, confirm you are testing against a current gateway version -- older versions used a different error shape.

## Related docs

* [cors](/configuration/cors)
* [introduction](/getting-started/introduction)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# CORS: Credentials and Origins

Set credentials and origins deliberately so browser auth works without opening the API too broadly. When \`allow\_credentials\` is true, the browser requires an

Set credentials and origins deliberately so browser auth works without opening the API too broadly. When `allow_credentials` is true, the browser requires an exact origin match -- wildcard origins are not permitted. This page explains the interaction between these two fields and common pitfalls.

**Last reviewed:** 2026-03-06

## When to use this

Use the CORS and response reference when you need to control how the gateway handles browser cross-origin requests or what shape responses take for static, error, and operational endpoints. CORS is configured globally and applies to all routes unless overridden by an explicit OPTIONS handler.

## Key concepts

* The CORS block is global -- it applies the same origin, method, and header policy to all routes. Per-route CORS overrides require explicit OPTIONS path entries.
* The gateway returns a 204 No Content response for OPTIONS preflight requests automatically. You only need an explicit OPTIONS route if a specific path requires different CORS headers.
* Static response routes can return JSON objects, strings, booleans, or null. The gateway serializes the `response` field as-is and sets `Content-Type: application/json`.
* Error responses follow a consistent JSON shape with `error` and `message` fields. 401 errors include details about which JWT check failed (expiry, issuer, audience).
* The gateway adds a `powered-by` response header by default. This can be useful for debugging which gateway version handled a request.

## Repo-grounded example

```json
{
  "cors": {
    "allow_origins": ["https://app.example.com"],
    "allow_methods": ["GET", "POST", "OPTIONS"],
    "allow_headers": ["Content-Type", "Authorization", "X-Refresh-Token"],
    "expose_headers": ["X-Request-Id"],
    "allow_credentials": true,
    "max_age": 300
  }
}
```

This snippet sets `allow_credentials: true` alongside a specific origin in `allow_origins`. If you set credentials to true with a wildcard origin, the browser will reject the response, so the gateway requires an explicit origin list.

## Troubleshooting

* If the browser shows a CORS error, check that `allow_origins` includes the exact origin (scheme + domain + port) your frontend uses -- wildcards are not supported when `allow_credentials` is true.
* If preflight requests return 404 instead of 204, verify that the global CORS block is present in your config and that no explicit OPTIONS route is shadowing the default behavior.
* If a static response returns `null` as a string instead of JSON null, make sure the `response` field is set to `null` (no quotes) in the config JSON.
* If error responses do not include the expected `message` field, confirm you are testing against a current gateway version -- older versions used a different error shape.

## Related docs

* [cors](/configuration/cors)
* [introduction](/getting-started/introduction)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# CORS: Default Preflight Behavior

Rely on the built-in 204 preflight response unless a route truly needs a custom OPTIONS handler. The gateway automatically responds to OPTIONS requests using

Rely on the built-in 204 preflight response unless a route truly needs a custom OPTIONS handler. The gateway automatically responds to OPTIONS requests using the global CORS config, returning a 204 with the appropriate headers. This page explains the default flow and when you need to override it.

**Last reviewed:** 2026-03-06

## When to use this

Use the CORS and response reference when you need to control how the gateway handles browser cross-origin requests or what shape responses take for static, error, and operational endpoints. CORS is configured globally and applies to all routes unless overridden by an explicit OPTIONS handler.

## Key concepts

* The CORS block is global -- it applies the same origin, method, and header policy to all routes. Per-route CORS overrides require explicit OPTIONS path entries.
* The gateway returns a 204 No Content response for OPTIONS preflight requests automatically. You only need an explicit OPTIONS route if a specific path requires different CORS headers.
* Static response routes can return JSON objects, strings, booleans, or null. The gateway serializes the `response` field as-is and sets `Content-Type: application/json`.
* Error responses follow a consistent JSON shape with `error` and `message` fields. 401 errors include details about which JWT check failed (expiry, issuer, audience).
* The gateway adds a `powered-by` response header by default. This can be useful for debugging which gateway version handled a request.

## Repo-grounded example

```json
{
  "cors": {
    "allow_origins": ["https://app.example.com"],
    "allow_methods": ["GET", "POST", "OPTIONS"],
    "allow_headers": ["Content-Type", "Authorization", "X-Refresh-Token"],
    "expose_headers": ["X-Request-Id"],
    "allow_credentials": true,
    "max_age": 300
  }
}
```

This snippet defines the global CORS policy. For any OPTIONS request, the gateway reads these fields and returns a 204 with headers like `Access-Control-Allow-Origin`, `Access-Control-Allow-Methods`, and `Access-Control-Max-Age` set from this config.

## Troubleshooting

* If the browser shows a CORS error, check that `allow_origins` includes the exact origin (scheme + domain + port) your frontend uses -- wildcards are not supported when `allow_credentials` is true.
* If preflight requests return 404 instead of 204, verify that the global CORS block is present in your config and that no explicit OPTIONS route is shadowing the default behavior.
* If a static response returns `null` as a string instead of JSON null, make sure the `response` field is set to `null` (no quotes) in the config JSON.
* If error responses do not include the expected `message` field, confirm you are testing against a current gateway version -- older versions used a different error shape.

## Related docs

* [cors](/configuration/cors)
* [introduction](/getting-started/introduction)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Responses: JSON, String, Boolean, and Null

Use config responses for small, deterministic endpoints where a full proxy or service call adds no value. The \`response\` field in a path entry can be a JSON

Use config responses for small, deterministic endpoints where a full proxy or service call adds no value. The `response` field in a path entry can be a JSON object, string, boolean, or null. This page documents each type, how the gateway serializes it, and which content type header is returned.

**Last reviewed:** 2026-03-06

## When to use this

Use the CORS and response reference when you need to control how the gateway handles browser cross-origin requests or what shape responses take for static, error, and operational endpoints. CORS is configured globally and applies to all routes unless overridden by an explicit OPTIONS handler.

## Key concepts

* The CORS block is global -- it applies the same origin, method, and header policy to all routes. Per-route CORS overrides require explicit OPTIONS path entries.
* The gateway returns a 204 No Content response for OPTIONS preflight requests automatically. You only need an explicit OPTIONS route if a specific path requires different CORS headers.
* Static response routes can return JSON objects, strings, booleans, or null. The gateway serializes the `response` field as-is and sets `Content-Type: application/json`.
* Error responses follow a consistent JSON shape with `error` and `message` fields. 401 errors include details about which JWT check failed (expiry, issuer, audience).
* The gateway adds a `powered-by` response header by default. This can be useful for debugging which gateway version handled a request.

## Repo-grounded example

```json
{
  "$schema": "./api-config.schema.json",
  "title": "Minimal Gateway",
  "cors": {
    "allow_origins": ["https://app.example.com"],
    "allow_methods": ["GET", "POST", "OPTIONS"],
    "allow_headers": ["Content-Type", "Authorization"],
    "expose_headers": ["X-Request-Id"],
    "allow_credentials": true,
    "max_age": 300
  },
  "paths": [
    {
      "method": "GET",
      "path": "/health",
      "response": { "status": "ok" }
    }
  ]
}
```

This snippet returns `{"status": "ok"}` as the response body for the `/health` route. The gateway serializes the `response` field as JSON and sets `Content-Type: application/json`. You can also use a plain string, boolean, or null value.

## Troubleshooting

* If the browser shows a CORS error, check that `allow_origins` includes the exact origin (scheme + domain + port) your frontend uses -- wildcards are not supported when `allow_credentials` is true.
* If preflight requests return 404 instead of 204, verify that the global CORS block is present in your config and that no explicit OPTIONS route is shadowing the default behavior.
* If a static response returns `null` as a string instead of JSON null, make sure the `response` field is set to `null` (no quotes) in the config JSON.
* If error responses do not include the expected `message` field, confirm you are testing against a current gateway version -- older versions used a different error shape.

## Related docs

* [cors](/configuration/cors)
* [introduction](/getting-started/introduction)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Responses: Error Shapes

Use this page to understand the gateway's JSON error surface before wiring client-side handling. The gateway returns structured JSON errors for 401, 403, 404,

Use this page to understand the gateway's JSON error surface before wiring client-side handling. The gateway returns structured JSON errors for 401, 403, 404, and 500 status codes, each with an `error` field and a human-readable `message`. Knowing these shapes helps you write consistent error handling in your frontend.

**Last reviewed:** 2026-03-06

## When to use this

Use the CORS and response reference when you need to control how the gateway handles browser cross-origin requests or what shape responses take for static, error, and operational endpoints. CORS is configured globally and applies to all routes unless overridden by an explicit OPTIONS handler.

## Key concepts

* The CORS block is global -- it applies the same origin, method, and header policy to all routes. Per-route CORS overrides require explicit OPTIONS path entries.
* The gateway returns a 204 No Content response for OPTIONS preflight requests automatically. You only need an explicit OPTIONS route if a specific path requires different CORS headers.
* Static response routes can return JSON objects, strings, booleans, or null. The gateway serializes the `response` field as-is and sets `Content-Type: application/json`.
* Error responses follow a consistent JSON shape with `error` and `message` fields. 401 errors include details about which JWT check failed (expiry, issuer, audience).
* The gateway adds a `powered-by` response header by default. This can be useful for debugging which gateway version handled a request.

## Repo-grounded example

```json
{
  "authorizer": {
    "type": "jwt",
    "secret": "$env.JWT_SECRET",
    "algorithm": "HS256",
    "issuer": "https://issuer.example.com",
    "audience": "api-audience"
  },
  "paths": [
    {
      "method": "GET",
      "path": "/private",
      "auth": true,
      "response": { "private": true }
    }
  ]
}
```

This snippet includes an `auth: true` route that returns a 401 JSON error if the bearer token is missing, expired, or fails issuer/audience validation. The error body includes which specific check failed, such as `"token expired"` or `"invalid audience"`.

## Troubleshooting

* If the browser shows a CORS error, check that `allow_origins` includes the exact origin (scheme + domain + port) your frontend uses -- wildcards are not supported when `allow_credentials` is true.
* If preflight requests return 404 instead of 204, verify that the global CORS block is present in your config and that no explicit OPTIONS route is shadowing the default behavior.
* If a static response returns `null` as a string instead of JSON null, make sure the `response` field is set to `null` (no quotes) in the config JSON.
* If error responses do not include the expected `message` field, confirm you are testing against a current gateway version -- older versions used a different error shape.

## Related docs

* [cors](/configuration/cors)
* [introduction](/getting-started/introduction)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Responses: Powered-By Header Behavior

Know when the gateway adds its response header so you can reason about downstream caching and observability. The gateway includes a \`powered-by\` header on every

Know when the gateway adds its response header so you can reason about downstream caching and observability. The gateway includes a `powered-by` header on every response, identifying the gateway and its version. This page documents the header format and how it affects caching proxies or CDN behavior.

**Last reviewed:** 2026-03-06

## When to use this

Use the CORS and response reference when you need to control how the gateway handles browser cross-origin requests or what shape responses take for static, error, and operational endpoints. CORS is configured globally and applies to all routes unless overridden by an explicit OPTIONS handler.

## Key concepts

* The CORS block is global -- it applies the same origin, method, and header policy to all routes. Per-route CORS overrides require explicit OPTIONS path entries.
* The gateway returns a 204 No Content response for OPTIONS preflight requests automatically. You only need an explicit OPTIONS route if a specific path requires different CORS headers.
* Static response routes can return JSON objects, strings, booleans, or null. The gateway serializes the `response` field as-is and sets `Content-Type: application/json`.
* Error responses follow a consistent JSON shape with `error` and `message` fields. 401 errors include details about which JWT check failed (expiry, issuer, audience).
* The gateway adds a `powered-by` response header by default. This can be useful for debugging which gateway version handled a request.

## Repo-grounded example

```json
{
  "$schema": "./api-config.schema.json",
  "title": "Minimal Gateway",
  "cors": {
    "allow_origins": ["https://app.example.com"],
    "allow_methods": ["GET", "POST", "OPTIONS"],
    "allow_headers": ["Content-Type", "Authorization"],
    "expose_headers": ["X-Request-Id"],
    "allow_credentials": true,
    "max_age": 300
  },
  "paths": [
    {
      "method": "GET",
      "path": "/health",
      "response": { "status": "ok" }
    }
  ]
}
```

This snippet produces a response that includes the gateway `powered-by` header automatically. The header is added after the response body is assembled, so it appears on static responses, proxied responses, and error responses alike.

## Troubleshooting

* If the browser shows a CORS error, check that `allow_origins` includes the exact origin (scheme + domain + port) your frontend uses -- wildcards are not supported when `allow_credentials` is true.
* If preflight requests return 404 instead of 204, verify that the global CORS block is present in your config and that no explicit OPTIONS route is shadowing the default behavior.
* If a static response returns `null` as a string instead of JSON null, make sure the `response` field is set to `null` (no quotes) in the config JSON.
* If error responses do not include the expected `message` field, confirm you are testing against a current gateway version -- older versions used a different error shape.

## Related docs

* [cors](/configuration/cors)
* [introduction](/getting-started/introduction)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Responses: Health, Readiness, and Liveness Patterns

Model operational endpoints separately so you can distinguish worker health from upstream dependency health. A health endpoint confirms the worker is running; a

Model operational endpoints separately so you can distinguish worker health from upstream dependency health. A health endpoint confirms the worker is running; a readiness endpoint can proxy an upstream status check. This page shows patterns for combining static and proxied health routes in one gateway config.

**Last reviewed:** 2026-03-06

## When to use this

Use the CORS and response reference when you need to control how the gateway handles browser cross-origin requests or what shape responses take for static, error, and operational endpoints. CORS is configured globally and applies to all routes unless overridden by an explicit OPTIONS handler.

## Key concepts

* The CORS block is global -- it applies the same origin, method, and header policy to all routes. Per-route CORS overrides require explicit OPTIONS path entries.
* The gateway returns a 204 No Content response for OPTIONS preflight requests automatically. You only need an explicit OPTIONS route if a specific path requires different CORS headers.
* Static response routes can return JSON objects, strings, booleans, or null. The gateway serializes the `response` field as-is and sets `Content-Type: application/json`.
* Error responses follow a consistent JSON shape with `error` and `message` fields. 401 errors include details about which JWT check failed (expiry, issuer, audience).
* The gateway adds a `powered-by` response header by default. This can be useful for debugging which gateway version handled a request.

## Repo-grounded example

```json
{
  "$schema": "./api-config.schema.json",
  "title": "Minimal Gateway",
  "cors": {
    "allow_origins": ["https://app.example.com"],
    "allow_methods": ["GET", "POST", "OPTIONS"],
    "allow_headers": ["Content-Type", "Authorization"],
    "expose_headers": ["X-Request-Id"],
    "allow_credentials": true,
    "max_age": 300
  },
  "paths": [
    {
      "method": "GET",
      "path": "/health",
      "response": { "status": "ok" }
    }
  ]
}
```

This snippet defines a static `/health` route that confirms the worker is running without any upstream dependency. To add readiness or liveness checks that verify upstream connectivity, define additional routes with `http_proxy` integrations pointing at your backend health endpoints.

## Troubleshooting

* If the browser shows a CORS error, check that `allow_origins` includes the exact origin (scheme + domain + port) your frontend uses -- wildcards are not supported when `allow_credentials` is true.
* If preflight requests return 404 instead of 204, verify that the global CORS block is present in your config and that no explicit OPTIONS route is shadowing the default behavior.
* If a static response returns `null` as a string instead of JSON null, make sure the `response` field is set to `null` (no quotes) in the config JSON.
* If error responses do not include the expected `message` field, confirm you are testing against a current gateway version -- older versions used a different error shape.

## Related docs

* [cors](/configuration/cors)
* [introduction](/getting-started/introduction)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Mapping And Variables

Use mapping when the upstream needs transformed headers or query params rather than the original client request. The mapping block lets you select specific

Use mapping when the upstream needs transformed headers or query params rather than the original client request. The mapping block lets you select specific values from the request, JWT, or config variables and forward them as upstream headers or query parameters. This page gives an end-to-end overview of the mapping system.

**Last reviewed:** 2026-03-06

## When to use this

Use the mapping and variables reference when you need to transform, inject, or replace values in upstream requests. Mapping lets you forward selected headers, query parameters, JWT claims, and config variables to the upstream without modifying your backend code.

## Key concepts

* The `mapping` block on a path entry defines which headers and query parameters to send to the upstream. Only mapped values are forwarded -- unmapped client headers and query params are dropped.
* Mapping sources include `$request.headers.*`, `$request.query.*`, `$request.jwt.*` (any JWT claim), `$config.*` (global variables), and `$route.*` (route-level variables).
* Global `variables` are defined at the top level of the config and available to all routes. Route-level `variables` are defined inside a path entry and override global variables with the same name.
* `$env.*` and `$secrets.*` placeholders are replaced at config load time, not at request time. This means environment variables and secrets are baked into the parsed config once at startup.
* If a mapping source resolves to `null` or `undefined`, the gateway sends an empty string for that header or query parameter. Use the debugging guide to trace missing values.

## Repo-grounded example

```json
{
  "variables": { "region": "eu-west-1" },
  "paths": [
    {
      "method": "GET",
      "path": "/proxy/{.+}",
      "auth": true,
      "integration": { "type": "http_proxy", "server": "upstream" },
      "mapping": {
        "headers": {
          "x-user-id": "$request.jwt.sub",
          "x-region": "$config.region"
        },
        "query": {
          "source": "$request.query.source"
        }
      },
      "variables": { "api_key": "internal-key" }
    }
  ]
}
```

This snippet defines a `mapping` block with header and query mappings. The `x-user-id` header is set from the JWT `sub` claim, the `x-region` header from a config variable, and the `source` query parameter from the original request query string.

## Troubleshooting

* If a mapped header arrives empty at the upstream, verify the source exists: check that the JWT claim is present in the token, the request header was sent by the client, or the variable is defined in config.
* If `$request.jwt.sub` is null on a route without `auth: true`, remember that JWT claims are only available after successful token validation -- add `auth: true` to the route.
* If route variables are not overriding global variables, confirm the variable name matches exactly (case-sensitive) and that the route-level `variables` block is inside the path entry, not at the top level.
* Use a tool like jwt.io to decode your test token and confirm the claim names match what your mapping expects (e.g., `sub` vs `user_id`).

## Related docs

* [README](/configuration/variable-mapping)
* [priority variables](/configuration/priority-variables)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Mapping from Request Headers

Forward selected request headers to the upstream without exposing the whole client header set. Only headers listed in the \`mapping.headers\` block are sent --

Forward selected request headers to the upstream without exposing the whole client header set. Only headers listed in the `mapping.headers` block are sent -- all other client headers are dropped for the upstream request. Use this to control exactly what metadata your backend receives.

**Last reviewed:** 2026-03-06

## When to use this

Use the mapping and variables reference when you need to transform, inject, or replace values in upstream requests. Mapping lets you forward selected headers, query parameters, JWT claims, and config variables to the upstream without modifying your backend code.

## Key concepts

* The `mapping` block on a path entry defines which headers and query parameters to send to the upstream. Only mapped values are forwarded -- unmapped client headers and query params are dropped.
* Mapping sources include `$request.headers.*`, `$request.query.*`, `$request.jwt.*` (any JWT claim), `$config.*` (global variables), and `$route.*` (route-level variables).
* Global `variables` are defined at the top level of the config and available to all routes. Route-level `variables` are defined inside a path entry and override global variables with the same name.
* `$env.*` and `$secrets.*` placeholders are replaced at config load time, not at request time. This means environment variables and secrets are baked into the parsed config once at startup.
* If a mapping source resolves to `null` or `undefined`, the gateway sends an empty string for that header or query parameter. Use the debugging guide to trace missing values.

## Repo-grounded example

```json
{
  "variables": { "region": "eu-west-1" },
  "paths": [
    {
      "method": "GET",
      "path": "/proxy/{.+}",
      "auth": true,
      "integration": { "type": "http_proxy", "server": "upstream" },
      "mapping": {
        "headers": {
          "x-user-id": "$request.jwt.sub",
          "x-region": "$config.region"
        },
        "query": {
          "source": "$request.query.source"
        }
      },
      "variables": { "api_key": "internal-key" }
    }
  ]
}
```

This snippet maps the `x-user-id` header from a JWT claim, but you can also map from client request headers using `$request.headers.x-custom-header`. The gateway reads the named header from the incoming request and forwards it to the upstream.

## Troubleshooting

* If a mapped header arrives empty at the upstream, verify the source exists: check that the JWT claim is present in the token, the request header was sent by the client, or the variable is defined in config.
* If `$request.jwt.sub` is null on a route without `auth: true`, remember that JWT claims are only available after successful token validation -- add `auth: true` to the route.
* If route variables are not overriding global variables, confirm the variable name matches exactly (case-sensitive) and that the route-level `variables` block is inside the path entry, not at the top level.
* Use a tool like jwt.io to decode your test token and confirm the claim names match what your mapping expects (e.g., `sub` vs `user_id`).

## Related docs

* [README](/configuration/variable-mapping)
* [priority variables](/configuration/priority-variables)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Mapping from Request Query Parameters

Promote request query values into stable upstream parameters when you need consistent backend contracts. The \`mapping.query\` block lets you rename, forward, or

Promote request query values into stable upstream parameters when you need consistent backend contracts. The `mapping.query` block lets you rename, forward, or inject query parameters for the upstream request. This is useful when your backend expects a specific parameter name that differs from what clients send.

**Last reviewed:** 2026-03-06

## When to use this

Use the mapping and variables reference when you need to transform, inject, or replace values in upstream requests. Mapping lets you forward selected headers, query parameters, JWT claims, and config variables to the upstream without modifying your backend code.

## Key concepts

* The `mapping` block on a path entry defines which headers and query parameters to send to the upstream. Only mapped values are forwarded -- unmapped client headers and query params are dropped.
* Mapping sources include `$request.headers.*`, `$request.query.*`, `$request.jwt.*` (any JWT claim), `$config.*` (global variables), and `$route.*` (route-level variables).
* Global `variables` are defined at the top level of the config and available to all routes. Route-level `variables` are defined inside a path entry and override global variables with the same name.
* `$env.*` and `$secrets.*` placeholders are replaced at config load time, not at request time. This means environment variables and secrets are baked into the parsed config once at startup.
* If a mapping source resolves to `null` or `undefined`, the gateway sends an empty string for that header or query parameter. Use the debugging guide to trace missing values.

## Repo-grounded example

```json
{
  "variables": { "region": "eu-west-1" },
  "paths": [
    {
      "method": "GET",
      "path": "/proxy/{.+}",
      "auth": true,
      "integration": { "type": "http_proxy", "server": "upstream" },
      "mapping": {
        "headers": {
          "x-user-id": "$request.jwt.sub",
          "x-region": "$config.region"
        },
        "query": {
          "source": "$request.query.source"
        }
      },
      "variables": { "api_key": "internal-key" }
    }
  ]
}
```

This snippet maps the `source` query parameter from `$request.query.source`, forwarding the client-provided value to the upstream. If the client omits the query parameter, the upstream receives an empty string for that key.

## Troubleshooting

* If a mapped header arrives empty at the upstream, verify the source exists: check that the JWT claim is present in the token, the request header was sent by the client, or the variable is defined in config.
* If `$request.jwt.sub` is null on a route without `auth: true`, remember that JWT claims are only available after successful token validation -- add `auth: true` to the route.
* If route variables are not overriding global variables, confirm the variable name matches exactly (case-sensitive) and that the route-level `variables` block is inside the path entry, not at the top level.
* Use a tool like jwt.io to decode your test token and confirm the claim names match what your mapping expects (e.g., `sub` vs `user_id`).

## Related docs

* [README](/configuration/variable-mapping)
* [priority variables](/configuration/priority-variables)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Mapping from JWT Claims

Inject user or tenant claims into upstream requests after the gateway verifies the token. Any standard or custom JWT claim is available via

Inject user or tenant claims into upstream requests after the gateway verifies the token. Any standard or custom JWT claim is available via `$request.jwt.<claim>`. This lets your backend trust user identity without re-validating the token, since the gateway already verified it.

**Last reviewed:** 2026-03-06

## When to use this

Use the mapping and variables reference when you need to transform, inject, or replace values in upstream requests. Mapping lets you forward selected headers, query parameters, JWT claims, and config variables to the upstream without modifying your backend code.

## Key concepts

* The `mapping` block on a path entry defines which headers and query parameters to send to the upstream. Only mapped values are forwarded -- unmapped client headers and query params are dropped.
* Mapping sources include `$request.headers.*`, `$request.query.*`, `$request.jwt.*` (any JWT claim), `$config.*` (global variables), and `$route.*` (route-level variables).
* Global `variables` are defined at the top level of the config and available to all routes. Route-level `variables` are defined inside a path entry and override global variables with the same name.
* `$env.*` and `$secrets.*` placeholders are replaced at config load time, not at request time. This means environment variables and secrets are baked into the parsed config once at startup.
* If a mapping source resolves to `null` or `undefined`, the gateway sends an empty string for that header or query parameter. Use the debugging guide to trace missing values.

## Repo-grounded example

```json
{
  "variables": { "region": "eu-west-1" },
  "paths": [
    {
      "method": "GET",
      "path": "/proxy/{.+}",
      "auth": true,
      "integration": { "type": "http_proxy", "server": "upstream" },
      "mapping": {
        "headers": {
          "x-user-id": "$request.jwt.sub",
          "x-region": "$config.region"
        },
        "query": {
          "source": "$request.query.source"
        }
      },
      "variables": { "api_key": "internal-key" }
    }
  ]
}
```

This snippet maps `$request.jwt.sub` into the `x-user-id` upstream header. You can map any claim from the JWT payload, including custom claims like `org_id` or `role`, using the same `$request.jwt.<claim>` syntax.

## Troubleshooting

* If a mapped header arrives empty at the upstream, verify the source exists: check that the JWT claim is present in the token, the request header was sent by the client, or the variable is defined in config.
* If `$request.jwt.sub` is null on a route without `auth: true`, remember that JWT claims are only available after successful token validation -- add `auth: true` to the route.
* If route variables are not overriding global variables, confirm the variable name matches exactly (case-sensitive) and that the route-level `variables` block is inside the path entry, not at the top level.
* Use a tool like jwt.io to decode your test token and confirm the claim names match what your mapping expects (e.g., `sub` vs `user_id`).

## Related docs

* [README](/configuration/variable-mapping)
* [priority variables](/configuration/priority-variables)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Mapping: Route Variables vs Global Variables

Use route variables for one-off overrides and global variables for cross-route defaults. Global variables in the top-level \`variables\` block apply to all

Use route variables for one-off overrides and global variables for cross-route defaults. Global variables in the top-level `variables` block apply to all routes. Route-level variables defined inside a specific path entry override globals with the same key for that route only.

**Last reviewed:** 2026-03-06

## When to use this

Use the mapping and variables reference when you need to transform, inject, or replace values in upstream requests. Mapping lets you forward selected headers, query parameters, JWT claims, and config variables to the upstream without modifying your backend code.

## Key concepts

* The `mapping` block on a path entry defines which headers and query parameters to send to the upstream. Only mapped values are forwarded -- unmapped client headers and query params are dropped.
* Mapping sources include `$request.headers.*`, `$request.query.*`, `$request.jwt.*` (any JWT claim), `$config.*` (global variables), and `$route.*` (route-level variables).
* Global `variables` are defined at the top level of the config and available to all routes. Route-level `variables` are defined inside a path entry and override global variables with the same name.
* `$env.*` and `$secrets.*` placeholders are replaced at config load time, not at request time. This means environment variables and secrets are baked into the parsed config once at startup.
* If a mapping source resolves to `null` or `undefined`, the gateway sends an empty string for that header or query parameter. Use the debugging guide to trace missing values.

## Repo-grounded example

```json
{
  "variables": { "region": "eu-west-1" },
  "paths": [
    {
      "method": "GET",
      "path": "/proxy/{.+}",
      "auth": true,
      "integration": { "type": "http_proxy", "server": "upstream" },
      "mapping": {
        "headers": {
          "x-user-id": "$request.jwt.sub",
          "x-region": "$config.region"
        },
        "query": {
          "source": "$request.query.source"
        }
      },
      "variables": { "api_key": "internal-key" }
    }
  ]
}
```

This snippet defines a global `region` variable at the top level and a route-level `api_key` variable inside the path entry. The route-level variable is only available to this specific path, while `region` is available to all routes via `$config.region`.

## Troubleshooting

* If a mapped header arrives empty at the upstream, verify the source exists: check that the JWT claim is present in the token, the request header was sent by the client, or the variable is defined in config.
* If `$request.jwt.sub` is null on a route without `auth: true`, remember that JWT claims are only available after successful token validation -- add `auth: true` to the route.
* If route variables are not overriding global variables, confirm the variable name matches exactly (case-sensitive) and that the route-level `variables` block is inside the path entry, not at the top level.
* Use a tool like jwt.io to decode your test token and confirm the claim names match what your mapping expects (e.g., `sub` vs `user_id`).

## Related docs

* [README](/configuration/variable-mapping)
* [priority variables](/configuration/priority-variables)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Environment Variables and Secret Replacement

Replace \`$env.\*\` and \`$secrets.\*\` placeholders at load time so sensitive values stay outside repo config. The gateway resolves these placeholders when it parses

Replace `$env.*` and `$secrets.*` placeholders at load time so sensitive values stay outside repo config. The gateway resolves these placeholders when it parses the config at startup, replacing them with values from Cloudflare environment variables and secrets. This keeps credentials out of your JSON config files and version control.

**Last reviewed:** 2026-03-06

## When to use this

Use the mapping and variables reference when you need to transform, inject, or replace values in upstream requests. Mapping lets you forward selected headers, query parameters, JWT claims, and config variables to the upstream without modifying your backend code.

## Key concepts

* The `mapping` block on a path entry defines which headers and query parameters to send to the upstream. Only mapped values are forwarded -- unmapped client headers and query params are dropped.
* Mapping sources include `$request.headers.*`, `$request.query.*`, `$request.jwt.*` (any JWT claim), `$config.*` (global variables), and `$route.*` (route-level variables).
* Global `variables` are defined at the top level of the config and available to all routes. Route-level `variables` are defined inside a path entry and override global variables with the same name.
* `$env.*` and `$secrets.*` placeholders are replaced at config load time, not at request time. This means environment variables and secrets are baked into the parsed config once at startup.
* If a mapping source resolves to `null` or `undefined`, the gateway sends an empty string for that header or query parameter. Use the debugging guide to trace missing values.

## Repo-grounded example

```json
{
  "authorizer": {
    "type": "auth0",
    "domain": "$env.AUTH0_DOMAIN",
    "client_id": "$env.AUTH0_CLIENT_ID",
    "client_secret": "$secrets.AUTH0_CLIENT_SECRET",
    "redirect_uri": "https://api.example.com/api/v1/auth0/callback",
    "callback_uri": "https://app.example.com/auth/callback",
    "jwks_uri": "https://tenant.us.auth0.com/.well-known/jwks.json",
    "scope": "openid profile email"
  },
  "paths": [
    {
      "method": "GET",
      "path": "/api/v1/auth0/callback",
      "integration": { "type": "auth0_callback" }
    }
  ]
}
```

This snippet uses `$env.AUTH0_DOMAIN`, `$env.AUTH0_CLIENT_ID`, and `$secrets.AUTH0_CLIENT_SECRET` placeholders. At startup, the gateway replaces these with the corresponding Cloudflare environment variables and secrets, so the parsed config contains the actual values.

## Troubleshooting

* If a mapped header arrives empty at the upstream, verify the source exists: check that the JWT claim is present in the token, the request header was sent by the client, or the variable is defined in config.
* If `$request.jwt.sub` is null on a route without `auth: true`, remember that JWT claims are only available after successful token validation -- add `auth: true` to the route.
* If route variables are not overriding global variables, confirm the variable name matches exactly (case-sensitive) and that the route-level `variables` block is inside the path entry, not at the top level.
* Use a tool like jwt.io to decode your test token and confirm the claim names match what your mapping expects (e.g., `sub` vs `user_id`).

## Related docs

* [README](/configuration/variable-mapping)
* [priority variables](/configuration/priority-variables)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Mapping: Debugging Null Values

Diagnose missing mapped values by checking token claims, request headers, and variable scope order. When a mapped value arrives as null or empty at the

Diagnose missing mapped values by checking token claims, request headers, and variable scope order. When a mapped value arrives as null or empty at the upstream, the issue is usually a missing source: the JWT claim does not exist, the request header was not sent, or the variable name has a typo. This page walks through the debugging steps.

**Last reviewed:** 2026-03-06

## When to use this

Use the mapping and variables reference when you need to transform, inject, or replace values in upstream requests. Mapping lets you forward selected headers, query parameters, JWT claims, and config variables to the upstream without modifying your backend code.

## Key concepts

* The `mapping` block on a path entry defines which headers and query parameters to send to the upstream. Only mapped values are forwarded -- unmapped client headers and query params are dropped.
* Mapping sources include `$request.headers.*`, `$request.query.*`, `$request.jwt.*` (any JWT claim), `$config.*` (global variables), and `$route.*` (route-level variables).
* Global `variables` are defined at the top level of the config and available to all routes. Route-level `variables` are defined inside a path entry and override global variables with the same name.
* `$env.*` and `$secrets.*` placeholders are replaced at config load time, not at request time. This means environment variables and secrets are baked into the parsed config once at startup.
* If a mapping source resolves to `null` or `undefined`, the gateway sends an empty string for that header or query parameter. Use the debugging guide to trace missing values.

## Repo-grounded example

```json
{
  "variables": { "region": "eu-west-1" },
  "paths": [
    {
      "method": "GET",
      "path": "/proxy/{.+}",
      "auth": true,
      "integration": { "type": "http_proxy", "server": "upstream" },
      "mapping": {
        "headers": {
          "x-user-id": "$request.jwt.sub",
          "x-region": "$config.region"
        },
        "query": {
          "source": "$request.query.source"
        }
      },
      "variables": { "api_key": "internal-key" }
    }
  ]
}
```

This snippet maps values from JWT claims, config variables, and request query parameters. If any source is missing at request time, the gateway forwards an empty string. Check the JWT payload, the `variables` block, and the actual client request to find the missing source.

## Troubleshooting

* If a mapped header arrives empty at the upstream, verify the source exists: check that the JWT claim is present in the token, the request header was sent by the client, or the variable is defined in config.
* If `$request.jwt.sub` is null on a route without `auth: true`, remember that JWT claims are only available after successful token validation -- add `auth: true` to the route.
* If route variables are not overriding global variables, confirm the variable name matches exactly (case-sensitive) and that the route-level `variables` block is inside the path entry, not at the top level.
* Use a tool like jwt.io to decode your test token and confirm the claim names match what your mapping expects (e.g., `sub` vs `user_id`).

## Related docs

* [README](/configuration/variable-mapping)
* [priority variables](/configuration/priority-variables)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Service Execution

Choose the right integration type based on whether you need a local module import or a bound Worker method call. The \`service\` type bundles handler code with

Choose the right integration type based on whether you need a local module import or a bound Worker method call. The `service` type bundles handler code with the gateway worker, while `service_binding` calls a separately deployed Worker. This page compares both patterns to help you pick the right one for your use case.

**Last reviewed:** 2026-03-06

## When to use this

Use the service execution recipes when your routes need to call Worker code directly instead of proxying to an external HTTP endpoint. The gateway supports two patterns: local service modules bundled with the worker, and service bindings that call separately deployed Workers via Cloudflare bindings.

## Key concepts

* The `service` integration type imports a local JavaScript module from the worker project and calls its default export. The module ships in the same worker bundle.
* The `service_binding` integration type calls a separately deployed Worker through a Cloudflare service binding. The target Worker must be deployed independently and bound in `wrangler.toml`.
* Pre-process hooks run before the main integration and can short-circuit the request by returning a response. Use them for custom authorization, input validation, or request enrichment.
* Post-process hooks run after the main integration returns and can modify the response. The Auth0 callback post-process hook is the most common use case.
* When choosing between proxy and service execution, consider latency (service bindings avoid an external HTTP round-trip) and coupling (proxy keeps the backend independently deployable).

## Repo-grounded example

```json
{
  "serviceBindings": [
    { "alias": "hooks", "binding": "HOOKS" },
    { "alias": "target", "binding": "TARGET" }
  ],
  "paths": [
    {
      "method": "POST",
      "path": "/orders",
      "pre_process": { "binding": "hooks", "function": "before" },
      "integration": {
        "type": "service_binding",
        "binding": "target",
        "function": "run"
      }
    }
  ]
}
```

This snippet uses the `service_binding` integration type with Cloudflare bindings. The `serviceBindings` array maps aliases to binding names declared in `wrangler.toml`. The `pre_process` hook runs before the main integration, and the `integration.function` field specifies which method to call on the bound Worker.

## Troubleshooting

* If a `service` integration returns 500, confirm that the entrypoint path in the `services` array matches the actual file location relative to the worker root and that the module exports a default function.
* If a `service_binding` integration returns a binding error, verify that the binding name in config matches the binding declared in `wrangler.toml` and that the target Worker is deployed.
* If a pre-process hook does not short-circuit as expected, check that the hook function returns a `Response` object -- returning `undefined` or `null` lets the request continue to the main integration.
* If post-process hooks are not running, confirm the hook config uses the correct `binding` and `function` field names and that the hook Worker is deployed and bound.

## Related docs

* [service binding](/configuration/service-binding)
* [servers](/configuration/servers)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Service Integrations with Local Entrypoints

Use local services when the gateway and the handler should ship together in one worker project. The \`services\` array defines local module entrypoints that the

Use local services when the gateway and the handler should ship together in one worker project. The `services` array defines local module entrypoints that the gateway imports at startup. This pattern keeps related code co-located and avoids the overhead of a separate Worker deployment.

**Last reviewed:** 2026-03-06

## When to use this

Use the service execution recipes when your routes need to call Worker code directly instead of proxying to an external HTTP endpoint. The gateway supports two patterns: local service modules bundled with the worker, and service bindings that call separately deployed Workers via Cloudflare bindings.

## Key concepts

* The `service` integration type imports a local JavaScript module from the worker project and calls its default export. The module ships in the same worker bundle.
* The `service_binding` integration type calls a separately deployed Worker through a Cloudflare service binding. The target Worker must be deployed independently and bound in `wrangler.toml`.
* Pre-process hooks run before the main integration and can short-circuit the request by returning a response. Use them for custom authorization, input validation, or request enrichment.
* Post-process hooks run after the main integration returns and can modify the response. The Auth0 callback post-process hook is the most common use case.
* When choosing between proxy and service execution, consider latency (service bindings avoid an external HTTP round-trip) and coupling (proxy keeps the backend independently deployable).

## Repo-grounded example

```json
{
  "services": [
    { "alias": "worker1", "entrypoint": "./services/endpoint1" }
  ],
  "paths": [
    {
      "method": "GET",
      "path": "/service",
      "integration": {
        "type": "service",
        "binding": "worker1"
      }
    }
  ]
}
```

This snippet defines a `services` array with one local entrypoint at `./services/endpoint1`. The `integration.binding` field references the service alias, and the gateway calls the module's default export when a request matches this path.

## Troubleshooting

* If a `service` integration returns 500, confirm that the entrypoint path in the `services` array matches the actual file location relative to the worker root and that the module exports a default function.
* If a `service_binding` integration returns a binding error, verify that the binding name in config matches the binding declared in `wrangler.toml` and that the target Worker is deployed.
* If a pre-process hook does not short-circuit as expected, check that the hook function returns a `Response` object -- returning `undefined` or `null` lets the request continue to the main integration.
* If post-process hooks are not running, confirm the hook config uses the correct `binding` and `function` field names and that the hook Worker is deployed and bound.

## Related docs

* [service binding](/configuration/service-binding)
* [servers](/configuration/servers)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Service Binding Worker Methods

Use service bindings when you want worker-to-worker calls through Cloudflare bindings instead of external HTTP. Service bindings provide zero-latency calls

Use service bindings when you want worker-to-worker calls through Cloudflare bindings instead of external HTTP. Service bindings provide zero-latency calls between Workers in the same Cloudflare account. This page explains how to configure the binding, reference it in config, and call specific methods on the target Worker.

**Last reviewed:** 2026-03-06

## When to use this

Use the service execution recipes when your routes need to call Worker code directly instead of proxying to an external HTTP endpoint. The gateway supports two patterns: local service modules bundled with the worker, and service bindings that call separately deployed Workers via Cloudflare bindings.

## Key concepts

* The `service` integration type imports a local JavaScript module from the worker project and calls its default export. The module ships in the same worker bundle.
* The `service_binding` integration type calls a separately deployed Worker through a Cloudflare service binding. The target Worker must be deployed independently and bound in `wrangler.toml`.
* Pre-process hooks run before the main integration and can short-circuit the request by returning a response. Use them for custom authorization, input validation, or request enrichment.
* Post-process hooks run after the main integration returns and can modify the response. The Auth0 callback post-process hook is the most common use case.
* When choosing between proxy and service execution, consider latency (service bindings avoid an external HTTP round-trip) and coupling (proxy keeps the backend independently deployable).

## Repo-grounded example

```json
{
  "serviceBindings": [
    { "alias": "hooks", "binding": "HOOKS" },
    { "alias": "target", "binding": "TARGET" }
  ],
  "paths": [
    {
      "method": "POST",
      "path": "/orders",
      "pre_process": { "binding": "hooks", "function": "before" },
      "integration": {
        "type": "service_binding",
        "binding": "target",
        "function": "run"
      }
    }
  ]
}
```

This snippet uses `serviceBindings` to define two bound Workers: `hooks` for pre-processing and `target` for the main integration. The `function` field on each integration specifies which method the gateway calls on the bound Worker.

## Troubleshooting

* If a `service` integration returns 500, confirm that the entrypoint path in the `services` array matches the actual file location relative to the worker root and that the module exports a default function.
* If a `service_binding` integration returns a binding error, verify that the binding name in config matches the binding declared in `wrangler.toml` and that the target Worker is deployed.
* If a pre-process hook does not short-circuit as expected, check that the hook function returns a `Response` object -- returning `undefined` or `null` lets the request continue to the main integration.
* If post-process hooks are not running, confirm the hook config uses the correct `binding` and `function` field names and that the hook Worker is deployed and bound.

## Related docs

* [service binding](/configuration/service-binding)
* [servers](/configuration/servers)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Pre-Process Hooks

Short-circuit requests before the main integration when policy checks or custom gating logic must run first. The \`pre\_process\` field on a path entry calls a

Short-circuit requests before the main integration when policy checks or custom gating logic must run first. The `pre_process` field on a path entry calls a service binding function before the main integration. If the hook returns a Response, the gateway sends it immediately without calling the main integration.

**Last reviewed:** 2026-03-06

## When to use this

Use the service execution recipes when your routes need to call Worker code directly instead of proxying to an external HTTP endpoint. The gateway supports two patterns: local service modules bundled with the worker, and service bindings that call separately deployed Workers via Cloudflare bindings.

## Key concepts

* The `service` integration type imports a local JavaScript module from the worker project and calls its default export. The module ships in the same worker bundle.
* The `service_binding` integration type calls a separately deployed Worker through a Cloudflare service binding. The target Worker must be deployed independently and bound in `wrangler.toml`.
* Pre-process hooks run before the main integration and can short-circuit the request by returning a response. Use them for custom authorization, input validation, or request enrichment.
* Post-process hooks run after the main integration returns and can modify the response. The Auth0 callback post-process hook is the most common use case.
* When choosing between proxy and service execution, consider latency (service bindings avoid an external HTTP round-trip) and coupling (proxy keeps the backend independently deployable).

## Repo-grounded example

```json
{
  "serviceBindings": [
    { "alias": "hooks", "binding": "HOOKS" },
    { "alias": "target", "binding": "TARGET" }
  ],
  "paths": [
    {
      "method": "POST",
      "path": "/orders",
      "pre_process": { "binding": "hooks", "function": "before" },
      "integration": {
        "type": "service_binding",
        "binding": "target",
        "function": "run"
      }
    }
  ]
}
```

This snippet adds a `pre_process` hook that calls the `before` function on the `hooks` service binding. If `before` returns a Response (e.g., a 403 Forbidden), the gateway returns it directly. If it returns nothing, the request continues to the `target` integration.

## Troubleshooting

* If a `service` integration returns 500, confirm that the entrypoint path in the `services` array matches the actual file location relative to the worker root and that the module exports a default function.
* If a `service_binding` integration returns a binding error, verify that the binding name in config matches the binding declared in `wrangler.toml` and that the target Worker is deployed.
* If a pre-process hook does not short-circuit as expected, check that the hook function returns a `Response` object -- returning `undefined` or `null` lets the request continue to the main integration.
* If post-process hooks are not running, confirm the hook config uses the correct `binding` and `function` field names and that the hook Worker is deployed and bound.

## Related docs

* [service binding](/configuration/service-binding)
* [servers](/configuration/servers)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Post-Process Hooks After Auth0 Callback

Run post-processing only when the Auth0 callback needs extra side effects after token exchange succeeds. The Auth0 callback integration supports a post-process

Run post-processing only when the Auth0 callback needs extra side effects after token exchange succeeds. The Auth0 callback integration supports a post-process hook that runs after the authorization code is exchanged for tokens. Use this to store tokens, create sessions, or enrich the callback response.

**Last reviewed:** 2026-03-06

## When to use this

Use the service execution recipes when your routes need to call Worker code directly instead of proxying to an external HTTP endpoint. The gateway supports two patterns: local service modules bundled with the worker, and service bindings that call separately deployed Workers via Cloudflare bindings.

## Key concepts

* The `service` integration type imports a local JavaScript module from the worker project and calls its default export. The module ships in the same worker bundle.
* The `service_binding` integration type calls a separately deployed Worker through a Cloudflare service binding. The target Worker must be deployed independently and bound in `wrangler.toml`.
* Pre-process hooks run before the main integration and can short-circuit the request by returning a response. Use them for custom authorization, input validation, or request enrichment.
* Post-process hooks run after the main integration returns and can modify the response. The Auth0 callback post-process hook is the most common use case.
* When choosing between proxy and service execution, consider latency (service bindings avoid an external HTTP round-trip) and coupling (proxy keeps the backend independently deployable).

## Repo-grounded example

```json
{
  "authorizer": {
    "type": "auth0",
    "domain": "$env.AUTH0_DOMAIN",
    "client_id": "$env.AUTH0_CLIENT_ID",
    "client_secret": "$secrets.AUTH0_CLIENT_SECRET",
    "redirect_uri": "https://api.example.com/api/v1/auth0/callback",
    "callback_uri": "https://app.example.com/auth/callback",
    "jwks_uri": "https://tenant.us.auth0.com/.well-known/jwks.json",
    "scope": "openid profile email"
  },
  "paths": [
    {
      "method": "GET",
      "path": "/api/v1/auth0/callback",
      "integration": { "type": "auth0_callback" }
    }
  ]
}
```

This snippet shows the Auth0 authorizer and callback route. To add a post-process hook, include a `post_process` field on the callback path entry with a `binding` and `function` that reference a service binding Worker. The hook receives the token exchange response.

## Troubleshooting

* If a `service` integration returns 500, confirm that the entrypoint path in the `services` array matches the actual file location relative to the worker root and that the module exports a default function.
* If a `service_binding` integration returns a binding error, verify that the binding name in config matches the binding declared in `wrangler.toml` and that the target Worker is deployed.
* If a pre-process hook does not short-circuit as expected, check that the hook function returns a `Response` object -- returning `undefined` or `null` lets the request continue to the main integration.
* If post-process hooks are not running, confirm the hook config uses the correct `binding` and `function` field names and that the hook Worker is deployed and bound.

## Related docs

* [service binding](/configuration/service-binding)
* [servers](/configuration/servers)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Worker-to-Worker API Composition

Compose internal Worker services behind one public gateway without turning every call into an external proxy. Service bindings let you build microservice-style

Compose internal Worker services behind one public gateway without turning every call into an external proxy. Service bindings let you build microservice-style architectures where multiple Workers collaborate through zero-latency bindings. This page shows how to wire multiple service bindings into a single gateway config.

**Last reviewed:** 2026-03-06

## When to use this

Use the service execution recipes when your routes need to call Worker code directly instead of proxying to an external HTTP endpoint. The gateway supports two patterns: local service modules bundled with the worker, and service bindings that call separately deployed Workers via Cloudflare bindings.

## Key concepts

* The `service` integration type imports a local JavaScript module from the worker project and calls its default export. The module ships in the same worker bundle.
* The `service_binding` integration type calls a separately deployed Worker through a Cloudflare service binding. The target Worker must be deployed independently and bound in `wrangler.toml`.
* Pre-process hooks run before the main integration and can short-circuit the request by returning a response. Use them for custom authorization, input validation, or request enrichment.
* Post-process hooks run after the main integration returns and can modify the response. The Auth0 callback post-process hook is the most common use case.
* When choosing between proxy and service execution, consider latency (service bindings avoid an external HTTP round-trip) and coupling (proxy keeps the backend independently deployable).

## Repo-grounded example

```json
{
  "serviceBindings": [
    { "alias": "hooks", "binding": "HOOKS" },
    { "alias": "target", "binding": "TARGET" }
  ],
  "paths": [
    {
      "method": "POST",
      "path": "/orders",
      "pre_process": { "binding": "hooks", "function": "before" },
      "integration": {
        "type": "service_binding",
        "binding": "target",
        "function": "run"
      }
    }
  ]
}
```

This snippet wires two service bindings into a single path: a `pre_process` hook and a main integration. You can extend this pattern by adding more paths that reference different service bindings, building a composed API surface from multiple independently developed Workers.

## Troubleshooting

* If a `service` integration returns 500, confirm that the entrypoint path in the `services` array matches the actual file location relative to the worker root and that the module exports a default function.
* If a `service_binding` integration returns a binding error, verify that the binding name in config matches the binding declared in `wrangler.toml` and that the target Worker is deployed.
* If a pre-process hook does not short-circuit as expected, check that the hook function returns a `Response` object -- returning `undefined` or `null` lets the request continue to the main integration.
* If post-process hooks are not running, confirm the hook config uses the correct `binding` and `function` field names and that the hook Worker is deployed and bound.

## Related docs

* [service binding](/configuration/service-binding)
* [servers](/configuration/servers)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Choosing Proxy vs Service Execution

Use this page when you are deciding whether a route should proxy upstream HTTP or execute worker code directly. Proxy routes (\`http\_proxy\`) forward requests to

Use this page when you are deciding whether a route should proxy upstream HTTP or execute worker code directly. Proxy routes (`http_proxy`) forward requests to external HTTP endpoints, while service routes call local or bound Worker code. This page compares latency, coupling, and deployment tradeoffs to help you choose.

**Last reviewed:** 2026-03-06

## When to use this

Use the service execution recipes when your routes need to call Worker code directly instead of proxying to an external HTTP endpoint. The gateway supports two patterns: local service modules bundled with the worker, and service bindings that call separately deployed Workers via Cloudflare bindings.

## Key concepts

* The `service` integration type imports a local JavaScript module from the worker project and calls its default export. The module ships in the same worker bundle.
* The `service_binding` integration type calls a separately deployed Worker through a Cloudflare service binding. The target Worker must be deployed independently and bound in `wrangler.toml`.
* Pre-process hooks run before the main integration and can short-circuit the request by returning a response. Use them for custom authorization, input validation, or request enrichment.
* Post-process hooks run after the main integration returns and can modify the response. The Auth0 callback post-process hook is the most common use case.
* When choosing between proxy and service execution, consider latency (service bindings avoid an external HTTP round-trip) and coupling (proxy keeps the backend independently deployable).

## Repo-grounded example

```json
{
  "servers": [
    { "alias": "upstream", "url": "https://api.example.com/base" }
  ],
  "paths": [
    {
      "method": "GET",
      "path": "/proxy/{.+}",
      "integration": {
        "type": "http_proxy",
        "server": "upstream"
      }
    }
  ]
}
```

This snippet uses an `http_proxy` integration that forwards requests to an external upstream. Compare this with the `service` or `service_binding` integration types, which execute Worker code directly without an external HTTP round-trip.

## Troubleshooting

* If a `service` integration returns 500, confirm that the entrypoint path in the `services` array matches the actual file location relative to the worker root and that the module exports a default function.
* If a `service_binding` integration returns a binding error, verify that the binding name in config matches the binding declared in `wrangler.toml` and that the target Worker is deployed.
* If a pre-process hook does not short-circuit as expected, check that the hook function returns a `Response` object -- returning `undefined` or `null` lets the request continue to the main integration.
* If post-process hooks are not running, confirm the hook config uses the correct `binding` and `function` field names and that the hook Worker is deployed and bound.

## Related docs

* [service binding](/configuration/service-binding)
* [servers](/configuration/servers)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# JWT And Security

Use HS256 JWT auth when you control the signing secret and want simple issuer and audience validation. This guide walks through configuring the authorizer block

Use HS256 JWT auth when you control the signing secret and want simple issuer and audience validation. This guide walks through configuring the authorizer block with a shared secret, setting the algorithm, and enabling auth on specific routes. HS256 is the simplest JWT setup and works well for internal APIs and single-tenant applications.

**Last reviewed:** 2026-03-06

## When to use this

Use the JWT and security guides when you need to protect routes with token-based authentication. The gateway validates JWT tokens at the edge before the request reaches your upstream, reducing load on your backend and centralizing auth checks in one place.

## Key concepts

* The gateway supports HS256 JWT validation with a shared secret. The secret is configured in the `authorizer` block and should be stored as a Cloudflare secret, not hardcoded in config.
* Issuer (`iss`) and audience (`aud`) claims are validated when configured. If either check fails, the gateway returns a 401 with a specific error message identifying which claim was invalid.
* Auth is opt-in per route: only paths with `auth: true` require a valid JWT. All other paths are public by default, even when an authorizer is configured.
* The gateway extracts the token from the `Authorization: Bearer <token>` header. No other token locations (cookies, query params) are supported.
* The gateway does not implement role-based access control, token revocation, or scope-based permissions. These must be handled by your upstream service or a pre-process hook.

## Repo-grounded example

```json
{
  "authorizer": {
    "type": "jwt",
    "secret": "$env.JWT_SECRET",
    "algorithm": "HS256",
    "issuer": "https://issuer.example.com",
    "audience": "api-audience"
  },
  "paths": [
    {
      "method": "GET",
      "path": "/private",
      "auth": true,
      "response": { "private": true }
    }
  ]
}
```

This snippet configures the `authorizer` with `type: "jwt"`, an HS256 algorithm, and a secret loaded from `$env.JWT_SECRET`. The `issuer` and `audience` fields add claim validation, and the `/private` path has `auth: true` to require a valid token.

## Troubleshooting

* If you get a 401 "missing authorization header" error, confirm the client sends the `Authorization` header with the `Bearer` prefix (note the space after Bearer).
* If you get a 401 "token expired" error, check the `exp` claim in your JWT -- the gateway compares it against the current UTC time on the Cloudflare edge node.
* If issuer or audience validation fails, decode your token at jwt.io and compare the `iss` and `aud` claims exactly (case-sensitive) against the values in your authorizer config.
* If a public route unexpectedly returns 401, verify that the route does not have `auth: true` set -- check for typos like `"auth": "true"` (string vs boolean).

## Related docs

* [authorizer](/configuration/authorizer)
* [authentication](/configuration/authentication)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# JWT Issuer and Audience Checks

Set issuer and audience correctly so tokens from the wrong tenant or app are rejected at the edge. The gateway compares the \`iss\` and \`aud\` claims in the JWT

Set issuer and audience correctly so tokens from the wrong tenant or app are rejected at the edge. The gateway compares the `iss` and `aud` claims in the JWT payload against the values in your authorizer config. This page explains how each check works and what error messages indicate a mismatch.

**Last reviewed:** 2026-03-06

## When to use this

Use the JWT and security guides when you need to protect routes with token-based authentication. The gateway validates JWT tokens at the edge before the request reaches your upstream, reducing load on your backend and centralizing auth checks in one place.

## Key concepts

* The gateway supports HS256 JWT validation with a shared secret. The secret is configured in the `authorizer` block and should be stored as a Cloudflare secret, not hardcoded in config.
* Issuer (`iss`) and audience (`aud`) claims are validated when configured. If either check fails, the gateway returns a 401 with a specific error message identifying which claim was invalid.
* Auth is opt-in per route: only paths with `auth: true` require a valid JWT. All other paths are public by default, even when an authorizer is configured.
* The gateway extracts the token from the `Authorization: Bearer <token>` header. No other token locations (cookies, query params) are supported.
* The gateway does not implement role-based access control, token revocation, or scope-based permissions. These must be handled by your upstream service or a pre-process hook.

## Repo-grounded example

```json
{
  "authorizer": {
    "type": "jwt",
    "secret": "$env.JWT_SECRET",
    "algorithm": "HS256",
    "issuer": "https://issuer.example.com",
    "audience": "api-audience"
  },
  "paths": [
    {
      "method": "GET",
      "path": "/private",
      "auth": true,
      "response": { "private": true }
    }
  ]
}
```

This snippet sets `issuer` to `"https://issuer.example.com"` and `audience` to `"api-audience"`. The gateway checks the `iss` and `aud` claims in every token presented to an `auth: true` route and returns a 401 if either does not match exactly.

## Troubleshooting

* If you get a 401 "missing authorization header" error, confirm the client sends the `Authorization` header with the `Bearer` prefix (note the space after Bearer).
* If you get a 401 "token expired" error, check the `exp` claim in your JWT -- the gateway compares it against the current UTC time on the Cloudflare edge node.
* If issuer or audience validation fails, decode your token at jwt.io and compare the `iss` and `aud` claims exactly (case-sensitive) against the values in your authorizer config.
* If a public route unexpectedly returns 401, verify that the route does not have `auth: true` set -- check for typos like `"auth": "true"` (string vs boolean).

## Related docs

* [authorizer](/configuration/authorizer)
* [authentication](/configuration/authentication)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# JWT: Protect Only Selected Routes

Gate only sensitive endpoints by setting \`auth: true\` where it matters instead of forcing auth on the whole API. The authorizer block configures how tokens are

Gate only sensitive endpoints by setting `auth: true` where it matters instead of forcing auth on the whole API. The authorizer block configures how tokens are validated, but routes are public by default. This page explains how to mix public and protected routes in the same gateway config.

**Last reviewed:** 2026-03-06

## When to use this

Use the JWT and security guides when you need to protect routes with token-based authentication. The gateway validates JWT tokens at the edge before the request reaches your upstream, reducing load on your backend and centralizing auth checks in one place.

## Key concepts

* The gateway supports HS256 JWT validation with a shared secret. The secret is configured in the `authorizer` block and should be stored as a Cloudflare secret, not hardcoded in config.
* Issuer (`iss`) and audience (`aud`) claims are validated when configured. If either check fails, the gateway returns a 401 with a specific error message identifying which claim was invalid.
* Auth is opt-in per route: only paths with `auth: true` require a valid JWT. All other paths are public by default, even when an authorizer is configured.
* The gateway extracts the token from the `Authorization: Bearer <token>` header. No other token locations (cookies, query params) are supported.
* The gateway does not implement role-based access control, token revocation, or scope-based permissions. These must be handled by your upstream service or a pre-process hook.

## Repo-grounded example

```json
{
  "authorizer": {
    "type": "jwt",
    "secret": "$env.JWT_SECRET",
    "algorithm": "HS256",
    "issuer": "https://issuer.example.com",
    "audience": "api-audience"
  },
  "paths": [
    {
      "method": "GET",
      "path": "/private",
      "auth": true,
      "response": { "private": true }
    }
  ]
}
```

This snippet shows an authorizer block alongside a single `auth: true` route. Any other paths in the `paths` array without `auth: true` remain publicly accessible, even though the authorizer is configured globally.

## Troubleshooting

* If you get a 401 "missing authorization header" error, confirm the client sends the `Authorization` header with the `Bearer` prefix (note the space after Bearer).
* If you get a 401 "token expired" error, check the `exp` claim in your JWT -- the gateway compares it against the current UTC time on the Cloudflare edge node.
* If issuer or audience validation fails, decode your token at jwt.io and compare the `iss` and `aud` claims exactly (case-sensitive) against the values in your authorizer config.
* If a public route unexpectedly returns 401, verify that the route does not have `auth: true` set -- check for typos like `"auth": "true"` (string vs boolean).

## Related docs

* [authorizer](/configuration/authorizer)
* [authentication](/configuration/authentication)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# JWT: Common 401 Errors

Debug missing bearer tokens, expired tokens, and invalid claims before blaming the upstream service. The gateway returns specific 401 error messages for each

Debug missing bearer tokens, expired tokens, and invalid claims before blaming the upstream service. The gateway returns specific 401 error messages for each validation failure, including "missing authorization header", "token expired", "invalid issuer", and "invalid audience". This page catalogs each error and its fix.

**Last reviewed:** 2026-03-06

## When to use this

Use the JWT and security guides when you need to protect routes with token-based authentication. The gateway validates JWT tokens at the edge before the request reaches your upstream, reducing load on your backend and centralizing auth checks in one place.

## Key concepts

* The gateway supports HS256 JWT validation with a shared secret. The secret is configured in the `authorizer` block and should be stored as a Cloudflare secret, not hardcoded in config.
* Issuer (`iss`) and audience (`aud`) claims are validated when configured. If either check fails, the gateway returns a 401 with a specific error message identifying which claim was invalid.
* Auth is opt-in per route: only paths with `auth: true` require a valid JWT. All other paths are public by default, even when an authorizer is configured.
* The gateway extracts the token from the `Authorization: Bearer <token>` header. No other token locations (cookies, query params) are supported.
* The gateway does not implement role-based access control, token revocation, or scope-based permissions. These must be handled by your upstream service or a pre-process hook.

## Repo-grounded example

```json
{
  "authorizer": {
    "type": "jwt",
    "secret": "$env.JWT_SECRET",
    "algorithm": "HS256",
    "issuer": "https://issuer.example.com",
    "audience": "api-audience"
  },
  "paths": [
    {
      "method": "GET",
      "path": "/private",
      "auth": true,
      "response": { "private": true }
    }
  ]
}
```

This snippet configures JWT validation with issuer and audience checks. When a request fails validation, the gateway returns a 401 JSON response with an error message identifying the specific failure (expired token, wrong issuer, wrong audience, or missing header).

## Troubleshooting

* If you get a 401 "missing authorization header" error, confirm the client sends the `Authorization` header with the `Bearer` prefix (note the space after Bearer).
* If you get a 401 "token expired" error, check the `exp` claim in your JWT -- the gateway compares it against the current UTC time on the Cloudflare edge node.
* If issuer or audience validation fails, decode your token at jwt.io and compare the `iss` and `aud` claims exactly (case-sensitive) against the values in your authorizer config.
* If a public route unexpectedly returns 401, verify that the route does not have `auth: true` set -- check for typos like `"auth": "true"` (string vs boolean).

## Related docs

* [authorizer](/configuration/authorizer)
* [authentication](/configuration/authentication)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Designing Public vs Private Routes

Separate public and private paths clearly so your API contract stays understandable for clients and maintainers. Group public routes (health, docs, login)

Separate public and private paths clearly so your API contract stays understandable for clients and maintainers. Group public routes (health, docs, login) together and private routes (user data, admin) together in your config for readability. This page offers patterns for organizing routes by access level.

**Last reviewed:** 2026-03-06

## When to use this

Use the JWT and security guides when you need to protect routes with token-based authentication. The gateway validates JWT tokens at the edge before the request reaches your upstream, reducing load on your backend and centralizing auth checks in one place.

## Key concepts

* The gateway supports HS256 JWT validation with a shared secret. The secret is configured in the `authorizer` block and should be stored as a Cloudflare secret, not hardcoded in config.
* Issuer (`iss`) and audience (`aud`) claims are validated when configured. If either check fails, the gateway returns a 401 with a specific error message identifying which claim was invalid.
* Auth is opt-in per route: only paths with `auth: true` require a valid JWT. All other paths are public by default, even when an authorizer is configured.
* The gateway extracts the token from the `Authorization: Bearer <token>` header. No other token locations (cookies, query params) are supported.
* The gateway does not implement role-based access control, token revocation, or scope-based permissions. These must be handled by your upstream service or a pre-process hook.

## Repo-grounded example

```json
{
  "authorizer": {
    "type": "jwt",
    "secret": "$env.JWT_SECRET",
    "algorithm": "HS256",
    "issuer": "https://issuer.example.com",
    "audience": "api-audience"
  },
  "paths": [
    {
      "method": "GET",
      "path": "/private",
      "auth": true,
      "response": { "private": true }
    }
  ]
}
```

This snippet places a private route with `auth: true` alongside the authorizer config. In a real config, you would add public routes (without `auth: true`) for endpoints like `/health` or `/login` so clients can access them without a token.

## Troubleshooting

* If you get a 401 "missing authorization header" error, confirm the client sends the `Authorization` header with the `Bearer` prefix (note the space after Bearer).
* If you get a 401 "token expired" error, check the `exp` claim in your JWT -- the gateway compares it against the current UTC time on the Cloudflare edge node.
* If issuer or audience validation fails, decode your token at jwt.io and compare the `iss` and `aud` claims exactly (case-sensitive) against the values in your authorizer config.
* If a public route unexpectedly returns 401, verify that the route does not have `auth: true` set -- check for typos like `"auth": "true"` (string vs boolean).

## Related docs

* [authorizer](/configuration/authorizer)
* [authentication](/configuration/authentication)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Bearer Token Handling

Use the standard Authorization header format so built-in token extraction works consistently. The gateway expects tokens in the \`Authorization: Bearer \<token>\`

Use the standard Authorization header format so built-in token extraction works consistently. The gateway expects tokens in the `Authorization: Bearer <token>` header and does not support tokens in cookies, query parameters, or custom headers. This page documents the exact format and common mistakes.

**Last reviewed:** 2026-03-06

## When to use this

Use the JWT and security guides when you need to protect routes with token-based authentication. The gateway validates JWT tokens at the edge before the request reaches your upstream, reducing load on your backend and centralizing auth checks in one place.

## Key concepts

* The gateway supports HS256 JWT validation with a shared secret. The secret is configured in the `authorizer` block and should be stored as a Cloudflare secret, not hardcoded in config.
* Issuer (`iss`) and audience (`aud`) claims are validated when configured. If either check fails, the gateway returns a 401 with a specific error message identifying which claim was invalid.
* Auth is opt-in per route: only paths with `auth: true` require a valid JWT. All other paths are public by default, even when an authorizer is configured.
* The gateway extracts the token from the `Authorization: Bearer <token>` header. No other token locations (cookies, query params) are supported.
* The gateway does not implement role-based access control, token revocation, or scope-based permissions. These must be handled by your upstream service or a pre-process hook.

## Repo-grounded example

```json
{
  "authorizer": {
    "type": "jwt",
    "secret": "$env.JWT_SECRET",
    "algorithm": "HS256",
    "issuer": "https://issuer.example.com",
    "audience": "api-audience"
  },
  "paths": [
    {
      "method": "GET",
      "path": "/private",
      "auth": true,
      "response": { "private": true }
    }
  ]
}
```

This snippet configures JWT validation. The gateway extracts the token by splitting the `Authorization` header value on the space character and taking the second part. If the header is missing or does not start with `Bearer` , the gateway returns a 401.

## Troubleshooting

* If you get a 401 "missing authorization header" error, confirm the client sends the `Authorization` header with the `Bearer` prefix (note the space after Bearer).
* If you get a 401 "token expired" error, check the `exp` claim in your JWT -- the gateway compares it against the current UTC time on the Cloudflare edge node.
* If issuer or audience validation fails, decode your token at jwt.io and compare the `iss` and `aud` claims exactly (case-sensitive) against the values in your authorizer config.
* If a public route unexpectedly returns 401, verify that the route does not have `auth: true` set -- check for typos like `"auth": "true"` (string vs boolean).

## Related docs

* [authorizer](/configuration/authorizer)
* [authentication](/configuration/authentication)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Security Limitations and Non-Goals

Understand what the gateway does not implement today so you can avoid overclaiming its security surface. The gateway handles JWT validation, issuer/audience

Understand what the gateway does not implement today so you can avoid overclaiming its security surface. The gateway handles JWT validation, issuer/audience checks, and token extraction. It does not implement role-based access control, token revocation lists, scope-based permissions, or request signing. Plan your security architecture accordingly.

**Last reviewed:** 2026-03-06

## When to use this

Use the JWT and security guides when you need to protect routes with token-based authentication. The gateway validates JWT tokens at the edge before the request reaches your upstream, reducing load on your backend and centralizing auth checks in one place.

## Key concepts

* The gateway supports HS256 JWT validation with a shared secret. The secret is configured in the `authorizer` block and should be stored as a Cloudflare secret, not hardcoded in config.
* Issuer (`iss`) and audience (`aud`) claims are validated when configured. If either check fails, the gateway returns a 401 with a specific error message identifying which claim was invalid.
* Auth is opt-in per route: only paths with `auth: true` require a valid JWT. All other paths are public by default, even when an authorizer is configured.
* The gateway extracts the token from the `Authorization: Bearer <token>` header. No other token locations (cookies, query params) are supported.
* The gateway does not implement role-based access control, token revocation, or scope-based permissions. These must be handled by your upstream service or a pre-process hook.

## Repo-grounded example

```json
{
  "authorizer": {
    "type": "jwt",
    "secret": "$env.JWT_SECRET",
    "algorithm": "HS256",
    "issuer": "https://issuer.example.com",
    "audience": "api-audience"
  },
  "paths": [
    {
      "method": "GET",
      "path": "/private",
      "auth": true,
      "response": { "private": true }
    }
  ]
}
```

This snippet shows the full extent of the gateway's auth capability: a shared secret, algorithm, issuer, audience, and per-route `auth` flag. Features beyond this -- such as RBAC, scopes, or token blacklists -- must be implemented in your upstream service or via a pre-process hook.

## Troubleshooting

* If you get a 401 "missing authorization header" error, confirm the client sends the `Authorization` header with the `Bearer` prefix (note the space after Bearer).
* If you get a 401 "token expired" error, check the `exp` claim in your JWT -- the gateway compares it against the current UTC time on the Cloudflare edge node.
* If issuer or audience validation fails, decode your token at jwt.io and compare the `iss` and `aud` claims exactly (case-sensitive) against the values in your authorizer config.
* If a public route unexpectedly returns 401, verify that the route does not have `auth: true` set -- check for typos like `"auth": "true"` (string vs boolean).

## Related docs

* [authorizer](/configuration/authorizer)
* [authentication](/configuration/authentication)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Auth0

Configure Auth0 when you need hosted identity, JWKS-backed verification, and callback flows at the gateway. This guide covers the full authorizer block,

Configure Auth0 when you need hosted identity, JWKS-backed verification, and callback flows at the gateway. This guide covers the full authorizer block, required environment variables, and the minimum paths needed for an Auth0 integration. Start here before configuring individual Auth0 routes.

**Last reviewed:** 2026-03-06

## When to use this

Use the Auth0 integration guides when your application uses Auth0 as its identity provider and you want the gateway to handle login redirects, callback token exchange, userinfo retrieval, and token refresh at the edge. This keeps Auth0-specific logic out of your backend services.

## Key concepts

* The Auth0 authorizer uses JWKS (JSON Web Key Sets) to verify tokens, so you do not need to manage signing secrets manually. Configure either a static `jwks` object or a `jwks_uri` that the gateway fetches at startup.
* The callback integration (`auth0_callback`) exchanges the authorization code for tokens at the edge, so your backend never sees the authorization code or client secret.
* The login redirect integration sends users to Auth0's `/authorize` endpoint with the correct parameters. The gateway constructs the redirect URL from the authorizer config.
* Refresh token and userinfo routes let you centralize all Auth0 API interactions behind the gateway, giving clients a single domain for auth operations.
* All Auth0 secrets (client\_secret, domain) should use `$secrets.*` or `$env.*` placeholders so they are resolved from Cloudflare environment variables at startup.

## Repo-grounded example

```json
{
  "authorizer": {
    "type": "auth0",
    "domain": "$env.AUTH0_DOMAIN",
    "client_id": "$env.AUTH0_CLIENT_ID",
    "client_secret": "$secrets.AUTH0_CLIENT_SECRET",
    "redirect_uri": "https://api.example.com/api/v1/auth0/callback",
    "callback_uri": "https://app.example.com/auth/callback",
    "jwks_uri": "https://tenant.us.auth0.com/.well-known/jwks.json",
    "scope": "openid profile email"
  },
  "paths": [
    {
      "method": "GET",
      "path": "/api/v1/auth0/callback",
      "integration": { "type": "auth0_callback" }
    }
  ]
}
```

This snippet defines the Auth0 authorizer with domain, client credentials, JWKS URI, redirect/callback URIs, and scope. The callback path uses the `auth0_callback` integration type. All sensitive values use `$env.*` and `$secrets.*` placeholders for safe deployment.

## Troubleshooting

* If the callback route returns a 500, confirm that `redirect_uri` in your config exactly matches the callback URL registered in your Auth0 application settings (including scheme and path).
* If JWKS validation fails, check that the `jwks_uri` is reachable from the Cloudflare edge and returns a valid JWKS JSON document. Test it with `curl` from your local machine first.
* If the login redirect goes to the wrong Auth0 tenant, verify that `domain` in the authorizer block points to your correct Auth0 tenant (e.g., `your-tenant.us.auth0.com`).
* If refresh token exchange returns an error, confirm that the Auth0 application has "Refresh Token Rotation" enabled and that the `offline_access` scope is included.

## Related docs

* [auth0](/configuration/auth0)
* [authorizer](/configuration/authorizer)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Auth0: JWKS vs JWKS URI

Choose local JWKS or remote JWKS URI based on whether you want static config or dynamic key retrieval. A local \`jwks\` object bakes the key set into your config,

Choose local JWKS or remote JWKS URI based on whether you want static config or dynamic key retrieval. A local `jwks` object bakes the key set into your config, which avoids a network call at startup but requires manual updates when Auth0 rotates keys. A `jwks_uri` fetches keys dynamically but adds startup latency.

**Last reviewed:** 2026-03-06

## When to use this

Use the Auth0 integration guides when your application uses Auth0 as its identity provider and you want the gateway to handle login redirects, callback token exchange, userinfo retrieval, and token refresh at the edge. This keeps Auth0-specific logic out of your backend services.

## Key concepts

* The Auth0 authorizer uses JWKS (JSON Web Key Sets) to verify tokens, so you do not need to manage signing secrets manually. Configure either a static `jwks` object or a `jwks_uri` that the gateway fetches at startup.
* The callback integration (`auth0_callback`) exchanges the authorization code for tokens at the edge, so your backend never sees the authorization code or client secret.
* The login redirect integration sends users to Auth0's `/authorize` endpoint with the correct parameters. The gateway constructs the redirect URL from the authorizer config.
* Refresh token and userinfo routes let you centralize all Auth0 API interactions behind the gateway, giving clients a single domain for auth operations.
* All Auth0 secrets (client\_secret, domain) should use `$secrets.*` or `$env.*` placeholders so they are resolved from Cloudflare environment variables at startup.

## Repo-grounded example

```json
{
  "authorizer": {
    "type": "auth0",
    "domain": "$env.AUTH0_DOMAIN",
    "client_id": "$env.AUTH0_CLIENT_ID",
    "client_secret": "$secrets.AUTH0_CLIENT_SECRET",
    "redirect_uri": "https://api.example.com/api/v1/auth0/callback",
    "callback_uri": "https://app.example.com/auth/callback",
    "jwks_uri": "https://tenant.us.auth0.com/.well-known/jwks.json",
    "scope": "openid profile email"
  },
  "paths": [
    {
      "method": "GET",
      "path": "/api/v1/auth0/callback",
      "integration": { "type": "auth0_callback" }
    }
  ]
}
```

This snippet uses `jwks_uri` to point at Auth0's well-known JWKS endpoint. The gateway fetches the key set at startup and uses it to verify token signatures. To use a static JWKS, replace `jwks_uri` with a `jwks` field containing the full key set JSON.

## Troubleshooting

* If the callback route returns a 500, confirm that `redirect_uri` in your config exactly matches the callback URL registered in your Auth0 application settings (including scheme and path).
* If JWKS validation fails, check that the `jwks_uri` is reachable from the Cloudflare edge and returns a valid JWKS JSON document. Test it with `curl` from your local machine first.
* If the login redirect goes to the wrong Auth0 tenant, verify that `domain` in the authorizer block points to your correct Auth0 tenant (e.g., `your-tenant.us.auth0.com`).
* If refresh token exchange returns an error, confirm that the Auth0 application has "Refresh Token Rotation" enabled and that the `offline_access` scope is included.

## Related docs

* [auth0](/configuration/auth0)
* [authorizer](/configuration/authorizer)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Auth0 Callback Route

Use the callback integration to exchange authorization codes for tokens without moving the flow into your upstream. The gateway handles the code-to-token

Use the callback integration to exchange authorization codes for tokens without moving the flow into your upstream. The gateway handles the code-to-token exchange with Auth0's token endpoint at the edge. Your upstream receives the final tokens or an error, never the raw authorization code.

**Last reviewed:** 2026-03-06

## When to use this

Use the Auth0 integration guides when your application uses Auth0 as its identity provider and you want the gateway to handle login redirects, callback token exchange, userinfo retrieval, and token refresh at the edge. This keeps Auth0-specific logic out of your backend services.

## Key concepts

* The Auth0 authorizer uses JWKS (JSON Web Key Sets) to verify tokens, so you do not need to manage signing secrets manually. Configure either a static `jwks` object or a `jwks_uri` that the gateway fetches at startup.
* The callback integration (`auth0_callback`) exchanges the authorization code for tokens at the edge, so your backend never sees the authorization code or client secret.
* The login redirect integration sends users to Auth0's `/authorize` endpoint with the correct parameters. The gateway constructs the redirect URL from the authorizer config.
* Refresh token and userinfo routes let you centralize all Auth0 API interactions behind the gateway, giving clients a single domain for auth operations.
* All Auth0 secrets (client\_secret, domain) should use `$secrets.*` or `$env.*` placeholders so they are resolved from Cloudflare environment variables at startup.

## Repo-grounded example

```json
{
  "authorizer": {
    "type": "auth0",
    "domain": "$env.AUTH0_DOMAIN",
    "client_id": "$env.AUTH0_CLIENT_ID",
    "client_secret": "$secrets.AUTH0_CLIENT_SECRET",
    "redirect_uri": "https://api.example.com/api/v1/auth0/callback",
    "callback_uri": "https://app.example.com/auth/callback",
    "jwks_uri": "https://tenant.us.auth0.com/.well-known/jwks.json",
    "scope": "openid profile email"
  },
  "paths": [
    {
      "method": "GET",
      "path": "/api/v1/auth0/callback",
      "integration": { "type": "auth0_callback" }
    }
  ]
}
```

This snippet defines the callback path at `/api/v1/auth0/callback` with the `auth0_callback` integration type. When Auth0 redirects the user here after login, the gateway exchanges the authorization code for tokens using the client credentials in the authorizer config.

## Troubleshooting

* If the callback route returns a 500, confirm that `redirect_uri` in your config exactly matches the callback URL registered in your Auth0 application settings (including scheme and path).
* If JWKS validation fails, check that the `jwks_uri` is reachable from the Cloudflare edge and returns a valid JWKS JSON document. Test it with `curl` from your local machine first.
* If the login redirect goes to the wrong Auth0 tenant, verify that `domain` in the authorizer block points to your correct Auth0 tenant (e.g., `your-tenant.us.auth0.com`).
* If refresh token exchange returns an error, confirm that the Auth0 application has "Refresh Token Rotation" enabled and that the `offline_access` scope is included.

## Related docs

* [auth0](/configuration/auth0)
* [authorizer](/configuration/authorizer)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Auth0 Login Redirect Route

Use the redirect integration when the gateway should initiate login instead of the frontend hardcoding the authorize URL. The gateway constructs the Auth0

Use the redirect integration when the gateway should initiate login instead of the frontend hardcoding the authorize URL. The gateway constructs the Auth0 `/authorize` URL from the authorizer config and redirects the user. This centralizes the login URL construction so frontend changes are not needed when Auth0 settings change.

**Last reviewed:** 2026-03-06

## When to use this

Use the Auth0 integration guides when your application uses Auth0 as its identity provider and you want the gateway to handle login redirects, callback token exchange, userinfo retrieval, and token refresh at the edge. This keeps Auth0-specific logic out of your backend services.

## Key concepts

* The Auth0 authorizer uses JWKS (JSON Web Key Sets) to verify tokens, so you do not need to manage signing secrets manually. Configure either a static `jwks` object or a `jwks_uri` that the gateway fetches at startup.
* The callback integration (`auth0_callback`) exchanges the authorization code for tokens at the edge, so your backend never sees the authorization code or client secret.
* The login redirect integration sends users to Auth0's `/authorize` endpoint with the correct parameters. The gateway constructs the redirect URL from the authorizer config.
* Refresh token and userinfo routes let you centralize all Auth0 API interactions behind the gateway, giving clients a single domain for auth operations.
* All Auth0 secrets (client\_secret, domain) should use `$secrets.*` or `$env.*` placeholders so they are resolved from Cloudflare environment variables at startup.

## Repo-grounded example

```json
{
  "authorizer": {
    "type": "auth0",
    "domain": "$env.AUTH0_DOMAIN",
    "client_id": "$env.AUTH0_CLIENT_ID",
    "client_secret": "$secrets.AUTH0_CLIENT_SECRET",
    "redirect_uri": "https://api.example.com/api/v1/auth0/callback",
    "callback_uri": "https://app.example.com/auth/callback",
    "jwks_uri": "https://tenant.us.auth0.com/.well-known/jwks.json",
    "scope": "openid profile email"
  },
  "paths": [
    {
      "method": "GET",
      "path": "/api/v1/auth0/callback",
      "integration": { "type": "auth0_callback" }
    }
  ]
}
```

This snippet configures the Auth0 authorizer with the fields needed to construct a login redirect: `domain`, `client_id`, `redirect_uri`, and `scope`. To add a login redirect route, create a path with the `auth0_login_redirect` integration type.

## Troubleshooting

* If the callback route returns a 500, confirm that `redirect_uri` in your config exactly matches the callback URL registered in your Auth0 application settings (including scheme and path).
* If JWKS validation fails, check that the `jwks_uri` is reachable from the Cloudflare edge and returns a valid JWKS JSON document. Test it with `curl` from your local machine first.
* If the login redirect goes to the wrong Auth0 tenant, verify that `domain` in the authorizer block points to your correct Auth0 tenant (e.g., `your-tenant.us.auth0.com`).
* If refresh token exchange returns an error, confirm that the Auth0 application has "Refresh Token Rotation" enabled and that the `offline_access` scope is included.

## Related docs

* [auth0](/configuration/auth0)
* [authorizer](/configuration/authorizer)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Auth0 Userinfo Route

Expose a profile endpoint through the gateway when the client needs a normalized entry point for Auth0 user info. The gateway proxies the userinfo request to

Expose a profile endpoint through the gateway when the client needs a normalized entry point for Auth0 user info. The gateway proxies the userinfo request to Auth0's `/userinfo` endpoint, forwarding the user's access token. This saves the client from needing to know the Auth0 domain or userinfo URL.

**Last reviewed:** 2026-03-06

## When to use this

Use the Auth0 integration guides when your application uses Auth0 as its identity provider and you want the gateway to handle login redirects, callback token exchange, userinfo retrieval, and token refresh at the edge. This keeps Auth0-specific logic out of your backend services.

## Key concepts

* The Auth0 authorizer uses JWKS (JSON Web Key Sets) to verify tokens, so you do not need to manage signing secrets manually. Configure either a static `jwks` object or a `jwks_uri` that the gateway fetches at startup.
* The callback integration (`auth0_callback`) exchanges the authorization code for tokens at the edge, so your backend never sees the authorization code or client secret.
* The login redirect integration sends users to Auth0's `/authorize` endpoint with the correct parameters. The gateway constructs the redirect URL from the authorizer config.
* Refresh token and userinfo routes let you centralize all Auth0 API interactions behind the gateway, giving clients a single domain for auth operations.
* All Auth0 secrets (client\_secret, domain) should use `$secrets.*` or `$env.*` placeholders so they are resolved from Cloudflare environment variables at startup.

## Repo-grounded example

```json
{
  "authorizer": {
    "type": "auth0",
    "domain": "$env.AUTH0_DOMAIN",
    "client_id": "$env.AUTH0_CLIENT_ID",
    "client_secret": "$secrets.AUTH0_CLIENT_SECRET",
    "redirect_uri": "https://api.example.com/api/v1/auth0/callback",
    "callback_uri": "https://app.example.com/auth/callback",
    "jwks_uri": "https://tenant.us.auth0.com/.well-known/jwks.json",
    "scope": "openid profile email"
  },
  "paths": [
    {
      "method": "GET",
      "path": "/api/v1/auth0/callback",
      "integration": { "type": "auth0_callback" }
    }
  ]
}
```

This snippet sets up the Auth0 authorizer with the domain and credentials needed for userinfo requests. To add a userinfo route, create a path with the `auth0_userinfo` integration type -- the gateway forwards the bearer token to Auth0's userinfo endpoint.

## Troubleshooting

* If the callback route returns a 500, confirm that `redirect_uri` in your config exactly matches the callback URL registered in your Auth0 application settings (including scheme and path).
* If JWKS validation fails, check that the `jwks_uri` is reachable from the Cloudflare edge and returns a valid JWKS JSON document. Test it with `curl` from your local machine first.
* If the login redirect goes to the wrong Auth0 tenant, verify that `domain` in the authorizer block points to your correct Auth0 tenant (e.g., `your-tenant.us.auth0.com`).
* If refresh token exchange returns an error, confirm that the Auth0 application has "Refresh Token Rotation" enabled and that the `offline_access` scope is included.

## Related docs

* [auth0](/configuration/auth0)
* [authorizer](/configuration/authorizer)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Auth0 Refresh Token Route

Handle refresh token exchange through the gateway when you want one edge-managed auth surface. The gateway sends the refresh token to Auth0's token endpoint and

Handle refresh token exchange through the gateway when you want one edge-managed auth surface. The gateway sends the refresh token to Auth0's token endpoint and returns the new access token to the client. This keeps the client\_secret on the server side and avoids exposing it in frontend code.

**Last reviewed:** 2026-03-06

## When to use this

Use the Auth0 integration guides when your application uses Auth0 as its identity provider and you want the gateway to handle login redirects, callback token exchange, userinfo retrieval, and token refresh at the edge. This keeps Auth0-specific logic out of your backend services.

## Key concepts

* The Auth0 authorizer uses JWKS (JSON Web Key Sets) to verify tokens, so you do not need to manage signing secrets manually. Configure either a static `jwks` object or a `jwks_uri` that the gateway fetches at startup.
* The callback integration (`auth0_callback`) exchanges the authorization code for tokens at the edge, so your backend never sees the authorization code or client secret.
* The login redirect integration sends users to Auth0's `/authorize` endpoint with the correct parameters. The gateway constructs the redirect URL from the authorizer config.
* Refresh token and userinfo routes let you centralize all Auth0 API interactions behind the gateway, giving clients a single domain for auth operations.
* All Auth0 secrets (client\_secret, domain) should use `$secrets.*` or `$env.*` placeholders so they are resolved from Cloudflare environment variables at startup.

## Repo-grounded example

```json
{
  "authorizer": {
    "type": "auth0",
    "domain": "$env.AUTH0_DOMAIN",
    "client_id": "$env.AUTH0_CLIENT_ID",
    "client_secret": "$secrets.AUTH0_CLIENT_SECRET",
    "redirect_uri": "https://api.example.com/api/v1/auth0/callback",
    "callback_uri": "https://app.example.com/auth/callback",
    "jwks_uri": "https://tenant.us.auth0.com/.well-known/jwks.json",
    "scope": "openid profile email"
  },
  "paths": [
    {
      "method": "GET",
      "path": "/api/v1/auth0/callback",
      "integration": { "type": "auth0_callback" }
    }
  ]
}
```

This snippet configures the Auth0 authorizer with client credentials needed for token refresh. To add a refresh route, create a path with the `auth0_refresh_token` integration type -- the gateway exchanges the refresh token for a new access token using the stored client secret.

## Troubleshooting

* If the callback route returns a 500, confirm that `redirect_uri` in your config exactly matches the callback URL registered in your Auth0 application settings (including scheme and path).
* If JWKS validation fails, check that the `jwks_uri` is reachable from the Cloudflare edge and returns a valid JWKS JSON document. Test it with `curl` from your local machine first.
* If the login redirect goes to the wrong Auth0 tenant, verify that `domain` in the authorizer block points to your correct Auth0 tenant (e.g., `your-tenant.us.auth0.com`).
* If refresh token exchange returns an error, confirm that the Auth0 application has "Refresh Token Rotation" enabled and that the `offline_access` scope is included.

## Related docs

* [auth0](/configuration/auth0)
* [authorizer](/configuration/authorizer)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Auth0 Error Handling

Use this page to understand upstream, network, and validation errors returned by the Auth0 integration. The gateway surfaces Auth0 API errors, network timeouts,

Use this page to understand upstream, network, and validation errors returned by the Auth0 integration. The gateway surfaces Auth0 API errors, network timeouts, and JWKS validation failures as structured JSON responses. This page catalogs each error type and explains what to check when you encounter it.

**Last reviewed:** 2026-03-06

## When to use this

Use the Auth0 integration guides when your application uses Auth0 as its identity provider and you want the gateway to handle login redirects, callback token exchange, userinfo retrieval, and token refresh at the edge. This keeps Auth0-specific logic out of your backend services.

## Key concepts

* The Auth0 authorizer uses JWKS (JSON Web Key Sets) to verify tokens, so you do not need to manage signing secrets manually. Configure either a static `jwks` object or a `jwks_uri` that the gateway fetches at startup.
* The callback integration (`auth0_callback`) exchanges the authorization code for tokens at the edge, so your backend never sees the authorization code or client secret.
* The login redirect integration sends users to Auth0's `/authorize` endpoint with the correct parameters. The gateway constructs the redirect URL from the authorizer config.
* Refresh token and userinfo routes let you centralize all Auth0 API interactions behind the gateway, giving clients a single domain for auth operations.
* All Auth0 secrets (client\_secret, domain) should use `$secrets.*` or `$env.*` placeholders so they are resolved from Cloudflare environment variables at startup.

## Repo-grounded example

```json
{
  "authorizer": {
    "type": "auth0",
    "domain": "$env.AUTH0_DOMAIN",
    "client_id": "$env.AUTH0_CLIENT_ID",
    "client_secret": "$secrets.AUTH0_CLIENT_SECRET",
    "redirect_uri": "https://api.example.com/api/v1/auth0/callback",
    "callback_uri": "https://app.example.com/auth/callback",
    "jwks_uri": "https://tenant.us.auth0.com/.well-known/jwks.json",
    "scope": "openid profile email"
  },
  "paths": [
    {
      "method": "GET",
      "path": "/api/v1/auth0/callback",
      "integration": { "type": "auth0_callback" }
    }
  ]
}
```

This snippet shows the Auth0 authorizer config. When any Auth0 operation fails (callback exchange, token refresh, userinfo fetch), the gateway returns a JSON error with the Auth0 error description, the HTTP status from Auth0, and additional context about which operation failed.

## Troubleshooting

* If the callback route returns a 500, confirm that `redirect_uri` in your config exactly matches the callback URL registered in your Auth0 application settings (including scheme and path).
* If JWKS validation fails, check that the `jwks_uri` is reachable from the Cloudflare edge and returns a valid JWKS JSON document. Test it with `curl` from your local machine first.
* If the login redirect goes to the wrong Auth0 tenant, verify that `domain` in the authorizer block points to your correct Auth0 tenant (e.g., `your-tenant.us.auth0.com`).
* If refresh token exchange returns an error, confirm that the Auth0 application has "Refresh Token Rotation" enabled and that the `offline_access` scope is included.

## Related docs

* [auth0](/configuration/auth0)
* [authorizer](/configuration/authorizer)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Supabase

Protect routes with Supabase-issued tokens when your app already uses Supabase Auth as the identity provider. The gateway validates Supabase JWTs using the

Protect routes with Supabase-issued tokens when your app already uses Supabase Auth as the identity provider. The gateway validates Supabase JWTs using the project JWT secret, checking issuer and audience claims. Use this when you want edge-level auth without running Supabase client libraries in your backend.

**Last reviewed:** 2026-03-06

## When to use this

Use the Supabase integration guides when your application uses Supabase Auth for identity and you want passwordless (OTP) authentication flows managed at the gateway edge. The gateway handles sending OTP codes and verifying them, so your backend only sees authenticated requests.

## Key concepts

* The Supabase authorizer validates JWTs issued by Supabase Auth using the project's JWT secret. Configure `jwt_secret`, `issuer`, and `audience` in the authorizer block.
* The `supabase_passwordless_auth` integration sends OTP codes via email or phone through Supabase's GoTrue API. The gateway constructs the request from the client payload and Supabase environment variables.
* The `supabase_passwordless_verify` integration verifies OTP codes and returns Supabase session tokens. The client sends the OTP code and the gateway validates it against Supabase.
* Supabase requires specific environment variables: `SUPABASE_URL`, `SUPABASE_ANON_KEY`, and `SUPABASE_JWT_SECRET`. All three must be set before any Supabase integration works.
* If Supabase is configured to send magic links instead of numeric OTP codes, the verify flow will not work. This is controlled in the Supabase dashboard under Auth settings.

## Repo-grounded example

```json
{
  "authorizer": {
    "type": "supabase",
    "jwt_secret": "$env.SUPABASE_JWT_SECRET",
    "issuer": "https://project.supabase.co/auth/v1",
    "audience": "authenticated"
  },
  "paths": [
    {
      "method": "POST",
      "path": "/api/v1/supabase/auth",
      "integration": { "type": "supabase_passwordless_auth" }
    },
    {
      "method": "POST",
      "path": "/api/v1/supabase/verify",
      "integration": { "type": "supabase_passwordless_verify" }
    }
  ]
}
```

This snippet configures the Supabase authorizer with `jwt_secret`, `issuer`, and `audience`. Any path with `auth: true` will require a valid Supabase-issued JWT in the Authorization header. The gateway checks the token signature, expiry, issuer, and audience before forwarding the request.

## Troubleshooting

* If OTP sending fails with a 400 error, verify that `SUPABASE_URL` and `SUPABASE_ANON_KEY` are set correctly and that the Supabase project has email or phone auth enabled.
* If OTP verification returns "invalid token", confirm that Supabase is configured to send numeric OTP codes, not magic links -- check the Auth settings in your Supabase dashboard.
* If JWT validation fails on protected routes, confirm that `SUPABASE_JWT_SECRET` matches the JWT secret shown in your Supabase project settings (Settings > API > JWT Secret).
* If you receive a "missing email or phone" error, ensure the client request body includes either an `email` or `phone` field in the JSON payload sent to the auth endpoint.

## Related docs

* [supabase otp](/configuration/supabase-otp)
* [authorizer](/configuration/authorizer)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Supabase Email OTP

Use the email OTP integration when you want passwordless email auth behind one edge endpoint. The gateway sends a POST request to Supabase's GoTrue API with the

Use the email OTP integration when you want passwordless email auth behind one edge endpoint. The gateway sends a POST request to Supabase's GoTrue API with the user's email address, triggering an OTP code delivery. The client then submits the OTP code to the verify endpoint to complete login.

**Last reviewed:** 2026-03-06

## When to use this

Use the Supabase integration guides when your application uses Supabase Auth for identity and you want passwordless (OTP) authentication flows managed at the gateway edge. The gateway handles sending OTP codes and verifying them, so your backend only sees authenticated requests.

## Key concepts

* The Supabase authorizer validates JWTs issued by Supabase Auth using the project's JWT secret. Configure `jwt_secret`, `issuer`, and `audience` in the authorizer block.
* The `supabase_passwordless_auth` integration sends OTP codes via email or phone through Supabase's GoTrue API. The gateway constructs the request from the client payload and Supabase environment variables.
* The `supabase_passwordless_verify` integration verifies OTP codes and returns Supabase session tokens. The client sends the OTP code and the gateway validates it against Supabase.
* Supabase requires specific environment variables: `SUPABASE_URL`, `SUPABASE_ANON_KEY`, and `SUPABASE_JWT_SECRET`. All three must be set before any Supabase integration works.
* If Supabase is configured to send magic links instead of numeric OTP codes, the verify flow will not work. This is controlled in the Supabase dashboard under Auth settings.

## Repo-grounded example

```json
{
  "authorizer": {
    "type": "supabase",
    "jwt_secret": "$env.SUPABASE_JWT_SECRET",
    "issuer": "https://project.supabase.co/auth/v1",
    "audience": "authenticated"
  },
  "paths": [
    {
      "method": "POST",
      "path": "/api/v1/supabase/auth",
      "integration": { "type": "supabase_passwordless_auth" }
    },
    {
      "method": "POST",
      "path": "/api/v1/supabase/verify",
      "integration": { "type": "supabase_passwordless_verify" }
    }
  ]
}
```

This snippet includes the `supabase_passwordless_auth` integration path. When a client POSTs an email address to this endpoint, the gateway calls Supabase's GoTrue API to send an OTP code. The `supabase_passwordless_verify` path handles the subsequent code verification.

## Troubleshooting

* If OTP sending fails with a 400 error, verify that `SUPABASE_URL` and `SUPABASE_ANON_KEY` are set correctly and that the Supabase project has email or phone auth enabled.
* If OTP verification returns "invalid token", confirm that Supabase is configured to send numeric OTP codes, not magic links -- check the Auth settings in your Supabase dashboard.
* If JWT validation fails on protected routes, confirm that `SUPABASE_JWT_SECRET` matches the JWT secret shown in your Supabase project settings (Settings > API > JWT Secret).
* If you receive a "missing email or phone" error, ensure the client request body includes either an `email` or `phone` field in the JSON payload sent to the auth endpoint.

## Related docs

* [supabase otp](/configuration/supabase-otp)
* [authorizer](/configuration/authorizer)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Supabase Phone OTP

Use the phone OTP integration when your product authenticates users by SMS. The flow is identical to email OTP, but the client sends a phone number instead of

Use the phone OTP integration when your product authenticates users by SMS. The flow is identical to email OTP, but the client sends a phone number instead of an email address. Make sure your Supabase project has phone auth enabled and an SMS provider configured in the dashboard.

**Last reviewed:** 2026-03-06

## When to use this

Use the Supabase integration guides when your application uses Supabase Auth for identity and you want passwordless (OTP) authentication flows managed at the gateway edge. The gateway handles sending OTP codes and verifying them, so your backend only sees authenticated requests.

## Key concepts

* The Supabase authorizer validates JWTs issued by Supabase Auth using the project's JWT secret. Configure `jwt_secret`, `issuer`, and `audience` in the authorizer block.
* The `supabase_passwordless_auth` integration sends OTP codes via email or phone through Supabase's GoTrue API. The gateway constructs the request from the client payload and Supabase environment variables.
* The `supabase_passwordless_verify` integration verifies OTP codes and returns Supabase session tokens. The client sends the OTP code and the gateway validates it against Supabase.
* Supabase requires specific environment variables: `SUPABASE_URL`, `SUPABASE_ANON_KEY`, and `SUPABASE_JWT_SECRET`. All three must be set before any Supabase integration works.
* If Supabase is configured to send magic links instead of numeric OTP codes, the verify flow will not work. This is controlled in the Supabase dashboard under Auth settings.

## Repo-grounded example

```json
{
  "authorizer": {
    "type": "supabase",
    "jwt_secret": "$env.SUPABASE_JWT_SECRET",
    "issuer": "https://project.supabase.co/auth/v1",
    "audience": "authenticated"
  },
  "paths": [
    {
      "method": "POST",
      "path": "/api/v1/supabase/auth",
      "integration": { "type": "supabase_passwordless_auth" }
    },
    {
      "method": "POST",
      "path": "/api/v1/supabase/verify",
      "integration": { "type": "supabase_passwordless_verify" }
    }
  ]
}
```

This snippet uses the same `supabase_passwordless_auth` integration as email OTP. The gateway determines whether to send an email or SMS based on the client request body -- include a `phone` field instead of `email` to trigger SMS OTP delivery.

## Troubleshooting

* If OTP sending fails with a 400 error, verify that `SUPABASE_URL` and `SUPABASE_ANON_KEY` are set correctly and that the Supabase project has email or phone auth enabled.
* If OTP verification returns "invalid token", confirm that Supabase is configured to send numeric OTP codes, not magic links -- check the Auth settings in your Supabase dashboard.
* If JWT validation fails on protected routes, confirm that `SUPABASE_JWT_SECRET` matches the JWT secret shown in your Supabase project settings (Settings > API > JWT Secret).
* If you receive a "missing email or phone" error, ensure the client request body includes either an `email` or `phone` field in the JSON payload sent to the auth endpoint.

## Related docs

* [supabase otp](/configuration/supabase-otp)
* [authorizer](/configuration/authorizer)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Supabase Verify OTP

Verify OTP codes through the gateway so the client only talks to one auth surface. The client sends the OTP code and the email or phone number to the verify

Verify OTP codes through the gateway so the client only talks to one auth surface. The client sends the OTP code and the email or phone number to the verify endpoint. The gateway forwards this to Supabase's GoTrue API and returns the session tokens if verification succeeds.

**Last reviewed:** 2026-03-06

## When to use this

Use the Supabase integration guides when your application uses Supabase Auth for identity and you want passwordless (OTP) authentication flows managed at the gateway edge. The gateway handles sending OTP codes and verifying them, so your backend only sees authenticated requests.

## Key concepts

* The Supabase authorizer validates JWTs issued by Supabase Auth using the project's JWT secret. Configure `jwt_secret`, `issuer`, and `audience` in the authorizer block.
* The `supabase_passwordless_auth` integration sends OTP codes via email or phone through Supabase's GoTrue API. The gateway constructs the request from the client payload and Supabase environment variables.
* The `supabase_passwordless_verify` integration verifies OTP codes and returns Supabase session tokens. The client sends the OTP code and the gateway validates it against Supabase.
* Supabase requires specific environment variables: `SUPABASE_URL`, `SUPABASE_ANON_KEY`, and `SUPABASE_JWT_SECRET`. All three must be set before any Supabase integration works.
* If Supabase is configured to send magic links instead of numeric OTP codes, the verify flow will not work. This is controlled in the Supabase dashboard under Auth settings.

## Repo-grounded example

```json
{
  "authorizer": {
    "type": "supabase",
    "jwt_secret": "$env.SUPABASE_JWT_SECRET",
    "issuer": "https://project.supabase.co/auth/v1",
    "audience": "authenticated"
  },
  "paths": [
    {
      "method": "POST",
      "path": "/api/v1/supabase/auth",
      "integration": { "type": "supabase_passwordless_auth" }
    },
    {
      "method": "POST",
      "path": "/api/v1/supabase/verify",
      "integration": { "type": "supabase_passwordless_verify" }
    }
  ]
}
```

This snippet includes the `supabase_passwordless_verify` integration path. The client POSTs the OTP code along with the email or phone used during the auth step. The gateway calls Supabase's verify endpoint and returns the access and refresh tokens on success.

## Troubleshooting

* If OTP sending fails with a 400 error, verify that `SUPABASE_URL` and `SUPABASE_ANON_KEY` are set correctly and that the Supabase project has email or phone auth enabled.
* If OTP verification returns "invalid token", confirm that Supabase is configured to send numeric OTP codes, not magic links -- check the Auth settings in your Supabase dashboard.
* If JWT validation fails on protected routes, confirm that `SUPABASE_JWT_SECRET` matches the JWT secret shown in your Supabase project settings (Settings > API > JWT Secret).
* If you receive a "missing email or phone" error, ensure the client request body includes either an `email` or `phone` field in the JSON payload sent to the auth endpoint.

## Related docs

* [supabase otp](/configuration/supabase-otp)
* [authorizer](/configuration/authorizer)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Supabase Alternative Email Auth Path

Use the alternative email path only when the default OTP flow does not match your project behavior. Some Supabase configurations require a different GoTrue

Use the alternative email path only when the default OTP flow does not match your project behavior. Some Supabase configurations require a different GoTrue endpoint or request format for email authentication. This page documents the alternative path and when it applies.

**Last reviewed:** 2026-03-06

## When to use this

Use the Supabase integration guides when your application uses Supabase Auth for identity and you want passwordless (OTP) authentication flows managed at the gateway edge. The gateway handles sending OTP codes and verifying them, so your backend only sees authenticated requests.

## Key concepts

* The Supabase authorizer validates JWTs issued by Supabase Auth using the project's JWT secret. Configure `jwt_secret`, `issuer`, and `audience` in the authorizer block.
* The `supabase_passwordless_auth` integration sends OTP codes via email or phone through Supabase's GoTrue API. The gateway constructs the request from the client payload and Supabase environment variables.
* The `supabase_passwordless_verify` integration verifies OTP codes and returns Supabase session tokens. The client sends the OTP code and the gateway validates it against Supabase.
* Supabase requires specific environment variables: `SUPABASE_URL`, `SUPABASE_ANON_KEY`, and `SUPABASE_JWT_SECRET`. All three must be set before any Supabase integration works.
* If Supabase is configured to send magic links instead of numeric OTP codes, the verify flow will not work. This is controlled in the Supabase dashboard under Auth settings.

## Repo-grounded example

```json
{
  "authorizer": {
    "type": "supabase",
    "jwt_secret": "$env.SUPABASE_JWT_SECRET",
    "issuer": "https://project.supabase.co/auth/v1",
    "audience": "authenticated"
  },
  "paths": [
    {
      "method": "POST",
      "path": "/api/v1/supabase/auth",
      "integration": { "type": "supabase_passwordless_auth" }
    },
    {
      "method": "POST",
      "path": "/api/v1/supabase/verify",
      "integration": { "type": "supabase_passwordless_verify" }
    }
  ]
}
```

This snippet uses the standard Supabase integration paths. The alternative email auth path changes the GoTrue endpoint the gateway calls. Consult this page if the default `supabase_passwordless_auth` integration returns errors specific to your Supabase project configuration.

## Troubleshooting

* If OTP sending fails with a 400 error, verify that `SUPABASE_URL` and `SUPABASE_ANON_KEY` are set correctly and that the Supabase project has email or phone auth enabled.
* If OTP verification returns "invalid token", confirm that Supabase is configured to send numeric OTP codes, not magic links -- check the Auth settings in your Supabase dashboard.
* If JWT validation fails on protected routes, confirm that `SUPABASE_JWT_SECRET` matches the JWT secret shown in your Supabase project settings (Settings > API > JWT Secret).
* If you receive a "missing email or phone" error, ensure the client request body includes either an `email` or `phone` field in the JSON payload sent to the auth endpoint.

## Related docs

* [supabase otp](/configuration/supabase-otp)
* [authorizer](/configuration/authorizer)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Supabase Required Environment Variables

Set the required Supabase environment variables before you test any passwordless auth route. The gateway needs \`SUPABASE\_URL\`, \`SUPABASE\_ANON\_KEY\`, and

Set the required Supabase environment variables before you test any passwordless auth route. The gateway needs `SUPABASE_URL`, `SUPABASE_ANON_KEY`, and `SUPABASE_JWT_SECRET` to communicate with your Supabase project. This page lists each variable, where to find it, and what happens if it is missing.

**Last reviewed:** 2026-03-06

## When to use this

Use the Supabase integration guides when your application uses Supabase Auth for identity and you want passwordless (OTP) authentication flows managed at the gateway edge. The gateway handles sending OTP codes and verifying them, so your backend only sees authenticated requests.

## Key concepts

* The Supabase authorizer validates JWTs issued by Supabase Auth using the project's JWT secret. Configure `jwt_secret`, `issuer`, and `audience` in the authorizer block.
* The `supabase_passwordless_auth` integration sends OTP codes via email or phone through Supabase's GoTrue API. The gateway constructs the request from the client payload and Supabase environment variables.
* The `supabase_passwordless_verify` integration verifies OTP codes and returns Supabase session tokens. The client sends the OTP code and the gateway validates it against Supabase.
* Supabase requires specific environment variables: `SUPABASE_URL`, `SUPABASE_ANON_KEY`, and `SUPABASE_JWT_SECRET`. All three must be set before any Supabase integration works.
* If Supabase is configured to send magic links instead of numeric OTP codes, the verify flow will not work. This is controlled in the Supabase dashboard under Auth settings.

## Repo-grounded example

```json
{
  "authorizer": {
    "type": "supabase",
    "jwt_secret": "$env.SUPABASE_JWT_SECRET",
    "issuer": "https://project.supabase.co/auth/v1",
    "audience": "authenticated"
  },
  "paths": [
    {
      "method": "POST",
      "path": "/api/v1/supabase/auth",
      "integration": { "type": "supabase_passwordless_auth" }
    },
    {
      "method": "POST",
      "path": "/api/v1/supabase/verify",
      "integration": { "type": "supabase_passwordless_verify" }
    }
  ]
}
```

This snippet references `$env.SUPABASE_JWT_SECRET` in the authorizer. In addition to the JWT secret, you must set `SUPABASE_URL` (your project URL) and `SUPABASE_ANON_KEY` (the public anon key) as Cloudflare environment variables or in your `.dev.vars` file for local development.

## Troubleshooting

* If OTP sending fails with a 400 error, verify that `SUPABASE_URL` and `SUPABASE_ANON_KEY` are set correctly and that the Supabase project has email or phone auth enabled.
* If OTP verification returns "invalid token", confirm that Supabase is configured to send numeric OTP codes, not magic links -- check the Auth settings in your Supabase dashboard.
* If JWT validation fails on protected routes, confirm that `SUPABASE_JWT_SECRET` matches the JWT secret shown in your Supabase project settings (Settings > API > JWT Secret).
* If you receive a "missing email or phone" error, ensure the client request body includes either an `email` or `phone` field in the JSON payload sent to the auth endpoint.

## Related docs

* [supabase otp](/configuration/supabase-otp)
* [authorizer](/configuration/authorizer)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Supabase Troubleshooting: Magic Link vs OTP

Debug the common mismatch where Supabase sends magic links instead of numeric OTP codes. The gateway's verify integration expects a numeric code, but Supabase

Debug the common mismatch where Supabase sends magic links instead of numeric OTP codes. The gateway's verify integration expects a numeric code, but Supabase defaults to magic links for email auth in some configurations. This page explains how to change the Supabase setting and verify the fix.

**Last reviewed:** 2026-03-06

## When to use this

Use the Supabase integration guides when your application uses Supabase Auth for identity and you want passwordless (OTP) authentication flows managed at the gateway edge. The gateway handles sending OTP codes and verifying them, so your backend only sees authenticated requests.

## Key concepts

* The Supabase authorizer validates JWTs issued by Supabase Auth using the project's JWT secret. Configure `jwt_secret`, `issuer`, and `audience` in the authorizer block.
* The `supabase_passwordless_auth` integration sends OTP codes via email or phone through Supabase's GoTrue API. The gateway constructs the request from the client payload and Supabase environment variables.
* The `supabase_passwordless_verify` integration verifies OTP codes and returns Supabase session tokens. The client sends the OTP code and the gateway validates it against Supabase.
* Supabase requires specific environment variables: `SUPABASE_URL`, `SUPABASE_ANON_KEY`, and `SUPABASE_JWT_SECRET`. All three must be set before any Supabase integration works.
* If Supabase is configured to send magic links instead of numeric OTP codes, the verify flow will not work. This is controlled in the Supabase dashboard under Auth settings.

## Repo-grounded example

```json
{
  "authorizer": {
    "type": "supabase",
    "jwt_secret": "$env.SUPABASE_JWT_SECRET",
    "issuer": "https://project.supabase.co/auth/v1",
    "audience": "authenticated"
  },
  "paths": [
    {
      "method": "POST",
      "path": "/api/v1/supabase/auth",
      "integration": { "type": "supabase_passwordless_auth" }
    },
    {
      "method": "POST",
      "path": "/api/v1/supabase/verify",
      "integration": { "type": "supabase_passwordless_verify" }
    }
  ]
}
```

This snippet sets up the standard Supabase OTP flow. If Supabase sends magic links instead of numeric codes, the verify endpoint will fail with an "invalid token" error. To fix this, go to your Supabase dashboard > Auth > Email and disable the magic link option, then re-test the OTP flow.

## Troubleshooting

* If OTP sending fails with a 400 error, verify that `SUPABASE_URL` and `SUPABASE_ANON_KEY` are set correctly and that the Supabase project has email or phone auth enabled.
* If OTP verification returns "invalid token", confirm that Supabase is configured to send numeric OTP codes, not magic links -- check the Auth settings in your Supabase dashboard.
* If JWT validation fails on protected routes, confirm that `SUPABASE_JWT_SECRET` matches the JWT secret shown in your Supabase project settings (Settings > API > JWT Secret).
* If you receive a "missing email or phone" error, ensure the client request body includes either an `email` or `phone` field in the JSON payload sent to the auth endpoint.

## Related docs

* [supabase otp](/configuration/supabase-otp)
* [authorizer](/configuration/authorizer)


# Deployment And Troubleshooting

Use Wrangler for repeatable deployment of the worker, service modules, and bindings configuration. This guide covers the \`wrangler.toml\` fields relevant to the

Use Wrangler for repeatable deployment of the worker, service modules, and bindings configuration. This guide covers the `wrangler.toml` fields relevant to the gateway, the `wrangler deploy` command, and post-deploy verification steps. Start here if you are deploying the gateway for the first time.

**Last reviewed:** 2026-03-06

## When to use this

Use the deployment and troubleshooting guides when you are deploying the gateway to Cloudflare, setting up CI/CD, running tests, or diagnosing production issues. These guides cover the operational side of the gateway lifecycle from local development to production debugging.

## Key concepts

* The gateway deploys as a standard Cloudflare Worker using `wrangler deploy`. The `wrangler.toml` file defines the worker name, entrypoint, compatibility settings, and binding declarations.
* GitHub Actions can automate deployments, running config validation, tests, and docs checks before publishing the worker. The workflow uses the same `wrangler deploy` command.
* The gateway repo includes Vitest unit tests and optional E2E tests using `unstable_dev`. Run unit tests with `npm test` and E2E tests with the `RUN_LOCAL_WORKER_E2E=true` flag.
* When debugging upstream failures, isolate whether the issue is in routing (wrong path matched), auth (token rejected), or the upstream itself (backend error). Check `wrangler tail` logs for the gateway's perspective.

## Repo-grounded example

```toml
name = "serverless-api-gateway"
main = "src/index.js"
compatibility_date = "2025-01-01"
compatibility_flags = ["nodejs_compat"]
find_additional_modules = true
rules = [{ type = "ESModule", globs = ["services/*.js"] }]
```

This snippet shows a `wrangler.toml` with the worker name, entrypoint, compatibility date, and module rules. The `compatibility_flags` array includes `nodejs_compat` for Node.js API support, and `rules` tells Wrangler to bundle JavaScript files from the `services/` directory as ES modules.

## Troubleshooting

* If `wrangler deploy` fails with "missing binding", check your `wrangler.toml` for typos in binding names and verify that all referenced KV namespaces, service bindings, and secrets exist in your Cloudflare account.
* If GitHub Actions deploys succeed but the worker returns 500, check whether environment variables and secrets are set in the Cloudflare dashboard -- they are not deployed by Wrangler and must be configured separately.
* If E2E tests fail with "unstable\_dev not found", make sure you are running a Wrangler version that supports `unstable_dev` and that `RUN_LOCAL_WORKER_E2E=true` is set in your environment.
* If routes work locally but not in production, compare the config source: local dev uses the file system, while production may use KV or `SAG_API_CONFIG_JSON`. Confirm the production config matches your local config.

## Related docs

* [wrangler](/deployment/wrangler)
* [github actions](/deployment/github-actions)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# GitHub Actions Deploy Guide

Automate deploys when you want config and docs checks to run before publishing the worker. This guide covers the GitHub Actions workflow structure, secrets

Automate deploys when you want config and docs checks to run before publishing the worker. This guide covers the GitHub Actions workflow structure, secrets configuration, and how to gate deploys on test results. Use this when you want every push to main to deploy automatically after validation passes.

**Last reviewed:** 2026-03-06

## When to use this

Use the deployment and troubleshooting guides when you are deploying the gateway to Cloudflare, setting up CI/CD, running tests, or diagnosing production issues. These guides cover the operational side of the gateway lifecycle from local development to production debugging.

## Key concepts

* The gateway deploys as a standard Cloudflare Worker using `wrangler deploy`. The `wrangler.toml` file defines the worker name, entrypoint, compatibility settings, and binding declarations.
* GitHub Actions can automate deployments, running config validation, tests, and docs checks before publishing the worker. The workflow uses the same `wrangler deploy` command.
* The gateway repo includes Vitest unit tests and optional E2E tests using `unstable_dev`. Run unit tests with `npm test` and E2E tests with the `RUN_LOCAL_WORKER_E2E=true` flag.
* When debugging upstream failures, isolate whether the issue is in routing (wrong path matched), auth (token rejected), or the upstream itself (backend error). Check `wrangler tail` logs for the gateway's perspective.

## Repo-grounded example

```toml
name = "serverless-api-gateway"
main = "src/index.js"
compatibility_date = "2025-01-01"
compatibility_flags = ["nodejs_compat"]
find_additional_modules = true
rules = [{ type = "ESModule", globs = ["services/*.js"] }]
```

This snippet shows the `wrangler.toml` that the GitHub Actions workflow deploys. In your workflow YAML, use the `cloudflare/wrangler-action` or run `npx wrangler deploy` directly, passing the Cloudflare API token as a secret.

## Troubleshooting

* If `wrangler deploy` fails with "missing binding", check your `wrangler.toml` for typos in binding names and verify that all referenced KV namespaces, service bindings, and secrets exist in your Cloudflare account.
* If GitHub Actions deploys succeed but the worker returns 500, check whether environment variables and secrets are set in the Cloudflare dashboard -- they are not deployed by Wrangler and must be configured separately.
* If E2E tests fail with "unstable\_dev not found", make sure you are running a Wrangler version that supports `unstable_dev` and that `RUN_LOCAL_WORKER_E2E=true` is set in your environment.
* If routes work locally but not in production, compare the config source: local dev uses the file system, while production may use KV or `SAG_API_CONFIG_JSON`. Confirm the production config matches your local config.

## Related docs

* [wrangler](/deployment/wrangler)
* [github actions](/deployment/github-actions)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Local Testing with Vitest

Use the existing unit and integration tests as the fastest confidence check for config and routing changes. The gateway repo uses Vitest for unit tests and

Use the existing unit and integration tests as the fastest confidence check for config and routing changes. The gateway repo uses Vitest for unit tests and optional coverage reporting. This page explains how to run the test suite, interpret results, and add tests for new route configurations.

**Last reviewed:** 2026-03-06

## When to use this

Use the deployment and troubleshooting guides when you are deploying the gateway to Cloudflare, setting up CI/CD, running tests, or diagnosing production issues. These guides cover the operational side of the gateway lifecycle from local development to production debugging.

## Key concepts

* The gateway deploys as a standard Cloudflare Worker using `wrangler deploy`. The `wrangler.toml` file defines the worker name, entrypoint, compatibility settings, and binding declarations.
* GitHub Actions can automate deployments, running config validation, tests, and docs checks before publishing the worker. The workflow uses the same `wrangler deploy` command.
* The gateway repo includes Vitest unit tests and optional E2E tests using `unstable_dev`. Run unit tests with `npm test` and E2E tests with the `RUN_LOCAL_WORKER_E2E=true` flag.
* When debugging upstream failures, isolate whether the issue is in routing (wrong path matched), auth (token rejected), or the upstream itself (backend error). Check `wrangler tail` logs for the gateway's perspective.

## Repo-grounded example

```bash
npm test
npm run test:coverage
RUN_LOCAL_WORKER_E2E=true npm run test:e2e
```

This snippet shows three test commands: `npm test` runs the Vitest unit suite, `npm run test:coverage` adds coverage reporting, and the E2E command runs worker-level tests. Start with `npm test` after any config change to catch schema or routing errors.

## Troubleshooting

* If `wrangler deploy` fails with "missing binding", check your `wrangler.toml` for typos in binding names and verify that all referenced KV namespaces, service bindings, and secrets exist in your Cloudflare account.
* If GitHub Actions deploys succeed but the worker returns 500, check whether environment variables and secrets are set in the Cloudflare dashboard -- they are not deployed by Wrangler and must be configured separately.
* If E2E tests fail with "unstable\_dev not found", make sure you are running a Wrangler version that supports `unstable_dev` and that `RUN_LOCAL_WORKER_E2E=true` is set in your environment.
* If routes work locally but not in production, compare the config source: local dev uses the file system, while production may use KV or `SAG_API_CONFIG_JSON`. Confirm the production config matches your local config.

## Related docs

* [wrangler](/deployment/wrangler)
* [github actions](/deployment/github-actions)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Local E2E with unstable\_dev

Run local worker E2E tests when you need real runtime behavior instead of only module-level assertions. The \`unstable\_dev\` API starts a local Wrangler dev

Run local worker E2E tests when you need real runtime behavior instead of only module-level assertions. The `unstable_dev` API starts a local Wrangler dev server and lets tests make real HTTP requests to the gateway. This catches issues that unit tests miss, like binding resolution and CORS header behavior.

**Last reviewed:** 2026-03-06

## When to use this

Use the deployment and troubleshooting guides when you are deploying the gateway to Cloudflare, setting up CI/CD, running tests, or diagnosing production issues. These guides cover the operational side of the gateway lifecycle from local development to production debugging.

## Key concepts

* The gateway deploys as a standard Cloudflare Worker using `wrangler deploy`. The `wrangler.toml` file defines the worker name, entrypoint, compatibility settings, and binding declarations.
* GitHub Actions can automate deployments, running config validation, tests, and docs checks before publishing the worker. The workflow uses the same `wrangler deploy` command.
* The gateway repo includes Vitest unit tests and optional E2E tests using `unstable_dev`. Run unit tests with `npm test` and E2E tests with the `RUN_LOCAL_WORKER_E2E=true` flag.
* When debugging upstream failures, isolate whether the issue is in routing (wrong path matched), auth (token rejected), or the upstream itself (backend error). Check `wrangler tail` logs for the gateway's perspective.

## Repo-grounded example

```bash
npm test
npm run test:coverage
RUN_LOCAL_WORKER_E2E=true npm run test:e2e
```

This snippet includes the `RUN_LOCAL_WORKER_E2E=true` environment variable that enables E2E tests. The test suite uses Wrangler's `unstable_dev` to start a local worker instance, then sends HTTP requests and asserts on response status, headers, and body.

## Troubleshooting

* If `wrangler deploy` fails with "missing binding", check your `wrangler.toml` for typos in binding names and verify that all referenced KV namespaces, service bindings, and secrets exist in your Cloudflare account.
* If GitHub Actions deploys succeed but the worker returns 500, check whether environment variables and secrets are set in the Cloudflare dashboard -- they are not deployed by Wrangler and must be configured separately.
* If E2E tests fail with "unstable\_dev not found", make sure you are running a Wrangler version that supports `unstable_dev` and that `RUN_LOCAL_WORKER_E2E=true` is set in your environment.
* If routes work locally but not in production, compare the config source: local dev uses the file system, while production may use KV or `SAG_API_CONFIG_JSON`. Confirm the production config matches your local config.

## Related docs

* [wrangler](/deployment/wrangler)
* [github actions](/deployment/github-actions)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Docs Sync and Canonical Examples

Treat the checked-in config examples as the canonical source for both docs and automated checks. The gateway repo includes config examples that are used in both

Treat the checked-in config examples as the canonical source for both docs and automated checks. The gateway repo includes config examples that are used in both documentation and test fixtures. This page explains the sync process so documentation and tests always reference the same config shapes.

**Last reviewed:** 2026-03-06

## When to use this

Use the deployment and troubleshooting guides when you are deploying the gateway to Cloudflare, setting up CI/CD, running tests, or diagnosing production issues. These guides cover the operational side of the gateway lifecycle from local development to production debugging.

## Key concepts

* The gateway deploys as a standard Cloudflare Worker using `wrangler deploy`. The `wrangler.toml` file defines the worker name, entrypoint, compatibility settings, and binding declarations.
* GitHub Actions can automate deployments, running config validation, tests, and docs checks before publishing the worker. The workflow uses the same `wrangler deploy` command.
* The gateway repo includes Vitest unit tests and optional E2E tests using `unstable_dev`. Run unit tests with `npm test` and E2E tests with the `RUN_LOCAL_WORKER_E2E=true` flag.
* When debugging upstream failures, isolate whether the issue is in routing (wrong path matched), auth (token rejected), or the upstream itself (backend error). Check `wrangler tail` logs for the gateway's perspective.

## Repo-grounded example

```json
{
  "$schema": "./api-config.schema.json",
  "title": "Minimal Gateway",
  "cors": {
    "allow_origins": ["https://app.example.com"],
    "allow_methods": ["GET", "POST", "OPTIONS"],
    "allow_headers": ["Content-Type", "Authorization"],
    "expose_headers": ["X-Request-Id"],
    "allow_credentials": true,
    "max_age": 300
  },
  "paths": [
    {
      "method": "GET",
      "path": "/health",
      "response": { "status": "ok" }
    }
  ]
}
```

This snippet is one of the canonical config examples used in both docs and tests. When you change a config example, the docs generation script and test fixtures should be updated together to keep documentation accurate and tests passing.

## Troubleshooting

* If `wrangler deploy` fails with "missing binding", check your `wrangler.toml` for typos in binding names and verify that all referenced KV namespaces, service bindings, and secrets exist in your Cloudflare account.
* If GitHub Actions deploys succeed but the worker returns 500, check whether environment variables and secrets are set in the Cloudflare dashboard -- they are not deployed by Wrangler and must be configured separately.
* If E2E tests fail with "unstable\_dev not found", make sure you are running a Wrangler version that supports `unstable_dev` and that `RUN_LOCAL_WORKER_E2E=true` is set in your environment.
* If routes work locally but not in production, compare the config source: local dev uses the file system, while production may use KV or `SAG_API_CONFIG_JSON`. Confirm the production config matches your local config.

## Related docs

* [wrangler](/deployment/wrangler)
* [github actions](/deployment/github-actions)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Debugging Upstream Failures

Use this guide when proxied routes fail and you need to isolate routing, auth, and upstream behavior. Start by checking whether the gateway matched the right

Use this guide when proxied routes fail and you need to isolate routing, auth, and upstream behavior. Start by checking whether the gateway matched the right route, then whether auth passed, then whether the upstream responded. This page provides a step-by-step process for narrowing down the failure layer.

**Last reviewed:** 2026-03-06

## When to use this

Use the deployment and troubleshooting guides when you are deploying the gateway to Cloudflare, setting up CI/CD, running tests, or diagnosing production issues. These guides cover the operational side of the gateway lifecycle from local development to production debugging.

## Key concepts

* The gateway deploys as a standard Cloudflare Worker using `wrangler deploy`. The `wrangler.toml` file defines the worker name, entrypoint, compatibility settings, and binding declarations.
* GitHub Actions can automate deployments, running config validation, tests, and docs checks before publishing the worker. The workflow uses the same `wrangler deploy` command.
* The gateway repo includes Vitest unit tests and optional E2E tests using `unstable_dev`. Run unit tests with `npm test` and E2E tests with the `RUN_LOCAL_WORKER_E2E=true` flag.
* When debugging upstream failures, isolate whether the issue is in routing (wrong path matched), auth (token rejected), or the upstream itself (backend error). Check `wrangler tail` logs for the gateway's perspective.

## Repo-grounded example

```json
{
  "servers": [
    { "alias": "upstream", "url": "https://api.example.com/base" }
  ],
  "paths": [
    {
      "method": "GET",
      "path": "/proxy/{.+}",
      "integration": {
        "type": "http_proxy",
        "server": "upstream"
      }
    }
  ]
}
```

This snippet defines an HTTP proxy route. When this route fails, check the gateway logs (`wrangler tail`) to see if the request matched this path, whether auth was evaluated, and what response the upstream returned. The logs show each step in the request lifecycle.

## Troubleshooting

* If `wrangler deploy` fails with "missing binding", check your `wrangler.toml` for typos in binding names and verify that all referenced KV namespaces, service bindings, and secrets exist in your Cloudflare account.
* If GitHub Actions deploys succeed but the worker returns 500, check whether environment variables and secrets are set in the Cloudflare dashboard -- they are not deployed by Wrangler and must be configured separately.
* If E2E tests fail with "unstable\_dev not found", make sure you are running a Wrangler version that supports `unstable_dev` and that `RUN_LOCAL_WORKER_E2E=true` is set in your environment.
* If routes work locally but not in production, compare the config source: local dev uses the file system, while production may use KV or `SAG_API_CONFIG_JSON`. Confirm the production config matches your local config.

## Related docs

* [wrangler](/deployment/wrangler)
* [github actions](/deployment/github-actions)
* [gateway troubleshooting matrix](/troubleshooting/wrangler-deploy-guide/gateway-troubleshooting-matrix)


# Gateway Troubleshooting Matrix

Use the matrix to map common symptoms to the fastest next diagnostic step. This page lists symptoms like "route returns 404", "auth returns 401", "upstream

Use the matrix to map common symptoms to the fastest next diagnostic step. This page lists symptoms like "route returns 404", "auth returns 401", "upstream returns 502", and "CORS error in browser" alongside the most likely cause and the command or config check to run first.

**Last reviewed:** 2026-03-06

## When to use this

Use the deployment and troubleshooting guides when you are deploying the gateway to Cloudflare, setting up CI/CD, running tests, or diagnosing production issues. These guides cover the operational side of the gateway lifecycle from local development to production debugging.

## Key concepts

* The gateway deploys as a standard Cloudflare Worker using `wrangler deploy`. The `wrangler.toml` file defines the worker name, entrypoint, compatibility settings, and binding declarations.
* GitHub Actions can automate deployments, running config validation, tests, and docs checks before publishing the worker. The workflow uses the same `wrangler deploy` command.
* The gateway repo includes Vitest unit tests and optional E2E tests using `unstable_dev`. Run unit tests with `npm test` and E2E tests with the `RUN_LOCAL_WORKER_E2E=true` flag.
* When debugging upstream failures, isolate whether the issue is in routing (wrong path matched), auth (token rejected), or the upstream itself (backend error). Check `wrangler tail` logs for the gateway's perspective.

## Repo-grounded example

```bash
npm test
npm run test:coverage
RUN_LOCAL_WORKER_E2E=true npm run test:e2e
```

This snippet shows the test commands available for diagnosing gateway issues. When a symptom appears in the matrix, the recommended action often starts with running the test suite to confirm whether the issue is in config, routing logic, or the upstream.

## Troubleshooting

* If `wrangler deploy` fails with "missing binding", check your `wrangler.toml` for typos in binding names and verify that all referenced KV namespaces, service bindings, and secrets exist in your Cloudflare account.
* If GitHub Actions deploys succeed but the worker returns 500, check whether environment variables and secrets are set in the Cloudflare dashboard -- they are not deployed by Wrangler and must be configured separately.
* If E2E tests fail with "unstable\_dev not found", make sure you are running a Wrangler version that supports `unstable_dev` and that `RUN_LOCAL_WORKER_E2E=true` is set in your environment.
* If routes work locally but not in production, compare the config source: local dev uses the file system, while production may use KV or `SAG_API_CONFIG_JSON`. Confirm the production config matches your local config.

## Related docs

* [wrangler](/deployment/wrangler)
* [github actions](/deployment/github-actions)


# A

Glossary terms starting with the letter A, covering APIs, authentication, and authorization.

This section contains glossary terms beginning with A. Topics include core API concepts, authentication and authorization mechanisms, and asynchronous operations.

* API (Application Programming Interface)
* API Endpoint
* API Gateway
* API Key
* API Rate Limiting
* Asynchronous Operation
* Authentication
* Authorization


# API (Application Programming Interface)

A set of rules and definitions that allows software applications to communicate with each other, enabling the exchange of data and functionality.

An API (Application Programming Interface) is a set of defined rules, protocols, and tools that allows different software applications to communicate with each other. APIs specify how software components should interact, abstracting away the underlying implementation and exposing only the objects or actions a developer needs.

APIs are fundamental to modern software architecture. They enable integration between disparate systems, allow third-party developers to build on top of existing platforms, and support the decomposition of monolithic applications into microservices. Common API styles include REST, GraphQL, and gRPC, each with different trade-offs around flexibility, performance, and ease of use.

In the context of API management, an API gateway sits in front of APIs to handle cross-cutting concerns such as authentication, rate limiting, request routing, and response transformation. This allows backend services to focus on business logic while the gateway enforces policies consistently across all exposed endpoints.


# API Endpoint

The point at which an API connects with the software program, allowing communication between systems.

An API endpoint is a specific URL or URI where an API receives requests. Each endpoint corresponds to a particular resource or operation that the API exposes. For example, `GET /api/users` might return a list of users, while `POST /api/users` creates a new user.

Endpoints are the touchpoints through which external clients interact with a backend service. They are defined by a combination of the HTTP method (GET, POST, PUT, DELETE, etc.) and the path. Well-designed endpoints follow consistent naming conventions and map logically to the underlying data model.

In API gateway architectures, endpoints are the primary unit of routing configuration. The gateway maps incoming requests to the correct backend service based on the endpoint path, method, and other criteria such as headers or query parameters. This makes endpoint management central to API governance, security enforcement, and traffic control.


# API Gateway

An API gateway is a server that acts as a single entry point for API requests, handling routing, authentication, and policy enforcement.

An API gateway is an infrastructure component that sits between clients and backend services, acting as a reverse proxy that receives all API requests, applies cross-cutting policies, and routes each request to the correct upstream service. Rather than exposing backend services directly to consumers, the gateway provides a unified interface that abstracts the internal architecture.

## Core responsibilities

A typical API gateway handles several concerns that would otherwise need to be implemented in every individual service:

* **Request routing**: Matching incoming requests to the correct backend service based on the URL path, HTTP method, headers, or other attributes.
* **Authentication and authorization**: Verifying the identity of callers using mechanisms such as API keys, JWT tokens, or OAuth flows, and enforcing access policies before the request reaches the backend.
* **Protocol translation**: Accepting requests in one format and converting them for backend services that may use a different protocol or data structure.
* **Traffic management**: Applying rate limiting, request throttling, and load balancing to protect backend services from being overwhelmed.
* **Observability**: Collecting logs, metrics, and traces at the gateway level to provide a centralized view of API traffic.
* **Response transformation**: Modifying responses before returning them to the client, such as filtering fields, adding headers, or changing formats.

## Why use an API gateway

Without a gateway, each backend service must independently handle authentication, CORS, logging, and other shared concerns. This leads to duplicated logic, inconsistent policy enforcement, and a larger attack surface. A gateway centralizes these responsibilities, making it easier to maintain consistent behavior across services and reducing the amount of boilerplate code in each backend.

For microservices architectures especially, a gateway simplifies the client experience. Clients call a single endpoint rather than tracking the addresses and protocols of many individual services.

## Serverless API Gateway

Serverless API Gateway is an open-source API gateway built on Cloudflare Workers. Because it runs at the edge on Cloudflare's network, it processes requests close to end users with low latency and without requiring you to provision or manage servers. Configuration is defined declaratively, covering path-based routing, JWT authorization, CORS policies, upstream server definitions, and variable mapping between requests and backends.

Being serverless, it follows a pay-per-request model and scales automatically with traffic. It supports routing to backend services on any cloud provider, making it a practical choice for multi-cloud or hybrid architectures.

## Related documentation

* [Configuration Overview](/configuration/overview) - How to configure gateway behavior
* [Authorizer Configuration](/configuration/authorizer) - Set up JWT authentication
* [Path Routing](/configuration/paths) - Define routing rules for API endpoints
* [Getting Started](/getting-started/introduction) - Quick start guide for deploying the gateway


# API Key

An API key is a unique identifier passed with API requests to authenticate the calling application and control access to services.

An API key is a string token that a client includes in API requests to identify itself to the server. API keys serve as a simple authentication mechanism, allowing the API provider to track which application or developer is making requests, enforce usage quotas, and control access to specific endpoints or functionality.

## How API keys work

When a developer registers with an API provider, they receive a unique API key. The client includes this key in each request, typically in one of three ways:

* **HTTP header**: Sent as a custom header such as `X-API-Key: abc123` or via the standard `Authorization` header.
* **Query parameter**: Appended to the URL, e.g., `?api_key=abc123`. This is simple but less secure because keys may appear in server logs, browser history, and referrer headers.
* **Request body**: Included as a field in the POST body. Less common and couples the key to the payload format.

The server validates the key against its records, identifies the caller, and decides whether to allow or deny the request based on the permissions associated with that key.

## API keys vs. other authentication methods

API keys identify the calling application, but they have limitations compared to other approaches:

* **API keys**: Simple to implement and suitable for identifying applications and enforcing rate limits. However, they provide coarse-grained access control and are difficult to revoke selectively if leaked.
* **JWT (JSON Web Tokens)**: Carry signed claims about the user's identity and permissions. They are self-contained, can expire, and support fine-grained authorization without a database lookup on every request.
* **OAuth 2.0**: A framework for delegated authorization, where a user grants an application limited access to their resources. More complex but appropriate for user-facing APIs where consent and scopes are important.
* **Mutual TLS**: Both client and server present certificates, providing strong identity verification at the transport layer. Primarily used in service-to-service communication.

In practice, many APIs combine API keys (for application identification and billing) with JWT or OAuth tokens (for user-level authentication and authorization).

## Securing API keys

API keys should be treated as credentials:

* Store them in environment variables or secret managers, never in source code or version control.
* Transmit them only over HTTPS to prevent interception.
* Rotate keys periodically and revoke compromised keys immediately.
* Restrict each key's permissions to the minimum required scope.
* Use separate keys for development, staging, and production environments.

## API keys and API gateways

An API gateway is a natural place to validate API keys because it processes every request before it reaches the backend. The gateway can check the key, enforce per-key rate limits, and reject unauthorized requests at the edge -- reducing load on backend services.

Serverless API Gateway supports JWT-based authorization through its authorizer configuration. For API key validation, teams can implement key checks in the backend services or use Cloudflare Workers custom logic alongside the gateway. The gateway's path configuration allows you to require authorization on specific endpoints while leaving others open, giving granular control over which routes need authentication.

## Related documentation

* [Authorizer Configuration](/configuration/authorizer) - Configure JWT-based authentication at the gateway
* [Path Routing](/configuration/paths) - Apply authorization selectively per route
* [Configuration Overview](/configuration/overview) - General gateway configuration reference


# API Rate Limiting

API rate limiting restricts the number of API requests a client can make within a time frame to protect services and ensure fair access.

API rate limiting is the practice of enforcing a maximum number of API requests that a client can make within a defined time period. It is a specific application of general rate limiting, tailored to the characteristics and requirements of API-based services. When the limit is exceeded, the API responds with an HTTP 429 status code and typically includes headers indicating when the client can retry.

## How API rate limiting works

An API rate limiter tracks request counts against defined quotas. The quota is usually expressed as a number of requests per time window (e.g., 1,000 requests per minute). The limiter identifies clients by one or more attributes:

* **API key**: Each registered API consumer has its own quota.
* **Authenticated user**: Limits are tied to the user identity extracted from a JWT or OAuth token.
* **IP address**: Used for unauthenticated endpoints or as a fallback when no API key is present.
* **Endpoint**: Different endpoints may have different limits based on their cost or sensitivity.

When a request arrives, the limiter checks the client's current count against the limit. If the count is within bounds, the request proceeds and the counter increments. If the limit is exceeded, the request is rejected.

## Standard response headers

Well-designed APIs communicate rate limit status through response headers:

* `X-RateLimit-Limit`: The maximum number of requests allowed in the current window.
* `X-RateLimit-Remaining`: How many requests the client can still make in the current window.
* `X-RateLimit-Reset`: The time (as a Unix timestamp or seconds) until the current window resets.
* `Retry-After`: Included with 429 responses to indicate how long the client should wait before retrying.

These headers let client applications implement backoff logic and avoid hammering the API when limits are reached.

## API rate limiting strategies

Different strategies suit different use cases:

* **Per-plan limits**: SaaS APIs commonly tie rate limits to subscription tiers. A free plan might allow 100 requests per minute, while an enterprise plan allows 10,000.
* **Per-endpoint limits**: Expensive operations (such as full-text search or report generation) get lower limits than lightweight reads.
* **Burst allowance**: Some implementations allow short bursts above the sustained rate, using a token bucket algorithm, as long as the average rate stays within bounds.
* **Graduated throttling**: Instead of hard rejection, the API may slow responses (add latency) as the client approaches its limit, providing a softer degradation.

## API rate limiting and API gateways

API gateways are the standard enforcement point for API rate limiting. Because the gateway processes every request before it reaches backend services, it can enforce limits consistently across all endpoints without requiring each backend to implement its own logic. The gateway can also differentiate between clients based on API keys, JWT claims, or IP addresses.

Serverless API Gateway does not include built-in API rate limiting at this time. Teams requiring API-level rate limits can use Cloudflare's platform-level rate limiting rules, which are applied at the network edge before requests reach the gateway Worker. This approach provides rate limiting without adding latency to the request path. For more granular, application-aware limits, rate limiting logic can be implemented in the backend services themselves.

## Related documentation

* [Authorizer Configuration](/configuration/authorizer) - Identify API consumers for per-client rate limits
* [Path Routing](/configuration/paths) - Define per-endpoint routing where rate limits can vary
* [Configuration Overview](/configuration/overview) - Gateway configuration reference


# Asynchronous Operation

Operations that occur without waiting for the previous operation to complete, improving efficiency and performance.

An asynchronous operation is a task that executes independently of the main program flow, allowing the system to continue processing other work while waiting for the operation to complete. Unlike synchronous operations, which block execution until they finish, asynchronous operations return control immediately and notify the caller when the result is ready.

Asynchronous patterns are essential in web development and API design, particularly for I/O-bound tasks like database queries, HTTP requests to external services, and file operations. Common implementation mechanisms include callbacks, promises, and async/await syntax in languages like JavaScript and Python.

In serverless and API gateway contexts, asynchronous processing is valuable for handling long-running tasks. Instead of keeping a client connection open, the API can accept a request, place the work on a queue, and return an immediate acknowledgment. The client can then poll for results or receive a webhook notification when processing completes. This approach improves responsiveness and resource utilization.


# Authentication

The process of verifying the identity of a user or system.

Authentication is the process of verifying the identity of a user, device, or system attempting to access a resource. It answers the question "who are you?" and typically involves presenting credentials such as a username and password, an API key, a token, or a certificate.

Common authentication methods in API contexts include API keys, OAuth 2.0 tokens, JSON Web Tokens (JWT), and mutual TLS. Each method has different security characteristics and is suited to different use cases. API keys are simple but offer limited security, while OAuth 2.0 provides delegated authorization flows suitable for third-party access.

API gateways commonly handle authentication as a centralized concern, validating credentials before requests reach backend services. This offloads authentication logic from individual services, ensures consistent enforcement, and simplifies the security architecture. In serverless deployments, gateway-level authentication is particularly important since there is no persistent server to maintain session state.


# Authorization

The process of verifying what specific applications, files, and data a user has access to.

Authorization is the process of determining what permissions an authenticated user or system has. While authentication verifies identity, authorization controls what actions that identity is allowed to perform. It answers the question "what are you allowed to do?"

Authorization models include role-based access control (RBAC), where permissions are assigned to roles and users are assigned to roles; attribute-based access control (ABAC), which evaluates policies based on user attributes, resource attributes, and environmental conditions; and scope-based access, commonly used in OAuth 2.0 to limit what a token can access.

In API management, authorization is typically enforced at the gateway level or within backend services. An API gateway can check whether a request's token contains the required scopes or roles before forwarding it. This provides a consistent policy enforcement point and reduces the risk of misconfigured access controls in individual services. Fine-grained authorization logic often still resides in the backend where business context is available.


# B

Glossary terms starting with the letter B, covering backend services and development blueprints.

This section contains glossary terms beginning with B.

* Backend as a Service (BaaS)
* Blueprint


# Backend as a Service (BaaS)

Backend as a Service (BaaS) provides ready-made backend features like databases, auth, and storage so developers can focus on frontend code.

Backend as a Service (BaaS) is a cloud computing model that provides developers with pre-built backend functionality -- such as databases, user authentication, file storage, push notifications, and server-side logic -- through APIs and SDKs. Instead of building and operating backend infrastructure from scratch, developers integrate these managed services into their applications and focus primarily on the frontend and business logic.

## What BaaS provides

A typical BaaS platform bundles several backend capabilities behind a unified API:

* **Database and data storage**: Managed databases (often real-time or document-oriented) that handle scaling, replication, and backups.
* **User authentication**: Sign-up, login, password reset, and identity federation flows with support for email/password, OAuth providers, and multi-factor authentication.
* **File and object storage**: APIs for uploading, storing, and serving files such as images, documents, and media.
* **Push notifications**: Sending notifications to mobile and web clients.
* **Server-side functions**: The ability to run custom backend logic in response to events, often through a built-in FaaS layer.

Popular BaaS platforms include Firebase (Google), Supabase (open source), AWS Amplify, and Appwrite. Each differs in its database model, pricing, self-hosting options, and extensibility.

## BaaS vs. building your own backend

Building a custom backend gives full control but requires setting up servers, databases, authentication systems, deployment pipelines, and ongoing maintenance. BaaS trades some of that control for speed: a developer can go from zero to a working backend in hours rather than weeks.

The trade-off is flexibility. BaaS platforms impose their own data models, query languages, and scaling limits. Applications that outgrow the platform's constraints may need to migrate to a custom backend, which can be costly if the application is tightly coupled to the BaaS provider's proprietary APIs.

## BaaS and API gateways

While BaaS platforms expose their own APIs, many applications combine BaaS with custom API services, third-party APIs, or multiple BaaS providers. An API gateway serves as the unified entry point that ties these pieces together, applying consistent authentication, CORS policies, and routing rules regardless of the backend.

Serverless API Gateway can route requests to BaaS endpoints alongside custom backend services. For example, you might configure the gateway to route authentication endpoints to Supabase, business logic endpoints to a custom service on AWS, and static asset requests to Cloudflare R2 -- all behind a single domain with consistent authorization policies managed at the gateway level.

## Related documentation

* [Authorizer Configuration](/configuration/authorizer) - Configure JWT authentication across BaaS and custom backends
* [Servers Configuration](/configuration/servers) - Define BaaS platforms as upstream servers
* [CORS Configuration](/configuration/cors) - Set up cross-origin policies for frontend-to-BaaS communication


# Blueprint

In API development, a predefined plan or layout for an API's structure and behavior.

A blueprint in API development is a predefined plan or template that describes the structure, endpoints, data models, and expected behavior of an API before it is implemented. Blueprints serve as a contract between API producers and consumers, enabling teams to agree on the interface before writing code.

API blueprints are commonly written using specification formats such as OpenAPI (formerly Swagger) or API Blueprint (a Markdown-based format). These documents define available endpoints, request and response schemas, authentication requirements, and error formats. They can be used to generate documentation, mock servers, client SDKs, and test suites automatically.

In serverless and gateway-driven architectures, blueprints are particularly useful because they allow teams to configure routing, validation, and transformation rules declaratively. The gateway can enforce the API contract at the edge, rejecting malformed requests before they reach backend functions. This reduces wasted compute and improves API reliability.




---

[Next Page](/llms-full.txt/1)

