Create and secure an AI agent wrapper using AI Gateway and Zero Trust
This tutorial explains how to use Cloudflare AI Gateway and Zero Trust to create a functional and secure website wrapper for an AI agent. Cloudflare Zero Trust administrators can protect access to the wrapper with Cloudflare Access. Additionally, you can enforce Gateway policies to control how your users interact with AI agents, including executing AI agents in an isolated browser with Browser Isolation, enforcing Data Loss Prevention profiles to prevent your users from sharing sensitive data, and scanning content to avoid answers from AI agents that violate internal corporate guidelines. Creating an AI agent wrapper is also an effective way to enforce tenant control if you have an enterprise plan for a specific AI provider, such as ChatGPT Enterprise.
This tutorial uses ChatGPT as an example AI agent.
Make sure you have:
- A Cloudflare Zero Trust organization.
- An API key for your desired AI provider, such as an OpenAI API key ↗ for ChatGPT.
First, create an AI gateway to control your AI app.
- Log in to the Cloudflare dashboard ↗ and select your account.
- Go to AI > AI Gateway.
- Select Create Gateway.
- Name your gateway.
- Select Create.
- Configure your desired options for the gateway.
- Connect your AI provider to proxy queries to your AI agent of choice using your AI gateway.
- (Optional) Turn on Authenticated Gateway. The Authenticated Gateway feature ensures your AI gateway can only be called securely by enforcing a token in the form of a request header
cf-aig-authorization
.- Go to AI > AI Gateway.
- Select your AI gateway, then go to Settings.
- Turn on Authenticated Gateway, then choose Confirm.
- Select Create authentication token, then select Create an AI Gateway authentication token.
- Configure your token and copy the token value. When creating your Worker, you will need to pass this token when calling your AI gateway.
For more information, refer to Getting started with AI Gateway.
Guardrails is an built-in AI Gateway security feature that allows Cloudflare to identify unsafe or inappropriate content in prompts and responses based on selected categories.
- Go to AI > AI Gateway.
- Select your AI gateway.
- Go to Guardrails.
- Turn on Guardrails.
- Select Change to configure the categories you would like to filter for both prompts and responses.
In order to build the Worker, you will need to choose if you want to build it locally using Wrangler or remotely using the dashboard ↗.
-
In a terminal, log in to your Cloudflare account:
Terminal window wrangler login -
Initiate the project locally:
Terminal window mkdir ai-agent-wrappercd ai-agent-wrapperwrangler init -
Create a
wrangler.toml
configuration file:name = "ai-agent-wrapper"main = "src/index.js"compatibility_date = "2023-10-30"[vars]# Add any environment variables here -
Add your AI provider's API key as a secret:
Terminal window wrangler secret put <OPENAI_API_KEY>
You can now build the Worker using the index.js
file created by Wrangler.
- Log in to the Cloudflare dashboard ↗ and select your account.
- Go to Workers & Pages > Workers & Pages.
- Select Create.
- In Workers, choose the Hello world template.
- Name your worker, then select Deploy.
- Select your Worker, then go to the Settings tab.
- Go to Variables and Secrets, then select Add.
- Choose Secret as the type, name your secret (for example,
OPENAI_API_KEY
), and enter the value of your AI provider's API key in Value.
You can now build the Worker using the online code editor by selecting Edit code on your Worker page.
The following is an example starter Worker that serves a simple front-end to allow a user to interact with an AI provider behind AI Gateway. This example uses OpenAI as its AI provider:
export default { async fetch(request, env) { if (request.url.endsWith("/api/chat")) { if (request.method === "POST") { try { const { messages } = await request.json();
const response = await fetch( "https://gateway.ai.cloudflare.com/v1/$ACCOUNT_ID/$GATEWAY_ID/openai/chat/completions", { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${env.OPENAI_API_KEY}`, }, body: JSON.stringify({ model: "gpt-4o-mini", messages: messages, }), }, );
if (!response.ok) { throw new Error(`AI Gateway Error: ${response.status}`); }
const result = await response.json(); return new Response( JSON.stringify({ response: result.choices[0].message.content, }), { headers: { "Content-Type": "application/json" }, }, ); } catch (error) { return new Response(JSON.stringify({ error: error.message }), { status: 500, headers: { "Content-Type": "application/json" }, }); } } return new Response("Method not allowed", { status: 405 }); }
return new Response(HTML, { headers: { "Content-Type": "text/html" }, }); },};
const HTML = `<!DOCTYPE html> <html lang="en" data-theme="dark">177 collapsed lines
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>ChatGPT Wrapper</title> <style> :root { --background-color: #1a1a1a; --chat-background: #2d2d2d; --text-color: #ffffff; --input-border: #404040; --message-ai-background: #404040; --message-ai-text: #ffffff; }
body { font-family: system-ui, sans-serif; margin: 0; padding: 20px; background: var(--background-color); display: flex; flex-direction: column; align-items: center; gap: 20px; color: var(--text-color); }
.chat-container { width: 100%; max-width: 800px; background: var(--chat-background); border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); height: 80vh; display: flex; flex-direction: column; }
.chat-header { padding: 15px 20px; border-bottom: 1px solid var(--input-border); background: var(--chat-background); border-radius: 10px 10px 0 0; text-align: center; }
.chat-messages { flex-grow: 1; overflow-y: auto; padding: 20px; }
.message { margin-bottom: 20px; padding: 10px 15px; border-radius: 10px; max-width: 80%; }
.user-message { background: #007AFF; color: white; margin-left: auto; }
.ai-message { background: var(--message-ai-background); color: var(--message-ai-text); }
.input-container { padding: 20px; border-top: 1px solid var(--input-border); display: flex; gap: 10px; }
input { flex-grow: 1; padding: 10px; border: 1px solid var(--input-border); border-radius: 5px; font-size: 16px; background: var(--chat-background); color: var(--text-color); }
button { padding: 10px 20px; background: #007AFF; color: white; border: none; border-radius: 5px; cursor: pointer; font-size: 16px; }
button:disabled { background: #ccc; }
.error { color: red; padding: 10px; text-align: center; } </style> </head> <body> <div class="chat-container"> <div class="chat-header"> <h2>AI Assistant</h2> </div> <div class="chat-messages" id="messages"></div> <div class="input-container"> <input type="text" id="userInput" placeholder="Type your message..." /> <button onclick="sendMessage()" id="sendButton">Send</button> </div> </div>
<script> let messages = []; const messagesDiv = document.getElementById('messages'); const userInput = document.getElementById('userInput'); const sendButton = document.getElementById('sendButton');
userInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') sendMessage(); });
async function sendMessage() { const content = userInput.value.trim(); if (!content) return;
userInput.disabled = true; sendButton.disabled = true;
messages.push({ role: 'user', content }); appendMessage('user', content); userInput.value = '';
try { const response = await fetch('/api/chat', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ messages }) });
if (!response.ok) { throw new Error('API request failed'); }
const result = await response.json(); const aiMessage = result.response;
messages.push({ role: 'assistant', content: aiMessage }); appendMessage('ai', aiMessage); } catch (error) { appendMessage('ai', 'Sorry, there was an error processing your request.'); console.error('Error:', error); }
userInput.disabled = false; sendButton.disabled = false; userInput.focus(); }
function appendMessage(role, content) { const messageDiv = document.createElement('div'); messageDiv.className = 'message ' + role + '-message'; messageDiv.textContent = content; messagesDiv.appendChild(messageDiv); messagesDiv.scrollTop = messagesDiv.scrollHeight; } </script> </body> </html>`;
Note that the account ID and gateway ID need to be replaced in the AI Gateway endpoint. You can add these as environment variables or secrets in Workers. If you chose to use Authenticated Gateway when creating your AI gateway, make sure to also add your token as a secret and pass its value to the AI gateway in the cf-aig-authorization
header.
Once the Worker code is complete, you need to make the Worker addressable using a hostname controllable by Cloudflare Access.
Edit the wrangler.toml
configuration file and add the following information to ensure that the Worker is only accessible using the custom hostname:
name = "ai-agent-wrapper"main = "src/index.js"compatibility_date = "2023-10-30"workers_dev = false
# Replace with your custom domainroutes = [ { pattern = "<YOUR_CUSTOM_DOMAIN>", custom_domain = true }]
[vars]# Add any environment variables here
To publish the worker, run wrangler publish
.
If you built your Worker remotely using the code editor available in the Cloudflare dashboard, you can deploy it by selecting Deploy.
To ensure that the Worker is only accessible from the custom hostname:
- Go to Workers & Pages > Workers & Pages.
- Select your Worker.
- Go to Settings.
- Within Domains & Routes, select Add.
- Choose Custom domain.
- Enter your desired custom domain name.
- Select Add domain.
The Worker is now behind an addressable public hostname. Make sure to turn off both workers.dev and Preview URLs so that the Worker can only be accessed with its custom domain.
To secure the AI agent wrapper to ensure that only trusted users can access it:
- In Zero Trust ↗, go to Access > Applications.
- Select Add an application.
- Choose Self-hosted.
- Enter a name for your AI agent wrapper application.
- In Session Duration, choose when the user's application token should expire.
- Select Add public hostname and enter the custom domain you set for your Worker.
- Configure your Access application for your Worker.
- Add Access policies to control who can connect to your application.
Now your AI wrapper can only be accessed by your users that successfully match your Access policies.
You can now block access to all unauthorized public AI agents with a Gateway HTTP policy.
-
In Zero Trust ↗, go to Gateway > Firewall policies.
-
Select HTTP.
-
Select Add a policy.
-
Add the following policy:
Selector Operator Value Action Content Categories in Artificial Intelligence Block -
Select Create policy.
This ensures that public AI agents are not accessible using a managed endpoint.
Alternatively, you can prevent users from using public AI agents by displaying a custom block message, redirect, or a user notification directing users to the AI agent wrapper.
Now that you have full control over access to your AI agent wrapper, you can enforce extra security methods such as Data Loss Prevention (DLP) and Clientless Web Isolation to protect and control data shared with the AI agent.
You can use Data Loss Prevention (DLP) to prevent your users from sending sensitive data to the AI agent.
-
In Zero Trust ↗, go to DLP > DLP profiles.
-
Ensure that the DLP profiles you want to enforce are properly configured.
-
Add an HTTP policy to enforce the DLP profile for the hostname for your wrapper. For example:
Selector Operator Value Logic Action Host is ai-wrapper.example.com
And Block DLP Profile in AI DLP profile -
Select Create policy.
For more information on creating DLP policies, refer to Scan HTTP traffic.
Because you published your wrapper as a self-hosted Access application, you can execute it in an isolated session for your users by creating an Access policy and configuring it for your application.
- In Zero Trust ↗, go to Settings > Browser Isolation.
- Enable Clientless Web Isolation.
- Go to Access > Policies.
- Select Add a policy.
- Set the Action to Allow.
- In Add rules, add identity rules to define who the application should be isolated for.
- In Additional settings (optional), turn on Isolate application.
Once the Access policy has been created, you can attach it to your wrapper.
- Go to Access > Applications.
- Choose your wrapper application, then select Configure.
- In Policies, select Select existing policies.
- Choose the Access policy you previously created.
- Select Confirm, then select Save application.
Because Clientless Web Isolation traffic applies your Gateway HTTP policies, your configured DLP profiles will apply to isolated sessions.
For more information on isolating an Access application, refer to Isolate self-hosted application.
Organizations that adopt Cloudflare to secure access to AI agents will benefit from improved visibility and configurability.
Zero Trust will log all Access events and DLP detections. In addition, AI Gateway provides visibility into user prompts, model response, token usage, and costs.
Logs can be exported to external providers with Logpush.
You can configure your wrapper to use a different AI provider or give your users the option to choose between multiple AI providers, including AI models running directly on Cloudflare's global network with Workers AI. With this, you can control costs related to AI usage or adopt newer models without impacting your users or the access controls already put in place.
Was this helpful?
- Resources
- API
- New to Cloudflare?
- Products
- Sponsorships
- Open Source
- Support
- Help Center
- System Status
- Compliance
- GDPR
- Company
- cloudflare.com
- Our team
- Careers
- 2025 Cloudflare, Inc.
- Privacy Policy
- Terms of Use
- Report Security Issues
- Trademark