Supabase · API key location

How to find your Supabase API keys

Find Supabase publishable, secret, anon, and service_role keys in the current dashboard, then choose the right key for browser or server code.

Published · Updated · Reviewed by SafeForProd

Open your Supabase project and use the Connect dialog for the usual client setup, or go to Settings → API Keys when you need a specific key. Current projects use a publishable key for browsers and a secret key for trusted backends. Older projects may also show the legacy anon and service_role pair.

The important part is not merely finding a value. It is copying the correct key class into the correct runtime.

The shortest path in the current dashboard

  1. Sign in to Supabase and open the intended project.
  2. Use Connect when you want the normal connection details for a framework or client library.
  3. Use Settings → API Keys when you need to see or manage a specific API key.
  4. In the publishable and secret keys tab, copy a publishable key for browser, mobile, desktop, CLI, or other public-client use.
  5. Copy a secret key only for a server, worker, secured backend API, or other trusted server environment.
  6. If the project still uses legacy keys, open the legacy API keys tab. The anon key is the client-side key; service_role is the privileged server-side key.

Supabase documents both locations in its current API-key guide and provides the legacy-to-current mapping in its migration guide.

Older tutorials may say Settings → API → Project API keys. The current documentation calls the destination Settings → API Keys. When a tutorial and the dashboard differ, use the dashboard labels and current Supabase documentation as the source of truth.

Which key should you copy?

Your code runs inCurrent keyLegacy equivalentSafe to publish?
Browser, mobile app, desktop app, CLI, public sourcePublishable: sb_publishable_...anon JWTYes
Server, worker, trusted backend API, admin jobSecret: sb_secret_...service_role JWTNo

Publishable and legacy anon keys have low privileges. Requests made without a signed-in user use the anon Postgres role; signed-in users use the authenticated role and their own access token. Row Level Security and Postgres grants are the actual data boundary.

Secret and legacy service_role keys authorize requests with elevated access and bypass RLS. They are not interchangeable with a browser key.

For a fuller behavior comparison, read Supabase API keys: publishable vs secret, anon vs service_role.

A normal browser configuration

This Vite example uses only values intended for a public client:

import { createClient } from '@supabase/supabase-js'

const supabase = createClient(
  import.meta.env.VITE_SUPABASE_URL,
  import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY,
)

Vite places variables prefixed with VITE_ in the client bundle. That is acceptable for the Supabase project URL and a publishable key. It is not acceptable for a secret or service_role key.

Variable names are conventions, not access controls. Calling a variable SUPABASE_SECRET_KEY does not keep it secret if the build tool includes it in browser JavaScript.

A normal server configuration

A trusted backend can read its secret key from the hosting platform’s secret store or a server-only environment variable:

import { createClient } from '@supabase/supabase-js'

const admin = createClient(
  process.env.SUPABASE_URL!,
  process.env.SUPABASE_SECRET_KEY!,
  {
    auth: {
      persistSession: false,
      autoRefreshToken: false,
      detectSessionInUrl: false,
    },
  },
)

The file containing this code must remain server-only. Do not import it into a shared module that a framework may bundle for the browser.

Supabase recommends a separate named secret key for each backend component where practical. That limits the rotation scope if one component is compromised.

Check these four things before saving the value

1. Confirm the project

Staging and production often look similar. Check the project name and reference before copying a key, and keep each environment’s URL and key together. A staging frontend pointed at the production project is an environment-boundary problem even when the key class is correct.

2. Confirm the prefix or dashboard label

  • sb_publishable_...: current client key.
  • sb_secret_...: current privileged server key.
  • eyJ...: a JWT-shaped value that may be a legacy anon key, a legacy service_role key, or another JWT. The shape alone does not establish the role.

For legacy JWT keys, use the dashboard label rather than guessing from the token text.

3. Confirm the runtime

Ask where the final value executes, not where the source file lives. Code in a server-rendered framework can cross the server/client boundary through shared imports, hydration, generated configuration, or a public environment-variable prefix.

4. Confirm the authorization model

A publishable key being visible is expected. It does not prove that RLS is enabled or correct. Before launch, review grants and policies for every exposed table and test the intended roles with owner-authorized accounts.

What if the key is already visible in JavaScript?

First classify it.

  • A confirmed publishable or legacy anon key in browser code is normally Informational. Do not rotate it merely because it is public.
  • A value that appears privileged but cannot be classified from public evidence is Needs verification. Check its dashboard label without using the key.
  • A confirmed secret or legacy service_role key in a public bundle is Confirmed exposure. Remove the root cause and follow the Supabase service-role key exposure runbook.

Do not paste real values into search engines, chat tools, issue trackers, or screenshots. Redact all but a short prefix when recording evidence.

What the free scan can tell you

The free scan can identify a Supabase project URL and key pattern in referenced public assets, classify an obvious publishable key as expected public configuration, and flag a privileged-looking value for owner verification. It does not use the key, call Supabase, query tables, or test RLS.

What requires source or human review

Choosing the correct key prevents a privileged credential from reaching the browser. It does not establish whether signed-in users can cross tenant boundaries, change protected fields, invoke unsafe functions, or reach rows outside their account.

Those questions require migrations, policies, application source, and bounded testing with explicit authorization. Use the Supabase RLS security checklist as an owner-run starting point.

Limitations

Supabase dashboard labels and migration behavior change over time. This guide reflects the current Supabase documentation reviewed on 2026-07-27. Self-hosted Supabase can use a different key-management flow. Never infer privileges from a copied JWT’s appearance alone.

Revision history

  • 2026-07-27: Initial draft based on the current Supabase API-key and migration documentation.