Skip to main content
This page explains how to:
  1. Create YOUR OWN proxy server that forwards requests to your Databrain backend
  2. Configure the proxy to validate requests and add authentication headers
Your proxy acts as a secure gateway between your frontend and the Databrain backend.
Proxy authentication lets you host a secure intermediary server that validates incoming requests and forwards them to your Databrain backend. This approach keeps your plugin tokens secure on your server, never exposing them to the client.
Enhanced Security: With proxy authentication, your frontend never handles plugin tokens. Your proxy validates requests and adds the required authentication before forwarding to Databrain.

How Proxy Authentication Works

1

Client Sends Request

Your frontend sends a request to your proxy server with the X-Proxy-Auth-Key header for validation.
2

Proxy Validates Request

Your proxy validates the X-Proxy-Auth-Key header. If invalid or missing, return an error response.
3

Proxy Forwards Request

Your proxy constructs the upstream URL, adds the X-Plugin-Token header, and forwards the request to your Databrain backend exactly as received.
4

Response Returned

Your proxy returns the Databrain backend response to the client exactly as received (status code, body, and headers).

What Your Proxy Must Do

Your proxy can be built on any backend: Node.js, Express, FastAPI, Python, Go, Lambda, Cloudflare Worker, etc. It must receive requests from your frontend and forward them to your Databrain backend exactly as-is, with required headers added.

1. Read the Incoming Request

Capture all parts of the incoming request:
  • Path
  • Query parameters
  • HTTP method
  • Headers
  • Body (JSON, text, or binary/raw)
Body must not be modified. Preserve the raw content if it’s binary (zip, pdf, excel, etc.) or text/JSON for other API calls.

2. Validate Proxy Authentication

Your proxy must read and validate the X-Proxy-Auth-Key header:
X-Proxy-Auth-Key: <your-secret-key>
Compare with your stored secret value. If missing or invalid, return an error:
{
  "error": { "message": "missing or invalid proxy key" }
}
Return appropriate HTTP status (401 or 403).

3. Forward Request to Databrain Backend

Construct Upstream URL

<SELFHOSTED_BACKEND_URL>/<path>?<query>

Forward Original Method

Forward the exact HTTP method: GET, POST, PUT, PATCH, DELETE.

Forward Body Exactly

Do not modify the request payload in any way.

Required Upstream Headers

Send these headers to your Databrain backend:
HeaderDescription
AcceptForward from incoming request
Accept-LanguageForward from incoming request
User-AgentForward from incoming request
Content-TypeForward if present in incoming request
X-Plugin-OriginForward if provided by frontend
X-Proxy-Auth-KeyForward original value
X-Proxy-Auth-UrlForward original value
X-Plugin-TokenYour plugin token (added by proxy)
OriginForward original value

4. Return Response Exactly

Return exactly what the Databrain backend returns:
  • Status code
  • Response body (binary or text, do not transform)
  • Response headers
Binary responses (zip, pdf, xlsx) must be forwarded as-is. Do not convert binary content to text.

About X-Plugin-Token

The X-Plugin-Token header authenticates your requests with the Databrain backend. You can provide this token in two ways:
  1. A saved token - Use a pre-generated guest token stored in your environment
  2. Generate on demand - Call the Databrain Guest Token API to generate tokens dynamically

Error Response Format

Every error your proxy returns should follow this format:
{
  "error": { "message": "description of the error" }
}
Examples:
{
  "error": { "message": "missing or invalid X-Proxy-Auth-Key" }
}
{
  "error": { "message": "upstream fetch failed" }
}

Requirements Summary

  • Keep method, path, and query unchanged
  • Preserve body type: JSON, text, or binary
  • Pass all required headers (including Origin)
  • Add X-Plugin-Token header
  • Validate X-Proxy-Auth-Key before forwarding
  • Use correct error format
  • Return upstream response exactly (status, body, headers)
  • Forward binary responses (zip, pdf, xlsx) as-is
  • Do not rewrite paths
  • Do not remove fields from body
  • Do not add custom fields to body
  • Do not modify query parameters
  • Do not transform the response

Implementation Examples

import express from "express";
import fetch from "node-fetch";
import bodyParser from "body-parser";

const app = express();
app.use(bodyParser.raw({ type: "*/*" })); // preserve raw body

// --- Environment variables ---
const PROXY_AUTH_KEY = process.env.PROXY_AUTH_KEY; // secret key for validating requests
const SELFHOSTED_BACKEND_URL = process.env.SELFHOSTED_BACKEND_URL; // your Databrain backend
const GUEST_TOKEN = process.env.GUEST_TOKEN; // plugin token (saved or generated via API)

app.all('/proxy-auth/*', async (req, res) => {
  try {
    // --- Extract path and query ---
    const upstreamPath = req.path.replace(/^\/proxy-auth/, '') || '/';
    const queryString = req.originalUrl.split('?')[1] || '';
    const upstreamUrl = `${SELFHOSTED_BACKEND_URL}${upstreamPath}${queryString ? `?${queryString}` : ''}`;

    const method = req.method;
    const incomingHeaders = req.headers || {};

    // --- Handle preflight OPTIONS request ---
    if (method === 'OPTIONS') {
      return res.status(204).end();
    }

    // --- Validate proxy key ---
    const incomingProxyKey = incomingHeaders['x-proxy-auth-key'];
    if (!incomingProxyKey || incomingProxyKey !== PROXY_AUTH_KEY) {
      return res.status(401).json({
        error: { message: 'missing or invalid X-Proxy-Auth-Key' },
      });
    }

    // --- Build upstream headers ---
    const upstreamHeaders: Record<string, any> = {
      Accept: incomingHeaders['accept'] || '*/*',
      'Accept-Language': incomingHeaders['accept-language'] || 'en-US',
      'User-Agent': incomingHeaders['user-agent'] || 'Mozilla/5.0',
      'X-Plugin-Token': GUEST_TOKEN,
    };

    if (incomingHeaders['content-type']) {
      upstreamHeaders['Content-Type'] = incomingHeaders['content-type'];
    }
    if (incomingHeaders['x-plugin-origin']) {
      upstreamHeaders['X-Plugin-Origin'] = incomingHeaders['x-plugin-origin'];
    }
    if (incomingHeaders['x-proxy-auth-url']) {
      upstreamHeaders['X-Proxy-Auth-Url'] = incomingHeaders['x-proxy-auth-url'];
    }
    if (incomingHeaders['x-proxy-auth-key']) {
      upstreamHeaders['X-Proxy-Auth-Key'] = incomingHeaders['x-proxy-auth-key'];
    }
    if (incomingHeaders['origin']) {
      upstreamHeaders['Origin'] = incomingHeaders['origin'];
    }

    // --- Prepare request body for non-GET/HEAD methods ---
    let upstreamBody;
    if (!['GET', 'HEAD'].includes(method)) {
      upstreamBody = req.is('application/json') ? JSON.stringify(req.body) : req.body;
    }

    // --- Forward request to backend ---
    let upstreamResponse;
    try {
      upstreamResponse = await fetch(upstreamUrl, {
        method,
        headers: upstreamHeaders,
        body: upstreamBody,
      });
    } catch (err: any) {
      return res.status(502).json({
        error: { message: 'upstream fetch failed' },
        detail: err.message,
      });
    }

    // --- Forward upstream headers as-is ---
    const outHeaders: Record<string, any> = {};
    upstreamResponse.headers.forEach((v, k) => (outHeaders[k] = v));

    // --- Handle binary vs text responses ---
    const contentType = upstreamResponse.headers.get('content-type') || '';
    if (contentType.startsWith('text/') || contentType.includes('json')) {
      const text = await upstreamResponse.text();
      res.status(upstreamResponse.status).set(outHeaders).send(text);
    } else {
      const buffer = Buffer.from(await upstreamResponse.arrayBuffer());
      res.status(upstreamResponse.status).set(outHeaders).send(buffer);
    }
  } catch (err: any) {
    return res.status(500).json({
      error: { message: 'internal server error' },
      detail: err.message,
    });
  }
});

// --- Start server ---
app.listen(3000, () => {
  console.log('Proxy server running on port 3000');
});

Frontend Configuration

Configure your frontend to send requests through your proxy server instead of directly to the Databrain backend.

Configuration Setup

import { Databrain } from '@databrainhq/plugin';

// Configure proxy authentication globally
if (typeof window !== 'undefined') {
  window.dbn = {
    proxyAuthUrl: 'https://your-proxy-server.com/proxy-auth',
    proxyAuthKey: 'your-proxy-authentication-key',
    isEnableProxyAuth: true
  };
}

function MyDashboard() {
  return (
    <Databrain
      dashboardId="your-dashboard-id"
      // No token prop needed - proxy handles authentication
    />
  );
}
TypeScript Users: You need to declare the global window.dbn type in your project:
declare global {
  interface Window {
    dbn?: {
      proxyAuthUrl?: string;
      proxyAuthKey?: string;
      isEnableProxyAuth?: boolean;
    };
  }
}

Configuration Properties

window.dbn.proxyAuthUrl
string
required
The full URL of your proxy endpoint. This is sent as the X-Proxy-Auth-Url header.Example: https://your-proxy-server.com/proxy-auth
window.dbn.proxyAuthKey
string
required
A secret authentication key sent as the X-Proxy-Auth-Key header for your proxy to validate.
Generate a strong, random key and store it securely. This key must match the one your proxy expects.
window.dbn.isEnableProxyAuth
boolean
required
Enable or disable proxy authentication mode.
  • true: Use proxy authentication (required for proxy auth to work)
  • false or omitted: Use direct token authentication

Environment Variables

Your proxy server requires these environment variables:
VariableDescription
PROXY_AUTH_KEYSecret key to validate incoming requests (must match frontend proxyAuthKey)
SELFHOSTED_BACKEND_URLYour Databrain backend URL (e.g., https://api.usedatabrain.com)
GUEST_TOKENYour plugin token (saved or generated via API)

Security Best Practices

  • Use Strong Keys: Generate a cryptographically random proxy authentication key
  • Validate Every Request: Always verify the X-Proxy-Auth-Key header
  • HTTPS Only: Ensure your proxy endpoint is only accessible via HTTPS
  • Rotate Keys: Periodically rotate your proxy authentication keys
Add rate limiting to prevent abuse:
  • Limit requests per IP address
  • Limit requests per user/session
  • Implement exponential backoff for repeated failures
  • Log all proxy requests for audit purposes
  • Monitor for unusual traffic patterns
  • Set up alerts for authentication failures
  • Store GUEST_TOKEN securely in environment variables
  • Never expose tokens in client-side code
  • Consider generating tokens dynamically for enhanced security

Error Handling

Common Errors

Error: {"error": {"message": "missing or invalid X-Proxy-Auth-Key"}}Cause: The X-Proxy-Auth-Key header is missing or doesn’t match.Solution: Verify that window.dbn.proxyAuthKey matches your proxy’s PROXY_AUTH_KEY environment variable.
Error: {"error": {"message": "upstream fetch failed"}}Cause: Your proxy cannot reach the Databrain backend.Solution:
  • Verify SELFHOSTED_BACKEND_URL is correct
  • Check network connectivity from your proxy server
  • Verify firewall rules allow outbound connections
Error: {"error": {"message": "internal server error"}}Cause: An unexpected error occurred in your proxy.Solution: Check your proxy server logs for detailed error information.

Testing Your Proxy

Use curl to test your proxy endpoint:
# Test with valid proxy key
curl -X GET "https://your-proxy-server.com/proxy-auth/api/health" \
  -H "X-Proxy-Auth-Key: your-proxy-key"

# Test authentication validation (should return 401)
curl -X GET "https://your-proxy-server.com/proxy-auth/api/health" \
  -H "X-Proxy-Auth-Key: invalid-key"