Identify AI Consumers on AI Model traffic with Kong Identity

TL;DR

Create a Kong Identity auth server and client, then create an openid-connect AI Auth Strategy that references the auth server’s issuer, and an oauth AI Consumer whose custom_id matches the client’s token claim. Attach the AI Auth Strategy to an AI Model’s access.auth_strategies. Requests without a valid bearer token are rejected with a 401. Authenticated requests are proxied to the upstream model, and usage is attributed to the matched AI Consumer instead of an anonymous caller.

Prerequisites

This is a Konnect tutorial and requires a Konnect personal access token.

  1. Create a new personal access token by opening the Konnect PAT page and selecting Generate Token.

  2. Export your token to an environment variable:

    export KONNECT_TOKEN='YOUR_KONNECT_PAT'
  3. Run the AI Gateway quickstart script to automatically provision a control plane and data plane in Kong Konnect, and configure your environment:

    curl -Ls https://get.konghq.com/ai | bash -s -- -k $KONNECT_TOKEN 

This sets up a AI Gateway control plane named ai-quickstart, provisions a local data plane, and prints out the following environment variables export:

export AI_GATEWAY_ID=your-gateway-id
export KONNECT_TOKEN=$KONNECT_TOKEN
export KONNECT_CONTROL_PLANE_NAME=ai-quickstart
export KONNECT_CONTROL_PLANE_URL=https://us.api.konghq.com
export KONNECT_PROXY_URL='http://localhost:8000'

Copy and paste these into your terminal to configure your session.

This tutorial uses kongctl to manage Konnect resources programmatically. We recommend keeping kongctl up to date with the latest version (1.15.1).

  1. Install kongctl from developer.konghq.com/kongctl.
  2. Verify the installation:

    kongctl version
  1. Create an OpenAI account.
  2. Get an API key.
  3. Export the API key as a variable:
     export OPENAI_API_KEY="<YOUR_OPENAI_API_KEY>"
     export OPENAI_AUTH_HEADER="Bearer $OPENAI_API_KEY"

AI Model traffic can either use placeholder API keys or AI Consumer credentials to authenticate traffic.

A placeholder key satisfies a client SDK that insists on a non-empty API key value, but it doesn’t identify who’s calling. You can use placeholders for testing, but we strongly recommend using AI Consumers and consumer credentials in a production environment.

AI Consumers with consumer credentials allow you to:

  • Attribute usage per-consumer
  • Apply per-caller policies
  • Revoke access for one caller without revoking the shared placeholder for everyone

Additionally, in most production environments, consumers should not have access to API keys themselves for security reasons.

This how-to uses an AI Consumer backed by a real credential (here, an OIDC bearer token) to give every request an identity that usage, rate limiting, and audit logs can use.

Create an auth server in Kong Identity

Before you can configure authentication, you must first create an auth server in Kong Identity. We recommend creating different auth servers for different environments or subsidiaries. The auth server name is unique per each organization and each Konnect region.

Create an auth server using the /v1/auth-servers endpoint:

_response=$(curl -X POST "https://us.api.konghq.com/v1/auth-servers" \
     --no-progress-meter --fail-with-body  \
     -H "Authorization: Bearer $KONNECT_TOKEN"\
     -H "Content-Type: application/json" \
     --json '{
       "name": "Appointments Dev",
       "audience": "http://myhttpbin.dev",
       "description": "Auth server for the Appointment dev environment"
     }')

Export the env variables:

export AUTH_SERVER_ID=$(echo "$_response" | jq -r ".id")
export ISSUER_URL=$(echo "$_response" | jq -r ".issuer")

Configure the auth server with scopes

Configure a scope in your auth server using the /v1/auth-servers/$AUTH_SERVER_ID/scopes endpoint:

SCOPE_ID=$(curl -X POST "https://us.api.konghq.com/v1/auth-servers/$AUTH_SERVER_ID/scopes" \
     --no-progress-meter --fail-with-body  \
     -H "Authorization: Bearer $KONNECT_TOKEN"\
     -H "Content-Type: application/json" \
     --json '{
       "name": "my-scope",
       "description": "Scope to test Kong Identity",
       "default": false,
       "include_in_metadata": false,
       "enabled": true
     }' | jq -r ".id"
)

Configure the auth server with custom claims

Configure a custom claim using the /v1/auth-servers/$AUTH_SERVER_ID/claims endpoint:

curl -X POST "https://us.api.konghq.com/v1/auth-servers/$AUTH_SERVER_ID/claims" \
     --no-progress-meter --fail-with-body  \
     -H "Authorization: Bearer $KONNECT_TOKEN"\
     -H "Content-Type: application/json" \
     --json '{
       "name": "test-claim",
       "value": "test",
       "include_in_token": true,
       "include_in_all_scopes": false,
       "include_in_scopes": [
         "'$SCOPE_ID'"
       ],
       "enabled": true
     }'

You can also configure dynamic custom claims with dynamic claim templating to generate claims during runtime.

Create a client in the auth server

The client is the machine-to-machine credential. In this tutorial, Konnect will autogenerate the client ID and secret, but you can alternatively specify one yourself.

Configure the client using the /v1/auth-servers/$AUTH_SERVER_ID/clients endpoint:

_response=$(curl -X POST "https://us.api.konghq.com/v1/auth-servers/$AUTH_SERVER_ID/clients" \
     --no-progress-meter --fail-with-body  \
     -H "Authorization: Bearer $KONNECT_TOKEN"\
     -H "Content-Type: application/json" \
     --json '{
       "name": "Client",
       "grant_types": [
         "client_credentials"
       ],
       "allow_all_scopes": false,
       "allow_scopes": [
         "'$SCOPE_ID'"
       ],
       "access_token_duration": 3600,
       "id_token_duration": 3600,
       "response_types": [
         "id_token",
         "token"
       ]
     }')

Export the env variables:

export CLIENT_SECRET=$(echo "$_response" | jq -r ".client_secret")
export CLIENT_ID=$(echo "$_response" | jq -r ".id")

Create an AI Auth Strategy, AI Consumer, AI Model Provider, and AI Model

Create an openid-connect AI Auth Strategy that uses Kong Identity as the issuer, an oauth AI Consumer whose custom_id matches the client’s token claim, and an AI Model Provider and AI Model for OpenAI. The AI Model references the AI Auth Strategy through access.auth_strategies.

custom_id must match the value Kong Identity places in the token claim named in config.consumer_claims (sub in this example). Confirm the actual sub value for your client (for example, by decoding a generated access token) before relying on this in production.

kongctl apply -f - --auto-approve --pat "$KONNECT_TOKEN" << 'EOF'
ai_gateway_auth_strategies:
  - ref: identity-oidc
    ai_gateway: !lookup {id: !env AI_GATEWAY_ID}
    display_name: "Identity OIDC"
    name: identity-oidc
    type: openid-connect
    config:
      issuer: !env ISSUER_URL
      client_id:
        - !env CLIENT_ID
      client_secret:
        - !secret {source: !env CLIENT_SECRET}
      auth_methods:
        - bearer
      scopes:
        - my-scope
      consumer_claims:
        - - sub
      cache_tokens_salt: identity-oidc-cache-salt
ai_gateway_consumers:
  - ref: cli-tool-consumer
    ai_gateway: !lookup {id: !env AI_GATEWAY_ID}
    display_name: "CLI Tool Consumer"
    name: cli-tool-consumer
    type: oauth
    custom_id: !env CLIENT_ID
    policies: []
ai_gateway_model_providers:
  - ref: generic-openai
    ai_gateway: !lookup {id: !env AI_GATEWAY_ID}
    name: generic-openai
    display_name: "generic-openai"
    type: openai
    config:
      auth:
        type: basic
        headers:
          - name: Authorization
            value: !secret {source: !env OPENAI_AUTH_HEADER}
ai_gateway_models:
  - ref: my-gpt-4o-mini
    ai_gateway: !lookup {id: !env AI_GATEWAY_ID}
    display_name: my-gpt-4o-mini
    name: my-gpt-4o-mini
    type: model
    enabled: true
    formats: [{ type: openai }]
    access:
      auth_strategies:
        - !ref identity-oidc#name
    config:
      route:
        paths:
          - /
        model:
          body_param: model
          values:
            - my-gpt-4o-mini
    capabilities: [generate]
    targets:
      - name: gpt-4o-mini
        provider: generic-openai
        config:
          type: openai
EOF

In this example:

  • ai_gateway_auth_strategies.config.consumer_claims: Locates the token claim that carries the AI Consumer identifier. - - sub maps to the top-level sub claim; nest further path segments to reach a claim nested deeper in the token.
  • ai_gateway_consumers.custom_id: Set to the identifier Kong Identity issues for this client. AI Gateway matches this against the sub claim on every incoming token.
  • ai_gateway_model_providers.config.auth: Stores your OpenAI API key. AI Gateway injects it into upstream requests automatically; the client that calls my-gpt-4o-mini never sees or needs it.
  • ai_gateway_models.access.auth_strategies: Requires a valid bearer token from Kong Identity on every request to my-gpt-4o-mini.

Validate

  1. Send a chat completion request without a token:
   curl -X POST "$KONNECT_PROXY_URL/chat/completions" \
        --no-progress-meter --fail-with-body  \
        -H "Content-Type: application/json" \
        --json '{
          "model": "my-gpt-4o-mini",
          "messages": [
            {
              "role": "user",
              "content": "What is the capital of France?"
            }
          ]
        }'

The request fails with 401 Unauthorized.

  1. Generate a token for the client and export it:
   ACCESS_TOKEN=$(curl -X POST "$ISSUER_URL/oauth/token" \
        --no-progress-meter --fail-with-body  \
        -H "Content-Type: application/x-www-form-urlencoded" \
        -d "grant_type=client_credentials" \
        -d "client_id=$CLIENT_ID" \
        -d "client_secret=$CLIENT_SECRET" \
        -d "scope=my-scope"  | jq -r ".access_token"
   )
  1. Send the same request with the token:
   curl -X POST "$KONNECT_PROXY_URL/chat/completions" \
        --no-progress-meter --fail-with-body  \
        -H "Content-Type: application/json"\
        -H "Authorization: Bearer $ACCESS_TOKEN" \
        --json '{
          "model": "my-gpt-4o-mini",
          "messages": [
            {
              "role": "user",
              "content": "What is the capital of France?"
            }
          ]
        }'

AI Gateway validates the bearer token against Kong Identity, matches its sub claim to the cli-tool-consumer AI Consumer, then proxies the request to OpenAI.

Confirm usage is tracked per AI Consumer

  1. In Konnect, go to Observability > Dashboards.
  2. From the Create dashboard dropdown menu, select “Create from template”.
  3. Click AI Gateway dashboard.
  4. Click Use template.
  5. Click Add filter.
  6. Select “AI gateway consumer”.
  7. From the Value dropdown menu, select “CLI Tool Consumer”.
  8. Click Apply.

You will see that the request from the previous step is attributed to cli-tool-consumer, not to an anonymous caller.

Cleanup

To clean up all AI Gateway resources created in this guide, run:

curl -Ls https://get.konghq.com/ai | bash -s -- -d
curl -X DELETE "https://us.api.konghq.com/v1/auth-servers/$AUTH_SERVER_ID?force=true" \
     --no-progress-meter --fail-with-body  \
     -H "Authorization: Bearer $KONNECT_TOKEN"\
     -H "Content-Type: application/json"

FAQs

Yes. The openid-connect AI Auth Strategy type works with any OIDC-compliant identity provider (Okta, Keycloak, Auth0, Azure AD, and others). Replace issuer, client_id, and client_secret with values from your provider, and set config.consumer_claims to wherever that provider places the identifier you use as the AI Consumer’s custom_id.

AI Gateway treats the request as an anonymous AI Consumer. Attach a Request Termination Policy to the anonymous AI Consumer if you want unmatched tokens rejected outright rather than proxied as anonymous.

Yes. Each AI Model supports one key-auth AI Auth Strategy and one openid-connect AI Auth Strategy at the same time. A request is authenticated if it satisfies either one, so you can keep issuing static API keys to some callers while others authenticate through Kong Identity.

Help us make these docs great!

Kong Developer docs are open source. If you find these useful and want to make them better, contribute today!