Featured

How to Secure APIs in Next.js With SaltingIO Bridge URLs

Stop writing API routes just to hide keys. SaltingIO bridge URLs let you secure third-party APIs in Next.js with CORS, rate limiting, and usage tracking — no backend needed.

SaltingIO Team February 26, 2026 7 min read API Keys
NextJsAPISecurityFrontendReactSaltingIOWebDev
How to Secure APIs in Next.js With SaltingIO Bridge URLs

How to Secure APIs in Next.js With SaltingIO Bridge URLs

You're building a Next.js app that calls OpenAI, Stripe, or a weather API. You've read the docs, you know NEXT_PUBLIC_ variables are exposed in the browser. So you create an API route in pages/api/ or app/api/ to hide the key.

Now you're maintaining a proxy endpoint, debugging CORS headers, adding rate limiting middleware, and deploying serverless functions. All to forward one API call.

There's a faster way. SaltingIO gives you a secure bridge URL that handles all of this --- in under 2 minutes.


The Problem: Next.js Doesn't Protect Your Keys by Default

Next.js has two types of environment variables:

  • NEXT_PUBLIC_* --- bundled into client-side JavaScript. Fully visible in the browser.
  • Server-only variables --- available in API routes and server components, but not accessible from client components.

If you need to call a third-party API from a client component (for streaming, real-time updates, or interactive UIs), you're stuck. Either you expose the key, or you build a backend proxy.

API routes solve this, but they come with baggage:

  • Cold starts on serverless platforms
  • Manual CORS configuration
  • No built-in rate limiting
  • No usage tracking
  • Another deployment artifact to maintain

The Myth: "API Routes Are the Only Way"

Every Next.js tutorial tells you the same thing: create a /api/proxy route, store your key in .env.local, and forward requests.

It works --- but it's overkill when all you need is a secure passthrough.

You end up writing boilerplate like this:

// app/api/chat/route.js
export async function POST(req) {
  const body = await req.json();
  const res = await fetch('https://api.openai.com/v1/chat/completions', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`
    },
    body: JSON.stringify(body)
  });
  return new Response(res.body, { headers: { 'Content-Type': 'application/json' } });
}

That's 15 lines of code, plus CORS handling, error handling, rate limiting, and deployment config. For a single API call.

SaltingIO replaces all of that with a single URL.


Step-by-Step: Securing Your Next.js App With a Salting Bridge

Here's how to secure any API key in your Next.js app using SaltingIO.

1. Create a Bridge Secret

Go to your Secrets page in the SaltingIO dashboard. Click Add Secret and select Bridge as the type.

Paste the upstream API endpoint and add your credentials:

  • URL: https://api.openai.com/v1/chat/completions
  • Headers: Authorization: Bearer sk-your-secret-key

Salting encrypts your key with AES-256-GCM before storing it. Zero-knowledge --- not even the Salting team can read it.


2. Lock It to Your Domain

In your bridge settings, add your domain to the CORS Allowlist:

  • https://myapp.vercel.app
  • http://localhost:3000 (for development)

Now, even if someone finds your bridge URL, requests from unauthorized origins are rejected instantly.


3. Enable Rate Limiting

Salting bridges come with built-in rate limiting. Configure the limits in your dashboard to prevent abuse --- no middleware required.

This is something API routes don't give you out of the box. With Salting, it's a toggle.


4. Replace the API Call in Your Next.js Code

Drop the API route entirely. Call the Salting bridge URL directly from your client component.

Before (Insecure --- or Requires API Route)

// Client component calling your own API route
const res = await fetch('/api/chat', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    model: 'gpt-4o',
    messages: [{ role: 'user', content: prompt }]
  })
});

After (Secure --- No API Route Needed)

// Client component calling the Salting bridge directly
const res = await fetch('https://api.salting.io/r/your-bridge-uuid', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    model: 'gpt-4o',
    messages: [{ role: 'user', content: prompt }]
  })
});

const data = await res.json();
console.log(data.choices[0].message.content);

Same request body. Same response. But your API key never touches the browser, and you deleted an entire API route from your codebase.


Full Next.js Example: Secure Chat Component

Here's a complete React client component for Next.js that calls OpenAI through a Salting bridge:

'use client';

import { useState } from 'react';

const BRIDGE_URL = 'https://api.salting.io/r/your-bridge-uuid';

export default function Chat() {
  const [input, setInput] = useState('');
  const [reply, setReply] = useState('');
  const [loading, setLoading] = useState(false);

  const handleSubmit = async (e) => {
    e.preventDefault();
    setLoading(true);

    const res = await fetch(BRIDGE_URL, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        model: 'gpt-4o',
        messages: [{ role: 'user', content: input }]
      })
    });

    const data = await res.json();
    setReply(data.choices[0].message.content);
    setLoading(false);
  };

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input
          value={input}
          onChange={(e) => setInput(e.target.value)}
          placeholder="Ask anything..."
        />
        <button type="submit" disabled={loading}>
          {loading ? 'Thinking...' : 'Send'}
        </button>
      </form>
      {reply && <p>{reply}</p>}
    </div>
  );
}

No /api/chat route. No server-side code. No key in your environment. Just a secure bridge URL.


The Technical Deep-Dive: What Happens Under the Hood

When your Next.js app calls the Salting bridge URL:

1. Origin Check

Salting checks the Origin header against your CORS allowlist. If the origin doesn't match, the request is rejected before anything else happens.

2. Rate Limit Check

The request is checked against your configured rate limits. Abusive traffic is blocked automatically.

3. Secure Header Injection

Salting decrypts your stored API key and injects it into the Authorization header server-side. The key never appears in the browser request.

4. Upstream Call

The request is forwarded to the upstream API (e.g., OpenAI) with your credentials attached.

5. Clean Response

The API response is returned to your Next.js app. You can optionally use response transformation to extract only the fields you need using GJSON-style select queries.

Your key:

  • Never leaves the Salting server
  • Never appears in browser DevTools
  • Never gets committed to your repo

Track Your API Usage

One advantage of routing requests through Salting: you get visibility.

The SaltingIO Dashboard shows request logs for your bridges, so you can track how your API is being used. Combine this with CORS enforcement and rate limiting, and you have a full security + observability layer without writing any infrastructure code.

You can also use the Playground tab to test your bridge in real-time --- send requests, inspect responses, and validate your setup before deploying.


Pro Tip: Use Template Variables for Dynamic Endpoints

If your API calls use dynamic parameters (like a city name or stock ticker), you don't need to hardcode them into the bridge.

Set up a template variable in your bridge URL:

https://api.weatherapi.com/v1/current.json?key=SECRET&q={{city}}

Then call it from Next.js with the value as a query parameter:

const res = await fetch('https://api.salting.io/r/your-bridge-uuid?city=London');
const data = await res.json();

Salting substitutes {{city}} with London before forwarding the request. Your key stays hidden, and your bridge stays flexible.


Conclusion

You don't need API routes, serverless functions, or a custom backend to secure API keys in Next.js.

With SaltingIO, you get:

  • AES-256-GCM encrypted key storage with zero-knowledge architecture
  • CORS enforcement to lock your bridge to your domain
  • Built-in rate limiting without middleware or configuration
  • Usage tracking through the dashboard
  • Template variables for dynamic API calls
  • Zero infrastructure to deploy or maintain

Stop writing proxy routes. Start shipping secure apps.


Secure your first API key for free on SaltingIO →