OAuth2 Proxy with Ingress Nginx
We recently added external authentication to our ingress-nginx using oauth2-proxy. The basic setup uses these two annotations on the ingress that we want protected:
# example snippet
nginx.ingress.kubernetes.io/auth-signin: https://access.example.com/oauth2/start?rd=$scheme://$host$request_uri
nginx.ingress.kubernetes.io/auth-url: https://access.example.com/oauth2/auth
The problem we hit
- When the backend service returns HTTP 401, ingress-nginx (with auth-signin set) intercepts that 401 and automatically redirects the client to the oauth2-proxy sign-in flow. That can be surprising if your upstream intentionally returns 401 (for example, an API that communicates auth state to the client and expects the client to react).
Why this happens
- Setting auth-signin tells ingress-nginx what URL to redirect unauthenticated users to. To implement that behavior it maps 401 responses to a redirect page by using NGINX error_page handling. The result: a backend 401 becomes a redirect to your auth endpoint instead of being passed through to the client.
The fix we used
- Prevent ingress-nginx from intercepting backend 401 responses by disabling proxy error interception for the relevant server block:
# Add this annotation to the ingress to avoid intercepting 401s from the backend
nginx.ingress.kubernetes.io/server-snippet: |
# Don't intercept 401 errors from backend - pass them through to client
proxy_intercept_errors off;
Full example ingress
- The following is a practical example showing the auth annotations together with the server-snippet. This is safe to apply to a specific ingress that needs pass-through behavior.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-protected-app
annotations:
nginx.ingress.kubernetes.io/auth-signin: "https://access.example.com/oauth2/start?rd=$scheme://$host$request_uri"
nginx.ingress.kubernetes.io/auth-url: "https://access.example.com/oauth2/auth"
nginx.ingress.kubernetes.io/server-snippet: |
# Ensure backend 401s are forwarded to the client instead of causing a redirect
proxy_intercept_errors off;
spec:
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-service
port:
number: 80