Choosing a Credential Mode

Security Overview | mTLS | Bundle Signing | Credential Encryption | Credential Modes

This guide explains the ways Axemere Gateway can hold and deliver your AI provider API keys, and how to pick the right one for your deployment.

Table of Contents


Quick Answer

I want...Use
Simplest setup: add key in console and goinline
My API key to never leave my own infrastructurealias
Each of my users to use their own org key (via header)byok
Claude CLI users to route through the gateway with their own subscriptionoauth passthrough
Each developer to use their own API key via the gatewaybyok_header passthrough

The Modes

inline — Axemere manages your key

Supported gateways: Self-hosted and managed.

You paste your API key into the Axemere console. The control plane protects it with envelope encryption (AES-256-GCM under a per-credential key wrapped by Cloud KMS) and stores it in the database. When the gateway processes a request, it receives the decrypted key over an mTLS-authenticated channel and uses it to authenticate the upstream call.

Your key is encrypted at rest. A database backup or SQL injection attack yields only ciphertext; the encryption key is never in the database.

See: Credential Encryption for the full mechanism.

Zero-config on the gateway. No environment variables to set, no files to manage. Add the key in the console; the gateway starts routing immediately.

Tradeoff: Your API key exists in the Axemere control plane database (encrypted) and briefly in gateway memory during active requests. If your security policy requires that API keys never leave your infrastructure, use alias instead.


alias — Your key stays on your gateway host

Supported gateways: Self-hosted only. This mode requires setting an environment variable on a host you control; Axemere's managed gateway infrastructure isn't a host you have shell access to, so there's nowhere to set it.

You set your API key as an environment variable on the gateway host and register only the variable name with the control plane. The control plane never sees the key itself, only a pointer.

Console: name = OPENAI_API_KEY
Gateway host: export OPENAI_API_KEY=sk-...

At request time, the gateway reads the environment variable and uses the result. The control plane has no access to the secret value, ever.

Your key never leaves your infrastructure. Appropriate for organizations whose security policy prohibits sending API keys to external services.

Tradeoff: You must set the environment variable on every gateway host and restart (or trigger a reload) when the variable is updated. The zero-config console experience does not apply: adding a key in the console without setting the env var results in a 403 with a diagnostic message.


Passthrough — the gateway forwards a credential it never stores

Supported gateways: Self-hosted and managed, for every mode below.

Three modes never send a real secret to Axemere at all: the gateway forwards a credential it received from the client, unchanged, straight to the provider. What differs between them is whose credential it is and how the gateway recognizes it. This matters for one more reason beyond storage: passthrough is also the closest thing to how most teams already call AI providers today, directly with an API key in their own code. Turning on BYOK or OAuth passthrough for a provider lets that existing code keep working unmodified behind the gateway (policy and audit apply immediately), and a team can migrate to inline or alias later without a second migration on the client side.

One nuance to know up front: for some providers, the gateway can't tell a BYOK key and an OAuth subscription token apart from the request alone. See Combined Passthrough below for what that means in practice.

BYOK — the caller supplies the key

byok — header-based, provider-agnostic

No key is stored anywhere. Each API call includes the key in the request via the X-MVGC-BYOK-Secret header. The gateway applies policy and audit but does not store or inject credentials.

This is appropriate when:

  • Each caller (user, tenant, application) has their own API key
  • You want the gateway purely as a policy and audit layer
  • You cannot store keys in any external system

Cost: Billed at the standard provider API rate. The gateway estimates token usage and enforces org budget limits.

Tradeoff: Every caller must supply their key on every request. Not compatible with transparent proxy mode (an unmodified AI SDK doesn't know to add this header) or zero-config SDK setup. Rotating a key means finding and updating it everywhere your organization put it, every developer's environment, every CI secret, every service config, since Axemere never stored it in the first place. That operational cost is exactly what inline and alias remove: rotation becomes one change in one place instead of a hunt across every caller.

byok_header — native header, per provider

The client sends their own AI provider API key in the provider's native authentication header instead of Axemere's own header. The gateway forwards the key in that header to the upstream. No key is stored on the gateway.

ProviderHeader
AnthropicAuthorization: Bearer sk-ant-...
OpenAIAuthorization: Bearer sk-...
Geminix-goog-api-key: AIzaSy-...
Azure OpenAIapi-key: <key>

Because the header is the provider's own, this mode does work with transparent proxy mode: an unmodified SDK already sends its own key this way.

Cost: Billed at the standard provider API rate. The gateway estimates token usage and enforces org budget limits.

Tradeoff: Every developer must supply their own API key on every request. The gateway audits all usage but cannot prevent a developer from calling the provider directly (bypassing the gateway). Rotation carries the same cost byok does: finding and updating the key everywhere your organization put it, rather than the one-place change inline/alias gives you.

Enabled per provider via the credential-byok-{provider} addon. See: Enabling BYOK passthrough for a provider.

OAuth — the caller supplies their provider subscription

The client sends their AI provider subscription OAuth token in the Authorization: Bearer header. The gateway forwards it unchanged to the provider. No key is stored on the gateway. Like byok_header, this uses the provider's own standard header, so it works with transparent proxy mode too.

This is the correct mode for Claude CLI users who have a paid Claude subscription: the Claude CLI automatically sends its subscription token to ANTHROPIC_BASE_URL when ANTHROPIC_API_KEY is not set in the environment. Claude CLI is the example here because it's the common case, but any client with a similar "send a subscription bearer token to a configurable base URL" mechanism can use this mode the same way, not just Claude CLI specifically.

Cost: Estimated at market API rates using provider pricing data. These estimated costs count toward project budgets and alert thresholds the same way API key spend does. Your actual subscription charges with the provider are determined by your agreement with them directly.

Tradeoff: Cost figures are estimates at market API rates: they reflect what equivalent API calls would cost, not what the customer's subscription actually charges. Org policy enforces rate limits, budgets (against the estimated cost), and allow/deny rules.

Enabled per provider via the credential-oauth-{provider} addon. See: Enabling OAuth passthrough for Claude CLI.

Combined Passthrough — when the provider can't tell OAuth from BYOK

oauth and byok_header are independent modes because for most providers they arrive on different signals and don't collide. For Anthropic and OpenAI specifically, both signals arrive as Authorization: Bearer <value>, but the gateway can still tell them apart heuristically by the token's own shape: a value starting with the provider's API-key prefix (sk-ant- for Anthropic, sk- for OpenAI) is treated as byok_header; anything else is treated as an oauth subscription token. That's why Anthropic and OpenAI get the same two independently-toggleable credential-oauth-{provider} / credential-byok-{provider} addons every other discriminable provider gets, rather than a combined one.

For providers with no such prefix convention to key off of — currently Cohere, DeepSeek, Mistral, xAI, Qwen, Moonshot, MiniMax, Perplexity, StepFun, Zhipu, NVIDIA NIM, Upstage, Together, Fireworks, OpenRouter, and Groq — an OAuth subscription token and a BYOK API key are genuinely indistinguishable from the request alone, so the gateway can't offer oauth and byok_header as two independently-toggleable addons for those providers. It exposes one instead: Combined Passthrough, enabled via the credential-passthrough-{provider} addon.

With Combined Passthrough enabled, any non-empty Authorization: Bearer value the client sends takes priority over the org's stored credential (inline/alias) and is forwarded upstream verbatim; the gateway has no way to verify whether it's a real OAuth token, a real API key, or anything else.

Watch for SDK placeholder keys. Some SDKs require a non-empty API key env var even when you intend the gateway to inject your stored inline/alias credential, so setups commonly set it to a placeholder value like "placeholder" or "unused". If Combined Passthrough is enabled for that provider, the placeholder is treated as a real client-supplied credential: it's forwarded to the provider (which rejects it with a genuine 401); your inline/alias credential is silently never used, and nothing in the console or logs flags what happened. If you want the gateway to always use your stored credential for a provider, leave Combined Passthrough disabled for it.


Comparison

inlinealiasoauthbyokbyok_header
API key stored by AxemereYes (encrypted)NoNoNoNo
Setup required on gateway hostNoneSet env varEnable addonNoneEnable addon
Zero-config after console setupYesNoNoNoNo
Key leaves customer infrastructureYes (to Axemere CP)NoNoNoNo
Works with transparent proxy modeYesYes (if env var is set)YesNoYes
Key rotationUpdate in consoleUpdate env var on your gateway hostVia your provider accountUpdate it in your own source/config, everywhere it's usedUpdate it in your own source/config, everywhere it's used
Cost trackingProvider rateProvider rateProvider rate (estimated, see OAuth)Provider rateProvider rate
Recommended for managed gatewaysYes—Claude CLI users (see note above)——
Recommended for self-hostedYesYesClaude CLI users—Developer BYOK
Per-caller isolation override———YesYes

Setup Examples

Setting up an inline credential

Gateways: Self-hosted and managed.

  1. In the Axemere console, go to Credentials → Add Credential
  2. Select your provider (e.g. OpenAI)
  3. Choose "Axemere manages your key" (inline mode)
  4. Paste your API key
  5. Click Save

The console will display your gateway's proxy URL immediately:

OPENAI_BASE_URL=https://<gateway>/proxy/openai

No changes needed on the gateway host.


Setting up an alias credential

Gateways: Self-hosted only.

  1. On your gateway host, set the environment variable:

    export OPENAI_API_KEY=sk-...
    

    For Kubernetes deployments, add it as a Secret and reference it in the Deployment env:

    env:
      - name: OPENAI_API_KEY
        valueFrom:
          secretKeyRef:
            name: provider-keys
            key: openai-api-key
    
  2. In the Axemere console, go to Credentials → Add Credential

  3. Select your provider

  4. Choose "Keep your key local" (alias mode)

  5. Enter the environment variable name: OPENAI_API_KEY

  6. Click Save

If the variable is not set on the gateway host, requests will fail with a 403 and a diagnostic message telling you exactly which variable is missing.


Using byok in a request

Gateways: Self-hosted and managed.

Include X-MVGC-BYOK-Secret in your HTTP request headers. This works from any language or tool that can make an HTTP request, no SDK required:

curl https://<gateway>/v1/chat/completions \
-H "X-MVGC-Org-ID: org-123" \
-H "X-MVGC-Workload-ID: default" \
-H "X-MVGC-Target-Host: api.openai.com" \
-H "X-MVGC-BYOK-Secret: sk-..." \
-H "Content-Type: application/json" \
-d '{"model":"gpt-4o-mini","messages":[...]}'

Or use the official Axemere SDK for your language, which handles the header wiring for you:

cfg := gateway.NewConfig(
  gateway.WithGatewayURL("https://<gateway>"),
  gateway.WithWorkloadID("default"),
  gateway.WithProviderAPIKey("sk-..."),
)
client := gateway.NewClient(cfg)

resp, err := client.Execute(context.Background(), gateway.ExecuteRequest{
  Provider: "openai",
  Model:    "gpt-4o-mini",
  Messages: []gateway.Message{
      {Role: "user", Content: "Hello"},
  },
})

No credential record is needed for byok; the gateway uses the supplied key directly.


Enabling OAuth passthrough for Claude CLI

Gateways: Self-hosted and managed.

This example enables OAuth passthrough for Anthropic so Claude CLI users can route through the gateway using their Claude subscription.

  1. In the Axemere console, go to Providers.
  2. Find Anthropic and switch on OAuth Passthrough.
  3. Share the gateway proxy URL and the pclaude setup with your users. See: Claude CLI Setup for the user-facing instructions.

To automate this (for example, as part of an org-provisioning script) instead of clicking the toggle, the same change is available via the admin API:

curl -s -X POST http://localhost:7080/v1/orgs/ORG_ID/addons/credential-oauth-anthropic/enable \
-H "MVGC-Admin-Token: ${MVGC_ADMIN_TOKEN}"

Enabling BYOK passthrough for a provider

Gateways: Self-hosted and managed.

This example enables BYOK passthrough for OpenAI so developers can supply their own OpenAI API key via the gateway.

  1. In the Axemere console, go to Providers.
  2. Find OpenAI and switch on BYOK.

To automate this instead of clicking the toggle, the same change is available via the admin API:

curl -s -X POST http://localhost:7080/v1/orgs/ORG_ID/addons/credential-byok-openai/enable \
-H "MVGC-Admin-Token: ${MVGC_ADMIN_TOKEN}"

Developers then include their key in the Authorization header of their requests:

curl https://gateway/proxy/openai/... \
  -H "Authorization: Bearer sk-my-own-openai-key" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-4o-mini","messages":[...]}'

For Gemini, the key goes in x-goog-api-key. For Azure OpenAI, use api-key.


Credential Scope and Distribution

Every credential has two independent dimensions: scope (which requests it resolves for) and distribution (which gateway nodes can access it). Understanding how they interact prevents silent failure modes.

See: the Credentials page in the console is where scope and distribution are actually configured; this section explains what the options mean.

Scope: which requests resolve this credential

ScopeBehaviour
Org DefaultFallback for any request that doesn't match a more specific scope. One default per provider + mode combination.
WorkloadResolves only for requests from the specified workloads. Overrides the org default for those workloads.
ProjectResolves only for requests attributed to the specified projects. Overrides the org default for those projects.

Scope determines credential selection: the control plane evaluates it before the request reaches the gateway node.

Distribution: which gateway nodes can use it

DistributionBehaviour
Org-wideAll registered gateway nodes in the org receive this credential.
Node-scopedOnly the nodes you explicitly assign can decrypt and use this credential.

Distribution determines credential delivery: which nodes the control plane pushes the credential to.

Edge case: Org Default with Node-scoped distribution

This combination is valid but carries a significant risk: the org default credential exists and will be selected by the CP for any unscoped request, but only the assigned nodes can actually use it. Requests arriving on an unassigned node will fail to resolve a credential; there is no fallback.

Yes

No

Request arrives

CP selects org default credential

Node assigned?

Key delivered - request succeeds

No key available - request fails

When it makes sense: Staged rollout of a new key: you assign it to a canary node first, verify it works, then expand assignment. During the rollout window, unassigned nodes continue using whatever they had before (or fail if no prior default existed).

When it's a problem: If this is your only org default for a provider and you want all traffic to route through it, node-scoped distribution leaves unassigned nodes with no credential at all.

The Axemere console shows an amber warning when you attempt to create an org default credential with node-scoped distribution, prompting you to consider org-wide distribution if full coverage is the intent.


Rotating a Credential

inline: Update the key in the Axemere console. The change propagates to all gateways within the cache TTL (up to 60 seconds for self-hosted; near-instant for managed gateways via the streaming config channel).

alias: Update the environment variable on the gateway host. For long-running processes, either restart the gateway or trigger a config reload. If using Kubernetes, update the Secret and roll the Deployment.

byok / byok_header: There's no rotation Axemere performs, because Axemere never stores this key. Rotating a BYOK-family credential means finding and updating it everywhere your own organization put it: every developer's environment, every CI secret store, every service config that sends the header. That's entirely on your own key-management practices, and it's exactly the operational risk inline and alias are built to remove: with either of those, rotation is one change in one place, not a hunt across every caller.

oauth: Rotation happens on the provider's side (revoking or refreshing the subscription token via your provider account), not through Axemere.


Troubleshooting

All of the following are 403 Forbidden responses from the gateway with a specific reason explaining what happened, unless noted otherwise. They apply to both self-hosted and managed gateways unless called out.

403: credential mode "oauth" (or "byok_header" / "passthrough") requires a client-supplied auth header that was not found

The passthrough/OAuth/BYOK-header addon is enabled for this provider but the client's request arrived without the expected header. The most common cause with Claude CLI specifically: ANTHROPIC_API_KEY is set in the environment, so the CLI uses that key instead of sending the subscription token, but it isn't forwarded in passthrough mode. Unset ANTHROPIC_API_KEY when using pclaude. See: Claude CLI Setup.

403: no credential configured for <provider> (<host>)

No credential exists for this provider in your org at all. The response tells you both ways to fix it: add an API key in the console for mode:inline, or set the environment variable and register it as mode:alias.

403: credential <id> (mode:inline) has an empty stored secret

The credential record exists but has no secret stored. Re-add the API key in the console by editing the credential.

403: credential <id> could not provide a secret for <host>

Covers mode:alias specifically: the credential is registered but the gateway couldn't resolve a value. Self-hosted only. Ensure the environment variable is set on this gateway's host and the gateway has been restarted or reloaded since. If the credential is actually mode:inline, re-add the API key in the console instead.

401 from the upstream provider (not from the gateway)

If this occurs with mode:alias, the environment variable is set but contains an invalid or expired key. Verify the key value and update it. If Combined Passthrough is enabled for this provider, check whether a client is sending an SDK placeholder value (e.g. "placeholder", "unused") instead of a real credential: it gets forwarded verbatim and rejected by the provider with a genuine 401, silently skipping your stored inline/alias credential with no console or log indication that this happened. See: Combined Passthrough.

Stored credential is being ignored even though it's configured correctly

Check whether Combined Passthrough is enabled for this provider (credential-passthrough-{provider} addon, shown as "Combined Passthrough" in the console). If enabled, any non-empty Authorization: Bearer header from the client is forwarded upstream in place of your stored credential. Disable the addon if you want the gateway to always use the stored inline/alias key for this provider.