DEV Community

Gumbo Sveins
Gumbo Sveins

Posted on

Polar Access Tokens Do Not Belong in NEXT_PUBLIC_

Polar Access Tokens Do Not Belong in NEXT_PUBLIC_

If a Polar organization access token ever lands in a variable that starts with NEXT_PUBLIC_, it ships to the browser. Anyone who opens DevTools can copy it. With that token they can read your products, create checkouts in your name, or worse depending on the scopes you granted.

This is not a Polar quirk. It is how Next.js works. NEXT_PUBLIC_ means "bundle this into client JavaScript." Secrets belong only on the server.

The safe split

Keep three buckets separate:

  1. Server only tokens. Polar organization access tokens, webhook secrets, and any API key that can create or mutate money related resources. Put these in Vercel Production and Preview without the NEXT_PUBLIC_ prefix.
  2. Public product identifiers. Checkout links, product slugs, and publishable ids that are meant to be shared. Those can live in the client.
  3. Return and success URLs. These are navigation aids, not credentials.

A minimal server route that creates a checkout should read the token only inside a Route Handler or Server Action:

import { Polar } from "@polar-sh/sdk"

export async function POST() {
  const accessToken = process.env.POLAR_ACCESS_TOKEN
  if (!accessToken) {
    return Response.json({ error: "Missing Polar token" }, { status: 500 })
  }

  const polar = new Polar({ accessToken })
  // create checkout on the server, return only the checkout URL to the client
  return Response.json({ url: "https://example.com/checkout" })
}
Enter fullscreen mode Exit fullscreen mode

The browser never sees POLAR_ACCESS_TOKEN. It only receives a checkout URL you already created.

How tokens leak in practice

Common paths that put a secret in the client:

  • Renaming POLAR_ACCESS_TOKEN to NEXT_PUBLIC_POLAR_ACCESS_TOKEN "so the pricing page can call Polar."
  • Importing a server module that reads the token into a Client Component.
  • Logging the full process.env object into an error reporter that also runs in the browser.
  • Copying a .env.local line into a GitHub Actions workflow that prints the env dump on failure.

Each of these turns a private key into a public one. Polar cannot tell that you meant it to stay private once the browser has it.

Check Vercel before you merge

Before you promote a branch:

  1. Open the project Environment Variables list.
  2. Confirm every Polar token and webhook secret has no NEXT_PUBLIC_ prefix.
  3. Confirm Production and Preview both have the server token, and Development has a sandbox token if you use one.
  4. Confirm nothing named like a secret is marked for the browser.

If you prefer an offline checklist before you touch the dashboard, that is what Deploy Guard is for. It is a printable env matrix so you catch prefix mistakes before merge.

Soft sell

If you want a longer go live checklist for Next.js on Vercel with Polar checkout and webhook notes, the Next.js / Vercel Production Launch Kit is $19.

If you mainly need the offline env matrix, Deploy Guard is $12.

More in this series

Top comments (0)