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:
-
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. - Public product identifiers. Checkout links, product slugs, and publishable ids that are meant to be shared. Those can live in the client.
- 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" })
}
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_TOKENtoNEXT_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.envobject into an error reporter that also runs in the browser. - Copying a
.env.localline 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:
- Open the project Environment Variables list.
- Confirm every Polar token and webhook secret has no
NEXT_PUBLIC_prefix. - Confirm Production and Preview both have the server token, and Development has a sandbox token if you use one.
- 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.
Top comments (0)