JWT Authorization

Secure your agentgateway LLM endpoints with JWT authentication using TrafficPolicy on Kubernetes.

What you’ll build

In this tutorial, you will:

  1. Set up a local Kubernetes cluster with agentgateway and an LLM backend
  2. Create a TrafficPolicy with JWT authentication
  3. Test that unauthenticated requests are rejected
  4. Test that authenticated requests with a valid JWT are allowed

Before you begin

Make sure you have the following tools installed:

For detailed installation instructions, see the LLM Gateway tutorial.


Step 1: Create a kind cluster

kind create cluster --name agentgateway

Step 2: Install agentgateway

# Gateway API CRDs
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.0/standard-install.yaml

# agentgateway CRDs
helm upgrade -i --create-namespace \
  --namespace agentgateway-system \
  --version v2.3.0-main agentgateway-crds oci://ghcr.io/kgateway-dev/charts/agentgateway-crds

# Control plane
helm upgrade -i -n agentgateway-system agentgateway oci://ghcr.io/kgateway-dev/charts/agentgateway \
  --version v2.3.0-main

Step 3: Create a Gateway

kubectl apply -f- <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: agentgateway-proxy
  namespace: agentgateway-system
spec:
  gatewayClassName: agentgateway
  listeners:
  - protocol: HTTP
    port: 80
    name: http
    allowedRoutes:
      namespaces:
        from: All
EOF

Wait for the proxy:

kubectl get deployment agentgateway-proxy -n agentgateway-system

Step 4: Set up an LLM backend

Set your API key and create the secret and backend:

export OPENAI_API_KEY=<insert your API key>

kubectl apply -f- <<EOF
apiVersion: v1
kind: Secret
metadata:
  name: openai-secret
  namespace: agentgateway-system
type: Opaque
stringData:
  Authorization: $OPENAI_API_KEY
---
apiVersion: agentgateway.dev/v1alpha1
kind: AgentgatewayBackend
metadata:
  name: openai
  namespace: agentgateway-system
spec:
  ai:
    provider:
      openai:
        model: gpt-4.1-nano
  policies:
    auth:
      secretRef:
        name: openai-secret
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: openai
  namespace: agentgateway-system
spec:
  parentRefs:
    - name: agentgateway-proxy
      namespace: agentgateway-system
  rules:
    - backendRefs:
      - name: openai
        namespace: agentgateway-system
        group: agentgateway.dev
        kind: AgentgatewayBackend
EOF

Step 5: Download the test JWT keys

For this tutorial, use pre-generated test keys from the agentgateway repository:

# Download the JWKS public key
curl -sL https://raw.githubusercontent.com/agentgateway/agentgateway/main/manifests/jwt/pub-key -o pub-key

# Download a pre-generated test JWT token
curl -sL https://raw.githubusercontent.com/agentgateway/agentgateway/main/manifests/jwt/example1.key -o test-token.jwt
⚠️
These are test keys only. For production, generate your own keys using tools like step-cli.

The test token contains these claims:

{
  "iss": "solo.io",
  "sub": "alice",
  "exp": 1900650294
}

Step 6: Create a JWT TrafficPolicy

Create a TrafficPolicy that enforces JWT authentication on the Gateway. Requests without a valid JWT will be rejected.

# Read the JWKS into a variable
JWKS=$(cat pub-key)

kubectl apply -f- <<EOF
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TrafficPolicy
metadata:
  name: jwt-auth
  namespace: agentgateway-system
spec:
  targetRefs:
    - group: gateway.networking.k8s.io
      kind: Gateway
      name: agentgateway-proxy
  traffic:
    jwtAuthentication:
      mode: Strict
      providers:
        - issuer: solo.io
          jwks:
            inline: '$JWKS'
      authorization:
        action: Allow
        policy:
          matchExpressions:
            - 'jwt.sub == "alice"'
EOF

This policy:

  • Requires a valid JWT on every request (mode: Strict)
  • Validates the token against the provided JWKS public key
  • Authorizes only tokens where sub is alice

Step 7: Test the JWT authentication

Set up port-forwarding:

kubectl port-forward deployment/agentgateway-proxy -n agentgateway-system 8080:80 &

Test without a token (should fail)

curl -s http://localhost:8080/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model": "gpt-4.1-nano", "messages": [{"role": "user", "content": "Hello"}]}'

You should receive a 401 Unauthorized response.

Test with a valid token (should succeed)

curl -s http://localhost:8080/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $(cat test-token.jwt)" \
  -d '{"model": "gpt-4.1-nano", "messages": [{"role": "user", "content": "Hello! What is JWT?"}]}' | jq

You should receive a successful response from OpenAI.


Authorization rules

The matchExpressions field uses CEL (Common Expression Language) for fine-grained access control:

# Allow only a specific user
matchExpressions:
  - 'jwt.sub == "alice"'

# Allow by email domain
matchExpressions:
  - 'jwt.email.endsWith("@company.com")'

# Allow by role claim
matchExpressions:
  - '"admin" in jwt.roles'

Cleanup

kill %1 2>/dev/null
kind delete cluster --name agentgateway

Next steps

Agentgateway assistant

Ask me anything about agentgateway configuration, features, or usage.

Note: AI-generated content might contain errors; please verify and test all returned information.

↑↓ navigate select esc dismiss

What could be improved?