Authentication

The proxy handles two independent auth directions: inbound — validating tokens from MCP clients — and outbound — attaching credentials to upstream API requests.

Inbound auth

Inbound auth protects your MCP endpoint. Configure it per-group:

groups:
  - name: default
    endpoint: /mcp
    upstreams: [kraken]
    inbound_auth:
      strategy: jwt
      jwt:
        issuer: https://auth.example.com
        jwks_url: https://auth.example.com/.well-known/jwks.json
        audience: mcp-anything

JWT

Validates OIDC JWTs. JWKS keys are auto-rotated on expiry.

inbound_auth:
  strategy: jwt
  jwt:
    issuer: https://auth.example.com
    jwks_url: https://auth.example.com/.well-known/jwks.json
    audience: my-mcp-proxy          # optional, validates aud claim
    algorithms: [RS256, ES256]      # optional, defaults to RS256

Token introspection

Validates tokens via an OIDC introspection endpoint. Suitable for opaque tokens.

inbound_auth:
  strategy: introspection
  introspection:
    endpoint: https://auth.example.com/oauth/introspect
    client_id: ${INTROSPECTION_CLIENT_ID}
    client_secret: ${INTROSPECTION_CLIENT_SECRET}

API key

Validates a static key from a request header.

inbound_auth:
  strategy: apikey
  apikey:
    header: X-API-Key
    value: ${API_KEY}

Lua

Custom validation logic in a Lua script. Receives the request headers and must return a boolean.

inbound_auth:
  strategy: lua
  lua:
    source: scripts/validate_token.lua
-- scripts/validate_token.lua
local token = headers["Authorization"]
if not token then return false end
-- custom validation logic
return token:sub(1, 7) == "Bearer " and #token > 20

JavaScript (Sobek)

Custom validation logic in a sandboxed ECMAScript runtime (Grafana Sobek). Receives the request headers as a plain object and must return a boolean.

inbound_auth:
  strategy: js
  js:
    source: scripts/validate_token.js
// scripts/validate_token.js
const token = headers["Authorization"] ?? "";
if (!token.startsWith("Bearer ")) return false;
// custom HMAC or structural check
return token.length > 20;

None

inbound_auth:
  strategy: none

No authentication. Use this for development or for public endpoints.

Outbound auth

Outbound auth injects credentials into requests the proxy makes to upstream APIs. Configure it per-upstream:

upstreams:
  - name: myapi
    type: http
    tool_prefix: api
    base_url: https://api.example.com
    openapi:
      source: https://api.example.com/openapi.yaml
    outbound_auth:
      strategy: oauth2_client_credentials
      oauth2_client_credentials:
        token_url: https://auth.example.com/oauth/token
        client_id: ${CLIENT_ID}
        client_secret: ${CLIENT_SECRET}
        scopes: [read:data, write:data]

Bearer token

Injects a static Bearer token from an environment variable.

outbound_auth:
  strategy: bearer
  bearer:
    token: ${API_TOKEN}

OAuth2 Client Credentials

Performs the OAuth2 CC flow and caches the token until it expires, then refreshes automatically.

outbound_auth:
  strategy: oauth2_client_credentials
  oauth2_client_credentials:
    token_url: https://auth.example.com/oauth/token
    client_id: ${CLIENT_ID}
    client_secret: ${CLIENT_SECRET}
    scopes: [read, write]

API key

Injects an API key as a header or query parameter.

outbound_auth:
  strategy: api_key
  api_key:
    header: X-API-Key        # or use: query: api_key
    value: ${UPSTREAM_KEY}

Lua

Custom token acquisition — useful for non-standard auth schemes.

outbound_auth:
  strategy: lua
  lua:
    source: scripts/get_token.lua

JavaScript (Sobek)

Token acquisition in a sandboxed ECMAScript runtime. The script must return a string that is used as the Authorization header value.

outbound_auth:
  strategy: js
  js:
    source: scripts/get_token.js
// scripts/get_token.js
const resp = ctx.fetch("https://auth.example.com/token", {
  method: "POST",
  body: JSON.stringify({ client_id: ctx.env.CLIENT_ID, client_secret: ctx.env.CLIENT_SECRET }),
  headers: { "Content-Type": "application/json" },
});
return "Bearer " + resp.json().access_token;

Per-operation bypass

Set x-mcp-auth-required: false on an operation via an overlay to skip outbound auth for that operation. Useful for public endpoints within an otherwise authenticated upstream.

- target: "$.paths[\"/public/status\"].get"
  update:
    x-mcp-auth-required: false

Secret references

All config fields that reference secrets use ${ENV_VAR} syntax. The proxy expands these at startup from the process environment. Secret values are never logged.

See also