Configure basic authentication

This guide introduces how to configure basic authentication for your applications using the AuthenticationFilter CRD.

Overview

Authentication is crucial for modern application security and allows you to be confident that only trusted and authorized users are accessing your applications, or API backends. Through this document, you’ll learn how to protect your application endpoints with NGINX Gateway Fabric using the AuthenticationFilter CRD. In this guide we will create two sample applications, tea and coffee, where we will enable basic authentication on the /coffee endpoint. The /tea endpoint will not have any authentication. This is to help demonstrate how the application behaves both with and without authentication. The /coffee endpoint will use the ExtensionRef filter to reference an AuthenticationFilter CRD which is configured for Basic Authentication.

Before you begin

Setup

Deploy demo applications

To deploy both the coffee and tea applications, copy the following YAML into your terminal:

yaml
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: coffee
spec:
  replicas: 2
  selector:
    matchLabels:
      app: coffee
  template:
    metadata:
      labels:
        app: coffee
    spec:
      containers:
      - name: coffee
        image: nginxdemos/nginx-hello:plain-text
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: coffee
spec:
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP
    name: http
  selector:
    app: coffee
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: tea
spec:
  replicas: 2
  selector:
    matchLabels:
      app: tea
  template:
    metadata:
      labels:
        app: tea
    spec:
      containers:
      - name: tea
        image: nginxdemos/nginx-hello:plain-text
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: tea
spec:
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP
    name: http
  selector:
    app: tea
EOF

Confirm that the Pods are running

kubectl get pods
text
NAME                      READY   STATUS    RESTARTS   AGE
coffee-654ddf664b-fllj7   1/1     Running   0          21s
coffee-654ddf664b-lpgq9   1/1     Running   0          21s
tea-75bc9f4b6d-cx2jl      1/1     Running   0          21s
tea-75bc9f4b6d-s99jz      1/1     Running   0          21s

Create a Gateway

To create your gateway resource, and provision the NGINX pod, copy the following YAML into your terminal:

yaml
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: cafe-gateway
spec:
  gatewayClassName: nginx
  listeners:
  - name: http
    port: 80
    protocol: HTTP
    hostname: "cafe.example.com"
EOF

After creating the Gateway resource, NGINX Gateway Fabric will provision an NGINX Pod and Service fronting it to route traffic. Verify the gateway is created:

kubectl get gateways.gateway.networking.k8s.io cafe-gateway
text
NAME           CLASS   ADDRESS         PROGRAMMED   AGE
cafe-gateway   nginx   10.96.187.113   True         10m

Save the public IP address and port of the NGINX Service into shell variables:

text
GW_IP=XXX.YYY.ZZZ.III
GW_PORT=<port number>

Create a Basic Authentication secret and AuthenticationFilter

Deploy secret with user credentials, and the AuthenticationFilter.

Important
Ensure the secret deployed is of type nginx.org/htpasswd and the key is auth
yaml
kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
  name: basic-auth
type: nginx.org/htpasswd
data:
  # Base64 of output from: htpasswd -bn user1 password1
  auth: dXNlcjE6JGFwcjEkWEFKeU5yekgkY0Rjdy9YMVBCZTFmTjltQVBweXpxMA==
---
apiVersion: gateway.nginx.org/v1alpha1
kind: AuthenticationFilter
metadata:
  name: basic-auth
spec:
  type: Basic
  basic:
    secretRef:
      name: basic-auth
    realm: "Restricted basic-auth"
EOF

Verify the AuthenticationFilter is Accepted, and there are no errors:

kubectl describe authenticationfilters.gateway.nginx.org | grep "Status:" -A10
text
Status:
  Controllers:
    Conditions:
      Last Transition Time:  2026-01-08T10:09:18Z
      Message:               The AuthenticationFilter is accepted
      Observed Generation:   1
      Reason:                Accepted
      Status:                True
      Type:                  Accepted
    Controller Name:         gateway.nginx.org/nginx-gateway-controller
Events:                      <none>

Deploy HTTPRoute referencing an AuthenticationFilter

Deploy an HTTPRoute which references the AuthenticationFilter. This uses the ExtensionRef filter type. In this example, we set this filter to the /coffee path:

yaml
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: cafe-routes
spec:
  parentRefs:
  - name: cafe-gateway
  rules:
  - matches:
    # Coffee configured with Basic Auth
    - path:
        type: PathPrefix
        value: /coffee
    backendRefs:
    - name: coffee
      port: 80
    filters:
    - type: ExtensionRef
      extensionRef:
        group: gateway.nginx.org
        kind: AuthenticationFilter
        name: basic-auth
  - matches:
    # Tea with no authentication configured
    - path:
        type: PathPrefix
        value: /tea
    backendRefs:
    - name: tea
      port: 80
EOF

Verify the HTTPRoute is Accepted, and there are no errors:

kubectl describe httproute cafe-routes | grep "Status:" -A10
text
Status:
  Parents:
    Conditions:
      Last Transition Time:  2026-01-06T15:18:55Z
      Message:               The Route is accepted
      Observed Generation:   1
      Reason:                Accepted
      Status:                True
      Type:                  Accepted
      Last Transition Time:  2026-01-06T15:18:55Z
      Message:               All references are resolved
      Observed Generation:   1
      Reason:                ResolvedRefs
      Status:                True
      Type:                  ResolvedRefs
    Controller Name:         gateway.nginx.org/nginx-gateway-controller
    Parent Ref:
      Group:         gateway.networking.k8s.io
      Kind:          Gateway
      Name:          cafe-gateway
      Namespace:     default
      Section Name:  http
Events:              <none>

Verify Basic Authentication

Your clients should be able to resolve the domain name "cafe.example.com" to the public IP of the NGINX Service. In this guide we will simulate that using curl’s --resolve option.

Accessing /coffee with valid credentials:

curl --resolve cafe.example.com:$GW_PORT:$GW_IP http://cafe.example.com:$GW_PORT/coffee -u user1:password1

Response:

text
Server address: 10.244.0.7:8080
Server name: coffee-654ddf664b-nhhvr
Date: 06/Jan/2026:15:20:15 +0000
URI: /coffee
Request ID: 13a925b2514b62c45ea4a79800248d5c

Accessing /coffee without credentials:

curl --resolve cafe.example.com:$GW_PORT:$GW_IP http://cafe.example.com:$GW_PORT/coffee

Response:

text
<html>
<head><title>401 Authorization Required</title></head>
<body>
<center><h1>401 Authorization Required</h1></center>
<hr><center>nginx</center>
</body>
</html>

Accessing /coffee with incorrect credentials:

curl --resolve cafe.example.com:$GW_PORT:$GW_IP http://cafe.example.com:$GW_PORT/coffee  -u user1:wrong 

Response:

text
<html>
<head><title>401 Authorization Required</title></head>
<body>
<center><h1>401 Authorization Required</h1></center>
<hr><center>nginx</center>
</body>
</html>

Accessing /tea

Since tea has no AuthenticationFilter attached, responses are processed normally:

curl --resolve cafe.example.com:$GW_PORT:$GW_IP http://cafe.example.com:$GW_PORT/tea

Response:

text
Server address: 10.244.0.10:8080
Server name: tea-75bc9f4b6d-ms2n8
Date: 06/Jan/2026:15:36:26 +0000
URI: /tea
Request ID: c7eb0509303de1c160cb7e7d2ac1d99f

Troubleshooting

  • Ensure the HTTPRoute is Accepted and references the correct AuthenticationFilter name and group.
  • Confirm the secret key is named auth and is of type nginx.org/htpasswd.
  • Ensure the secret referenced by the AuthenticationFilter is in the same namespace.

Further reading