Major update to our Free Plan: now with 1 GB of Postgres storage per project, 100 projects included
/AI Gateway/Authentication

AI Gateway authentication

How Neon credentials work with AI Gateway

AI Gateway uses Neon bearer credentials, the same scoped-credential system as Object Storage: one credential API mints branch-scoped tokens that differ by scope (AI Gateway uses ai_gateway:invoke). No provider API keys are needed.

Creating a credential

A credential must include the ai_gateway:invoke scope.

Create a credential with the Neon CLI:

neon credentials create --scope ai_gateway:invoke --name my-app-credential

The api_token is printed once; set it as NEON_AI_GATEWAY_TOKEN. Run it in a directory linked to your project, or pass --project-id and --branch.

Pull credentials with neon

For local development, neon env pull writes your AI Gateway credentials to your .env file automatically, with no manual copy-paste from the API response:

neon env pull --file .env

This populates NEON_AI_GATEWAY_TOKEN and NEON_AI_GATEWAY_BASE_URL for the current branch alongside your database connection string. Running neon config apply or neon deploy also auto-pulls credentials after a successful apply. To check current credential status:

neon config status

For production deployments, use the API-based workflow to create named credentials. expires_at is accepted but not currently enforced. Revoke credentials explicitly instead of relying on expiry.

Using your credential

Pass your credential as a bearer token on every request:

Authorization: Bearer <your-credential>

When using an AI SDK, set this as the apiKey parameter:

import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.NEON_AI_GATEWAY_TOKEN,
  baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`,
});

Environment variables

Neon provides two gateway env vars. NEON_AI_GATEWAY_BASE_URL is the bare branch host, so you append the dialect path yourself when configuring an SDK.

VariableValue
NEON_AI_GATEWAY_TOKENBearer token (nt_live_...)
NEON_AI_GATEWAY_BASE_URLBare branch host: https://<branch-host>, with no path. Append the dialect path yourself

Append the dialect path for the endpoint you need:

NEON_AI_GATEWAY_BASE_URL + /v1            → chat completions (all providers)
NEON_AI_GATEWAY_BASE_URL + /openai/v1     → OpenAI Responses API
NEON_AI_GATEWAY_BASE_URL + /anthropic     → Anthropic Messages API
NEON_AI_GATEWAY_BASE_URL + /gemini        → Gemini generateContent API

The Anthropic and Gemini values are SDK base URLs: the Anthropic SDK appends /v1/messages and google-genai appends /v1beta/models/..., so don't add those segments yourself. Calling either endpoint directly takes the full path, /anthropic/v1/messages or /gemini/v1beta/models/<model>:<action>.

Each inference dialect is also reachable at a longer /ai-gateway/<dialect>/v1 path (e.g. /ai-gateway/mlflow/v1 for chat completions, /ai-gateway/openai/v1 for Responses, /ai-gateway/anthropic/v1 for Anthropic Messages, /ai-gateway/gemini for Gemini). Both forms behave identically and neither is deprecated, but the shorter paths are what the docs and SDKs use. The model list is the exception: it has only GET /v1/models, with no /ai-gateway/... form. See Shorter paths for the full mapping.

To use an OpenAI SDK, set its apiKey and baseURL from these variables (see the examples below).

Credentials in Neon Functions

When your code runs inside Neon Functions, both gateway env vars are injected automatically. No credential creation step required:

VariableValue
NEON_AI_GATEWAY_TOKENBearer token for the AI Gateway
NEON_AI_GATEWAY_BASE_URLBranch gateway host with https:// prefix, no path

See Environment variables for the full list of variables Neon injects into a function.

Configure an OpenAI SDK by setting apiKey and baseURL from these variables. Use the OpenAI Responses dialect for responses.create():

import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.NEON_AI_GATEWAY_TOKEN,
  baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/openai/v1`,
});

const response = await client.responses.create({
  model: 'gpt-5-mini',
  input: 'What is Neon?',
});

For the chat completions endpoint, point the base URL at /v1 instead:

import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.NEON_AI_GATEWAY_TOKEN,
  baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`,
});

How branch binding works

Each credential is tied to the branch it was created on. It's valid for:

  • That branch (the anchor branch)
  • Any branch descended from it: preview branches, feature branches, CI branches

It's not valid for branches outside that lineage.

This means a credential created on your main branch works in all branches that were forked from main. A credential created on a feature branch only works within that feature branch's descendants.

main  ──── credential valid here
  └── preview/feature-x  ──── and here
        └── preview/sub-branch  ──── and here
staging  ──── credential NOT valid here (different lineage)

This design lets you use a single credential across your entire development workflow (local dev, preview deployments, and CI) without creating separate credentials for each environment.

Common auth errors

ErrorCauseFix
401 UnauthorizedMissing or invalid credentialCheck that NEON_AI_GATEWAY_TOKEN is set and contains the full token
403 ForbiddenCredential lacks ai_gateway:invoke scopeRecreate the credential with the correct scope
403 ForbiddenBranch not in credential lineageUse a credential created on this branch or an ancestor branch. The gateway returns: credential not authorized for this branch
503 Service UnavailableAuth store temporarily unavailableRetry the request

Rotating credentials

To rotate a credential in place with the Neon CLI, run neon credentials rotate <token_id> (find the id with neon credentials list). The token_id stays the same and a new api_token is minted, so update NEON_AI_GATEWAY_TOKEN with it. Otherwise, create a new credential, update your environment variables, then revoke the old one.

The Console's Connect dialog can rotate a credential (AI Gateway tab > Rotate credential) but not revoke one. To revoke, use the Neon CLI (neon credentials revoke <token_id>) or the API:

curl -X DELETE "https://console.neon.tech/api/v2/projects/{project_id}/branches/{branch_id}/credentials/{token_id}" \
  -H "Authorization: Bearer $NEON_API_KEY"

Or with the Neon CLI:

neon credentials revoke <token_id>

Need help?

Join our Discord Server to ask questions or see what others are doing with Neon. For paid plan support options, see Support.

Was this page helpful?
Edit on GitHub