NGINX Ingress Controller 5.5.0 introduced ExternalAuth, a new Policy type that lets you define external authentication once in a Policy resource and apply it consistently across both VirtualServer and Ingress traffic paths. This is the first blog in a two part series that covers the ExternalAuth Policy, and is focused on:
- How ExternalAuth policy works in NGINX Ingress Controller.
- Where to attach it in VirtualServer, VirtualServerRoute, and Ingress.
- Patterns for basic auth, OAuth2, and per-route policies.
Why Use a Policy for External Authentication?
Many teams start with per-service authentication logic or raw NGINX config snippets and quickly end up with drift. Using a dedicated Policy for external auth gives you:
- A single source of truth for your authentication configuration.
- Reuse across services and namespaces.
- Cleaner reviews because auth rules are isolated from route logic.
How ExternalAuth Policy Works in NGINX Ingress Controller
At a high level:
- Create a Policy resource with
spec.externalAuth. - Attach it where traffic is defined:
VirtualServer.spec.policies(or per-routespec.routes[].policies)VirtualServerRoute.spec.subroutes[].policies- Ingress via the
nginx.org/policiesannotation, or per-route via Mergeable Ingress minion annotations
- NGINX Ingress Controller renders an internal
auth_requestlocation that proxies every inbound request to your auth service before forwarding it to the backend.- A
2xxresponse allows the request through. - A
401or403response rejects it.
- A
If the auth service returns 401 and authSigninURI is configured, NGINX redirects the client there instead, enabling browser-based OAuth2 flows.
Example Basic Auth Policy
apiVersion: k8s.nginx.org/v1
kind: Policy
metadata:
name: external-auth-basic-policy
spec:
externalAuth:
authURI: "/auth"
authServiceName: "default/basic-auth-svc"
sslEnabled: true
sslVerify: true
sslVerifyDepth: 2
sniName: "external-auth-tls"
trustedCertSecret: "external-auth-ca-secret"
Example OAuth2 Policy With Sign-in Redirect
The examples in this blog use oauth2-proxy with GitHub, but the ExternalAuth policy works with any OAuth2/OIDC provider — just configure oauth2-proxy for your provider of choice (Google, Azure AD, Okta, Keycloak, etc.):
apiVersion: k8s.nginx.org/v1
kind: Policy
metadata:
name: external-auth-oauth2-policy
spec:
externalAuth:
authURI: "/oauth2/auth"
authSigninURI: "/oauth2/signin"
authServiceName: "default/oauth2-proxy-svc"
sslEnabled: true
sslVerify: true
sslVerifyDepth: 2
sniName: "external-auth-tls"
trustedCertSecret: "external-auth-ca-secret"
Example VirtualServer Referencing ExternalAuth Policies
You can deploy both of the above policies end-to-end with the VirtualServer external-auth-oauth2 example on GitHub, or the basic-auth-only example for a simpler starting point.
Policies can be applied at the server level (all routes inherit it) or at the route level (per-path control). This VirtualServer applies different auth per route:
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
name: cafe
spec:
host: cafe.example.com
tls:
secret: tls-secret
redirect:
enable: true
upstreams:
- name: tea
service: tea-svc
port: 80
- name: coffee
service: coffee-svc
port: 80
routes:
- path: /tea
action:
pass: tea
policies:
- name: external-auth-basic-policy
- path: /coffee
action:
pass: coffee
policies:
- name: external-auth-oauth2-policy
Example Ingress Referencing an ExternalAuth Policy
Reference the policy in the nginx.org/policies annotation to protect all paths on the Ingress:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: cafe-ingress
annotations:
nginx.org/policies: "external-auth-basic-policy"
spec:
ingressClassName: nginx
tls:
- hosts:
- cafe.example.com
secretName: tls-secret
rules:
- host: cafe.example.com
http:
paths:
- path: /tea
pathType: Prefix
backend:
service:
name: tea-svc
port:
number: 80
- path: /coffee
pathType: Prefix
backend:
service:
name: coffee-svc
port:
number: 80
You can deploy this end-to-end with the Ingress external-auth example on GitHub.
To apply different policies to different paths, use the Mergeable Ingress (master/minion) pattern: create a master Ingress for the host and TLS, and set nginx.org/policies on each minion independently. For example, the /tea minion can reference external-auth-basic-policy and the /coffee minion can reference external-auth-oauth2-policy. See the Ingress external-auth-mergeable example on GitHub for a complete walkthrough.
Important Behavior to Remember
- For VirtualServer and VirtualServerRoute, a route-level policy overrides the same-type policy at
spec.policies. - Only one ExternalAuth policy per route is applied. If multiple ExternalAuth policies are referenced on the same route, the first one is used and subsequent ones are ignored.
- Without
authSigninURI, unauthenticated requests receive a bare401instead of being redirected. - When
authSigninURIis set, NGINX Ingress Controller generates a location block forauthSigninRedirectBasePath(defaults to/oauth2) that proxies all requests under that path to the authentication service. This covers the OAuth2 callback endpoint (typically/oauth2/callback). Override the default withauthSigninRedirectBasePathif your auth service uses a different path prefix. - The
trustedCertSecretmust be typenginx.org/cawith the CA stored under theca.crtkey. Usenamespace/secretfor cross-namespace references. - When deploying oauth2-proxy, set
redirect_urlto the full callback URL on your host (e.g.https://cafe.example.com/oauth2/callback). This is the URL your OAuth provider redirects back to after authorization. It must match what you registered in the OAuth App settings.
More Information
You can find complete working examples on GitHub and more documentation in our docs:
- ExternalAuth Policy docs
- VirtualServer external-auth example
- VirtualServer external-auth-oauth2 example
- Ingress external-auth example
- Ingress external-auth-mergeable example
- NGINX Ingress Controller documentation
- NGINX Community forum
- NGINX Kubernetes Community site

