> For the complete documentation index, see [llms.txt](https://docs.goassay.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.goassay.ai/developers/list-your-api-get-started/cloudflare-worker.md).

# Verify with a Cloudflare Worker (no code)

Put a ready-made signature-checking gateway in front of your API.

The ready-made Worker checks the Assay signature before forwarding a request to your API. You do not change your application code. You do need a Cloudflare account and a way to restrict access to your origin server, the API behind the Worker.

## How it works

Assay calls the Worker's public HTTPS address. The Worker verifies the request against Assay's public keys, then sends valid calls to `ORIGIN_URL`. Invalid signatures get `401`; your origin is not called.

## Deploy and configure

1. Open [Deploy to Cloudflare](https://deploy.workers.cloudflare.com/?url=https://github.com/assay-ai/assay-provider-verify/tree/main/worker), sign in to Cloudflare and deploy the ready-made Worker.
2. In the repository Cloudflare created for you, set `ORIGIN_URL` in `wrangler.toml` under `[vars]` to your origin, for example `https://origin.example.com`, and commit it. An optional path prefix is allowed. Do not point it back to the Worker. A value set only in the Cloudflare dashboard is replaced by `wrangler.toml` on the next deploy.
3. Attach the Worker to the public hostname Assay will call, using a route or custom domain. For example, use `api.example.com` for the Worker and `origin.example.com` for the origin.
4. Restrict the origin to requests from the Worker. If your gateway already checks a secret header, set the Worker's `ORIGIN_SECRET` secret with `npx wrangler secret put ORIGIN_SECRET` and require that value in `x-assay-origin-secret` at the origin. Otherwise, arrange a private origin connection such as Cloudflare Tunnel, with no public bypass. Configuring the Worker secret alone does not restrict the origin.
5. Sign in to Assay and open your listing's **Connect & test** step.
6. Set **Your API's address** to the Worker's HTTPS address, including the path your tool needs. Assay must sign the Worker's hostname, not the origin's hostname.
7. Under **Authentication**, choose **Assay signature (recommended)**.
8. Fill in the tool's test input and click **Save and run test**, or **Run the test again**.

## Check it worked

The signed call should reach your origin and pass the test. There should be no **Signature not enforced** warning. Check that a direct call to the origin cannot bypass the gateway.

You can also check the public route without a signature. Replace this example with your Worker's address and a path it protects:

```sh
curl -i https://api.example.com/v1/search
```

Expect status `401`, `content-type: application/json` and this body:

```json
{"error":"invalid_assay_signature","reason":"MISSING"}
```

## Details

| Setting or behavior | Default / result                                                                                                                                              |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ORIGIN_URL`        | Required deployment setting; replace the template's `https://origin.example.com`. The Worker appends the incoming path and query to the origin's path prefix. |
| `JWKS_URL`          | Leave unset to fetch Assay's public keys from `https://api.goassay.ai/.well-known/assay-request-keys.json`.                                                   |
| `ORIGIN_SECRET`     | Unset. When set, the Worker adds `x-assay-origin-secret` on forwarded calls.                                                                                  |
| Request body cap    | 5 MiB (5,242,880 bytes), buffered before verification. Larger bodies get `413 {"error":"payload_too_large"}`.                                                 |
| Forwarded request   | Same method and body. Removes `Signature`, `Signature-Input`, `Content-Digest` and `Host`; keeps `X-Assay-Call-Id`.                                           |
| Origin redirects    | Returned to the caller; the Worker does not follow them. Use an origin URL that answers directly.                                                             |
| Replay store        | In-memory per Worker instance. A captured request can be accepted again on another instance while its signature is still valid.                               |

{% hint style="danger" %}
The default deployment checks signature authenticity and expiry, but does not provide shared replay protection. Assay signs requests for five minutes, and the verifier allows 60 seconds of clock tolerance around the signed times. To reject replays across instances, enable the Durable Object below.
{% endhint %}

<details>

<summary>Optional: reject replays across Worker instances</summary>

Enable the supplied `NONCE_STORE` Durable Object binding and its `NonceStore` migration in `worker/wrangler.toml`, then redeploy. Also set `NONCE_LOCATION_HINT` (for example `weur` or `enam`) under `[vars]` to a region near your origin. This changes deployment configuration and adds a shared storage call per verified request. If the store is unavailable, the Worker returns `503 {"error":"replay_store_unavailable"}` and does not forward the call.

</details>

## Errors

| Symptom                      | Fix                                                                                                                 |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| Valid Assay calls get `401`. | Keep the incoming method, host, path, query and body unchanged until verification. Use the Worker address in Assay. |
| **Signature not enforced**   | Check that the route actually runs the Worker and the origin has no public bypass.                                  |
| Calls get `413`.             | Keep bodies within the Worker's cap.                                                                                |

## Go further

* List your API (optional): [Or: publish your own API](https://docs.goassay.ai/list-your-api/publish-your-own-api).

## Next

* [Verify in your code (Node, Python, Go)](/developers/list-your-api-get-started/verify-in-your-code.md) — an alternative to the Worker.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.goassay.ai/developers/list-your-api-get-started/cloudflare-worker.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
