Integrating Proxy Functions in Your Code
After creating a proxy function, you need to update your frontend code to call the proxy URL instead of the third-party API directly. This is the key step that keeps your secrets safe — your code never touches the real API key.
How It Works
Without a proxy, your frontend calls the third-party API directly and must include the API key:
// BEFORE: Secret exposed in frontend code
fetch('https://api.brevo.com/v3/smtp/email', {
method: 'POST',
headers: {
'api-key': 'xkeysib-YOUR-SECRET-KEY', // Visible to anyone!
'Content-Type': 'application/json'
},
body: JSON.stringify({
sender: { email: 'you@example.com' },
to: [{ email: 'user@example.com' }],
subject: 'Hello',
htmlContent: '<p>Welcome!</p>'
})
})
With a proxy, your frontend calls the EnvManager proxy URL instead. The proxy injects the secret server-side:
// AFTER: Secret never leaves the server
fetch('https://your-project.supabase.co/functions/v1/proxy-handler/abc-123', {
method: 'POST',
headers: {
'x-proxy-token': 'your-proxy-token', // Safe: this is a proxy token, not your API key
'Content-Type': 'application/json'
},
body: JSON.stringify({
sender: { email: 'you@example.com' },
to: [{ email: 'user@example.com' }],
subject: 'Hello',
htmlContent: '<p>Welcome!</p>'
})
})
Notice the only things that change are the URL and the authentication header. The request body stays exactly the same.
What You Need
After creating a proxy, you receive two values from EnvManager:
| Value | Where to Find It | Purpose |
|---|---|---|
| Proxy URL | Code Preview section after saving, or the proxy list | Replace the third-party API URL with this |
| Proxy Token | Code Preview section after saving | Send in the x-proxy-token header to authenticate |
The proxy token is not your API key. It authenticates your frontend with the proxy. Your actual API key is stored securely in EnvManager and injected server-side by the proxy. Never share the proxy token publicly — treat it like a password for your proxy endpoint.
Step-by-Step Integration
Get Your Proxy URL and Token
Open the proxy function in EnvManager. In the Code Preview section, copy the Proxy URL and Proxy Token.
Replace the API URL
In your frontend code, change the URL from the third-party API to your proxy URL:
// Before
const url = 'https://api.stripe.com/v1/charges'
// After
const url = 'https://your-project.supabase.co/functions/v1/proxy-handler/your-proxy-id'
Replace the Auth Header
Remove the API key header and add the proxy token header instead:
// Before
headers: {
'Authorization': 'Bearer sk_live_YOUR_STRIPE_KEY',
'Content-Type': 'application/x-www-form-urlencoded'
}
// After
headers: {
'x-proxy-token': 'your-proxy-token',
'Content-Type': 'application/x-www-form-urlencoded'
}
The proxy adds the Authorization: Bearer sk_live_... header automatically using your stored secret.
Keep the Request Body the Same
The request body does not change. The proxy forwards it to the third-party API as-is (when pass-through is enabled).
Test It
Use the built-in test panel or try a request from your local development environment to confirm everything works.
Code Examples by Framework
Plain JavaScript (Fetch)
const PROXY_URL = 'https://your-project.supabase.co/functions/v1/proxy-handler/your-proxy-id'
const PROXY_TOKEN = 'your-proxy-token'
async function sendEmail(to, subject, body) {
const response = await fetch(PROXY_URL, {
method: 'POST',
headers: {
'x-proxy-token': PROXY_TOKEN,
'Content-Type': 'application/json'
},
body: JSON.stringify({
sender: { email: 'noreply@yoursite.com' },
to: [{ email: to }],
subject: subject,
htmlContent: body
})
})
if (!response.ok) {
throw new Error(`Proxy error: ${response.status}`)
}
return response.json()
}
React / Next.js
const PROXY_URL = process.env.NEXT_PUBLIC_PROXY_URL
const PROXY_TOKEN = process.env.NEXT_PUBLIC_PROXY_TOKEN
export default function ContactForm() {
async function handleSubmit(e) {
e.preventDefault()
const formData = new FormData(e.target)
const res = await fetch(PROXY_URL, {
method: 'POST',
headers: {
'x-proxy-token': PROXY_TOKEN,
'Content-Type': 'application/json'
},
body: JSON.stringify({
sender: { email: 'noreply@yoursite.com' },
to: [{ email: 'team@yoursite.com' }],
subject: `Contact from ${formData.get('name')}`,
htmlContent: `<p>${formData.get('message')}</p>`
})
})
if (res.ok) {
alert('Message sent!')
}
}
return (
<form onSubmit={handleSubmit}>
<input name="name" placeholder="Name" required />
<textarea name="message" placeholder="Message" required />
<button type="submit">Send</button>
</form>
)
}
Vue / Nuxt
<script setup>
const proxyUrl = useRuntimeConfig().public.proxyUrl
const proxyToken = useRuntimeConfig().public.proxyToken
async function submitForm() {
const { data, error } = await useFetch(proxyUrl, {
method: 'POST',
headers: {
'x-proxy-token': proxyToken,
'Content-Type': 'application/json'
},
body: {
sender: { email: 'noreply@yoursite.com' },
to: [{ email: 'team@yoursite.com' }],
subject: 'New contact form submission',
htmlContent: '<p>Hello from the contact form</p>'
}
})
if (error.value) {
console.error('Proxy error:', error.value)
}
}
</script>
Astro
---
// This runs on the server during build, but for dynamic calls
// use a client-side script or API route
---
<script>
const PROXY_URL = import.meta.env.PUBLIC_PROXY_URL
const PROXY_TOKEN = import.meta.env.PUBLIC_PROXY_TOKEN
document.querySelector('#contact-form').addEventListener('submit', async (e) => {
e.preventDefault()
const res = await fetch(PROXY_URL, {
method: 'POST',
headers: {
'x-proxy-token': PROXY_TOKEN,
'Content-Type': 'application/json'
},
body: JSON.stringify({
sender: { email: 'noreply@yoursite.com' },
to: [{ email: 'team@yoursite.com' }],
subject: 'Contact form',
htmlContent: '<p>Message from the site</p>'
})
})
if (res.ok) alert('Sent!')
})
</script>
Storing the Proxy Token
The proxy token authenticates your frontend with the proxy. Here are some recommendations for where to store it:
| Approach | When to Use |
|---|---|
Environment variable (e.g., NEXT_PUBLIC_PROXY_TOKEN) | Most frameworks — loaded at build time |
| Hardcoded in client code | Simple static sites — acceptable since the token only grants access to the proxy, not the underlying API key |
| Server-side only | If your framework has server routes (Next.js API routes, Nuxt server routes), you can keep the token server-side for an extra layer of security |
The proxy token is designed to be safe for client-side use. Even if someone gets the token, they can only call your proxy — not the underlying API. Combined with CORS restrictions and rate limiting, you have strong protection against abuse.
Handling Errors
The proxy returns standard HTTP status codes. Your error handling should account for both proxy errors and upstream API errors:
| Status | Meaning |
|---|---|
200 | Success — the third-party API responded normally |
400 | Bad request — missing required fields |
401 | Invalid or missing x-proxy-token header |
403 | CORS origin not allowed |
404 | Proxy function not found or disabled |
429 | Rate limit exceeded — wait and retry |
502 | The third-party API returned an error |
504 | The third-party API timed out (25-second limit) |
const response = await fetch(PROXY_URL, { /* ... */ })
if (response.status === 429) {
// Rate limited — check headers for reset time
const retryAfter = response.headers.get('X-RateLimit-Reset')
console.log(`Rate limited. Try again at ${retryAfter}`)
} else if (response.status === 502) {
// The third-party API itself had an error
const body = await response.json()
console.error('Upstream API error:', body)
} else if (!response.ok) {
console.error(`Proxy error: ${response.status}`)
}
CORS and Allowed Origins
If your proxy returns a CORS error in the browser console, check that your website's domain is listed in the proxy's Allowed Origins setting. See CORS Configuration for details.
During local development, add http://localhost:3000 (or whichever port you use) to the allowed origins list.
Related Topics
Creating Proxy Functions
Set up a new proxy function step by step.
Templates
Pre-configured proxies for Brevo, Stripe, and OpenAI.
Testing
Verify your proxy works before going live.
Rate Limiting
Protect your proxy against abuse.