Industry · · 4 min read

How to authenticate OpenAI Operator requests using HTTP message signatures

How to authenticate OpenAI Operator requests using HTTP message signatures

Cloudflare recently introduced a new authentication standard, HTTP message signatures, designed to securely verify automated traffic from known bot operators. OpenAI has adopted this standard in its OpenAI Operator product, which allows ChatGPT agents to perform actions on behalf of users.

This new approach replaces the traditional method of IP-based allowlisting with a cryptographic scheme based on signed HTTP requests. Instead of maintaining and rotating lists of IP addresses, websites can now verify a bot’s identity using public keys published by the bot provider.

For developers and security teams, this simplifies bot verification while improving security guarantees. It’s especially relevant in the context of AI agents, which may trigger critical workflows like submitting forms, triggering transactions, or modifying content.

Understanding the bot authentication standard

Under this standard, each bot operator exposes a public key via a well-known endpoint:

/.well-known/http-message-signatures-directory

This endpoint returns metadata used to verify signed requests. For example, OpenAI’s key directory is available at https://chatgpt.com/.well-known/http-message-signatures-directory .

A sample response looks like this:


{
  "keys": [
    {
      "kid": "otMqcjr17mGyruktGvJU8oojQTSMHlVm7uO-lrcqbdg",
      "crv": "Ed25519",
      "kty": "OKP",
      "x": "7F_3jDlxaquwh291MiACkcS3Opq88NksyHiakzS-Y1g",
      "use": "sig",
      "nbf": 1735689600,
      "exp": 1754656053
    }
  ],
  "signature_agent": "<https://chatgpt.com>",
  "purpose": "ai"
}

This data allows any server receiving a request from OpenAI’s agent to verify the signature using the published public key. Keys are versioned using the kid (key ID) field and have defined validity periods (nbf, exp).

Publishing keys at a predictable location removes the need for out-of-band key distribution and supports dynamic key rotation with minimal coordination.

Example: verifying a signed request from OpenAI Operator

To demonstrate how this works in practice, we instructed OpenAI’s agent to visit a page that includes Castle instrumentation. As expected, our server later received a POST request to the following endpointhttps://deviceandbrowserinfo.com/info_device

The request includes the following relevant headers:

{
  "Signature": "sig1=:OxtIqCmhbdHV9oNRn2rCmSaMJFC83CrzTsgC6CaULImrbish5S1h5PwO+8tSNGG8GzSHpRl/E/mgy5vKvuD0DQ==:",
  "Signature-Input": "sig1=(\\"@authority\\" \\"@method\\" \\"@path\\" \\"signature-agent\\");created=1754053298;keyid=\\"otMqcjr17mGyruktGvJU8oojQTSMHlVm7uO-lrcqbdg\\";expires=1754056898;nonce=\\"...\\";tag=\\"web-bot-auth\\";alg=\\"ed25519\\"",
  "Signature-Agent": "\\"<https://chatgpt.com>\\"",
  "Content-Type": "application/json",
  "User-Agent": "Mozilla/5.0 ..."
}

These headers indicate the request was signed using the Ed25519 key with ID otMqcjr17mGyruktGvJU8oojQTSMHlVm7uO-lrcqbdg, which matches the key published by OpenAI. The Signature-Agent header asserts the identity of the sender, and the signature covers the HTTP method, path, authority, and agent fields.

To verify the request, we’ll use Cloudflare’s web-bot-auth Node.js library, which provides helpers for signature parsing and verification.

Step-by-step: verifying signatures in Node.js

The following Node.js snippet shows how to verify a signed request from OpenAI using Cloudflare’s web-bot-auth package. Note that the signature is time-sensitive. If you're replaying a real request, verification may fail if the signature has expired.

import { verify } from "web-bot-auth";
import { verifierFromJWK } from "web-bot-auth/crypto";

(async () => {
  // Public key retrieved from OpenAI's /.well-known/http-message-signatures-directory
  const OPEN_AI_KEY = {
    kid: "otMqcjr17mGyruktGvJU8oojQTSMHlVm7uO-lrcqbdg",
    crv: "Ed25519",
    kty: "OKP",
    x: "7F_3jDlxaquwh291MiACkcS3Opq88NksyHiakzS-Y1g",
    use: "sig",
    nbf: 1735689600,
    exp: 1754656053
  };

  // Construct a synthetic Request object for the demo
  const signedRequest = new Request("<https://deviceandbrowserinfo.com/info_device>", {
    method: "POST",
    headers: {
      Signature: "sig1=:OxtIqCmhbdHV9oNRn2rCmSaMJFC83CrzTsgC6CaULImrbish5S1h5PwO+8tSNGG8GzSHpRl/E/mgy5vKvuD0DQ==:",
      "Signature-Input": 'sig1=("@authority" "@method" "@path" "signature-agent");created=1754053298;keyid="otMqcjr17mGyruktGvJU8oojQTSMHlVm7uO-lrcqbdg";expires=1754056898;nonce="...";tag="web-bot-auth";alg="ed25519"',
      "Signature-Agent": "\\"<https://chatgpt.com>\\"",
      "Content-Type": "application/json"
    },
    body: "{}"
  });

  try {
    await verify(signedRequest, await verifierFromJWK(OPEN_AI_KEY));
    console.log("Signature verification successful");
  } catch (err) {
    console.error("Signature verification failed:", err.message);
  }
})();

In a production setup, you would extract the Request object from your web framework (e.g. Express or Fastify) and dynamically fetch and cache keys from the /.well-known/http-message-signatures-directory endpoint.

Why signed requests are a better way to verify AI agents

This example shows how to verify that a request was sent by an authenticated bot, using only its public key and HTTP headers. The benefits over traditional IP-based allowlists are clear:

For bot providers like OpenAI, this allows them to publish a single cryptographic identity. For receiving sites, it enables fine-grained authentication tied to specific agents and actions.

While this example uses Node.js, Cloudflare’s GitHub repository includes implementations for Go (via Caddy) and Rust as well.

Technical considerations

Verifying bot requests using signed HTTP headers is a more secure and maintainable alternative to managing IP allowlists. It provides strong authenticity guarantees with minimal integration overhead.

While the example in this post is intentionally simple, deploying this approach in production requires a few additional considerations:

As more AI agents are entrusted with user actions, cryptographic authentication provides a scalable foundation for verifying their requests.

Read next