git.iko.soy/typeable/oauth2-proxy
on master help sign in
docs: fix how to use skip-provider-button with proper auth redirect handling (#3315)
dcc7970Stefan Markmann
CHANGELOG.md+2−1
@@ -8,7 +8,8 @@
8
8
9## Changes since v7.14.1
9## Changes since v7.14.1
10
10
11−- [#3314](https://github.com/oauth2-proxy/oauth2-proxy/pull/3314) revert: fix: skip provider button auth only redirect (#3309)
11+- [#3314](https://github.com/oauth2-proxy/oauth2-proxy/pull/3314) revert: fix: skip provider button auth only redirect (#3309) (@StefanMarkmann / @tuunit)
12+- [#3315](https://github.com/oauth2-proxy/oauth2-proxy/pull/3315) docs: clarify browser vs API routes for nginx auth_request redirects (@StefanMarkmann)
12
13
13# V7.14.1
14# V7.14.1
14
15
contrib/local-environment/nginx.conf+18−13
@@ -18,17 +18,20 @@ server {
18
18
19 auth_request /internal-auth/oauth2/auth;
19 auth_request /internal-auth/oauth2/auth;
20
20
21− # If the auth_request denies the request (401), redirect to the sign_in page
21+ # On 401, redirect to the sign_in page via a named location
22− # and include the final rd URL back to the user's original request.
22+ # This ensures a proper 302 redirect that browsers will follow
23− error_page 401 =403 http://oauth2-proxy.oauth2-proxy.localhost/oauth2/sign_in?rd=$scheme://$host$request_uri;
23+ error_page 401 = @oauth2_signin;
24−
25− # Alternatively send the request to `start` to skip the provider button
26− # error_page 401 = http://oauth2-proxy.oauth2-proxy.localhost/oauth2/start?rd=$scheme://$host$request_uri;
27
24
28 location / {
25 location / {
29 proxy_pass http://httpbin/;
26 proxy_pass http://httpbin/;
30 }
27 }
31
28
29+ # Named location for OAuth2 sign-in redirect
30+ # Returns a proper 302 that works with --skip-provider-button
31+ location @oauth2_signin {
32+ return 302 http://oauth2-proxy.oauth2-proxy.localhost/oauth2/sign_in?rd=$scheme://$host$request_uri;
33+ }
34+
32 # auth_request must be a URI so this allows an internal path to then proxy to
35 # auth_request must be a URI so this allows an internal path to then proxy to
33 # the real auth_request path.
36 # the real auth_request path.
34 # The trailing /'s are required so that nginx strips the prefix before proxying.
37 # The trailing /'s are required so that nginx strips the prefix before proxying.
@@ -52,18 +55,20 @@ server {
52 location / {
55 location / {
53 auth_request /internal-auth/oauth2/auth;
56 auth_request /internal-auth/oauth2/auth;
54
57
55− # If the auth_request denies the request (401), redirect to the sign_in page
58+ # On 401, redirect to the sign_in page via a named location
56− # and include the final rd URL back to the user's original request.
59+ # This ensures a proper 302 redirect that browsers will follow
57− error_page 401 =403 http://oauth2-proxy.oauth2-proxy.localhost/oauth2/sign_in?rd=$scheme://$host$request_uri;
60+ error_page 401 = @oauth2_signin;
58−
59− # Alternatively send the request to `start` to skip the provider button
60− # error_page 401 = http://oauth2-proxy.oauth2-proxy.localhost/oauth2/start?rd=$scheme://$host$request_uri;
61−
62
61
63 root /usr/share/nginx/html;
62 root /usr/share/nginx/html;
64 index index.html index.htm;
63 index index.html index.htm;
65 }
64 }
66
65
66+ # Named location for OAuth2 sign-in redirect
67+ # Returns a proper 302 that works with --skip-provider-button
68+ location @oauth2_signin {
69+ return 302 http://oauth2-proxy.oauth2-proxy.localhost/oauth2/sign_in?rd=$scheme://$host$request_uri;
70+ }
71+
67 # redirect server error pages to the static page /50x.html
72 # redirect server error pages to the static page /50x.html
68 error_page 500 502 503 504 /50x.html;
73 error_page 500 502 503 504 /50x.html;
69 location = /50x.html {
74 location = /50x.html {
docs/docs/configuration/integrations/nginx.md+68−1
@@ -43,7 +43,7 @@ server {
43
43
44 location / {
44 location / {
45 auth_request /oauth2/auth;
45 auth_request /oauth2/auth;
46− error_page 401 =403 /oauth2/sign_in;
46+ error_page 401 = @oauth2_signin;
47
47
48 # pass information via X-User and X-Email headers to backend,
48 # pass information via X-User and X-Email headers to backend,
49 # requires running with --set-xauthrequest flag
49 # requires running with --set-xauthrequest flag
@@ -82,9 +82,76 @@ server {
82 proxy_pass http://backend/;
82 proxy_pass http://backend/;
83 # or "root /path/to/site;" or "fastcgi_pass ..." etc
83 # or "root /path/to/site;" or "fastcgi_pass ..." etc
84 }
84 }
85+
86+ # Named location for handling OAuth2 sign-in redirects
87+ # This ensures the browser receives a proper 302 redirect that it will follow
88+ location @oauth2_signin {
89+ return 302 /oauth2/sign_in?rd=$scheme://$host$request_uri;
90+ }
91+}
92+```
93+
94+### Understanding the `error_page` redirect pattern
95+
96+The `auth_request` directive expects the authentication endpoint (`/oauth2/auth`) to return:
97+- **2xx**: Request is authenticated, allow access
98+- **401 or 403**: Request is not authenticated, deny access
99+
100+When a 401 is returned, nginx triggers the `error_page` directive. The recommended pattern uses a **named location** (`@oauth2_signin`) that returns a proper **302 redirect**:
101+
102+```nginx
103+error_page 401 = @oauth2_signin;
104+
105+location @oauth2_signin {
106+ return 302 /oauth2/sign_in?rd=$scheme://$host$request_uri;
85}
107}
86```
108```
87
109
110+:::warning Avoid `error_page 401 =403` with sign_in
111+Some older configurations use `error_page 401 =403 /oauth2/sign_in`. While this works for displaying the sign-in page, it returns a **403 status code** with a `Location` header. Browsers do not automatically follow redirects on 403 responses, which can cause issues when using `--skip-provider-button=true` (users see a "Found." link instead of being automatically redirected).
112+
113+The named location pattern above ensures the browser receives a standard **302 redirect** that works correctly with all oauth2-proxy configurations.
114+:::
115+
116+### Browser vs API Routes
117+
118+:::important When to use redirects
119+Redirecting authentication failures (302 to `/oauth2/sign_in`) should **only be used for browser-facing routes**. API or machine clients should receive a plain 401/403 response without redirect.
120+:::
121+
122+#### Browser-facing routes (HTML, UI)
123+
124+For interactive browser routes where users should be redirected to sign in:
125+
126+```nginx
127+location / {
128+ auth_request /oauth2/auth;
129+ error_page 401 = @oauth2_signin;
130+ proxy_pass http://backend/;
131+}
132+
133+location @oauth2_signin {
134+ return 302 /oauth2/sign_in?rd=$scheme://$host$request_uri;
135+}
136+```
137+
138+#### API / Machine routes (no redirect)
139+
140+For API endpoints where clients expect a 401/403 status code (not a redirect):
141+
142+```nginx
143+location /api/ {
144+ auth_request /oauth2/auth;
145+ error_page 401 =401; # Pass through the 401 status
146+ proxy_pass http://backend/;
147+}
148+```
149+
150+This ensures:
151+- ✅ Browsers get a redirect and smooth login flow
152+- ✅ API clients fail fast with appropriate HTTP status codes
153+- ✅ `/oauth2/auth` remains a pure boolean oracle (2xx/401)
154+
88When you use ingress-nginx in Kubernetes, you can configure the same behavior with the following annotations on your Ingress resource:
155When you use ingress-nginx in Kubernetes, you can configure the same behavior with the following annotations on your Ingress resource:
89
156
90```yaml
157```yaml
docs/versioned_docs/version-7.10.x/configuration/integration.md+69−1
@@ -33,9 +33,15 @@ server {
33 proxy_pass_request_body off;
33 proxy_pass_request_body off;
34 }
34 }
35
35
36+ # Named location for handling OAuth2 sign-in redirects
37+ # This ensures the browser receives a proper 302 redirect that it will follow
38+ location @oauth2_signin {
39+ return 302 /oauth2/sign_in?rd=$scheme://$host$request_uri;
40+ }
41+
36 location / {
42 location / {
37 auth_request /oauth2/auth;
43 auth_request /oauth2/auth;
38− error_page 401 =403 /oauth2/sign_in;
44+ error_page 401 = @oauth2_signin;
39
45
40 # pass information via X-User and X-Email headers to backend,
46 # pass information via X-User and X-Email headers to backend,
41 # requires running with --set-xauthrequest flag
47 # requires running with --set-xauthrequest flag
@@ -77,6 +83,68 @@ server {
77}
83}
78```
84```
79
85
86+### Understanding the `error_page` redirect pattern
87+
88+The `auth_request` directive expects the authentication endpoint (`/oauth2/auth`) to return:
89+- **2xx**: Request is authenticated, allow access
90+- **401 or 403**: Request is not authenticated, deny access
91+
92+When a 401 is returned, nginx triggers the `error_page` directive. The recommended pattern uses a **named location** (`@oauth2_signin`) that returns a proper **302 redirect**:
93+
94+
95+```nginx
96+error_page 401 = @oauth2_signin;
97+
98+location @oauth2_signin {
99+ return 302 /oauth2/sign_in?rd=$scheme://$host$request_uri;
100+}
101+```
102+
103+:::warning Avoid `error_page 401 =403` with sign_in
104+Some older configurations use `error_page 401 =403 /oauth2/sign_in`. While this works for displaying the sign-in page, it returns a **403 status code** with a `Location` header. Browsers do not automatically follow redirects on 403 responses, which can cause issues when using `--skip-provider-button=true` (users see a "Found." link instead of being automatically redirected).
105+
106+The named location pattern above ensures the browser receives a standard **302 redirect** that works correctly with all oauth2-proxy configurations.
107+:::
108+
109+### Browser vs API Routes
110+
111+:::important When to use redirects
112+Redirecting authentication failures (302 to `/oauth2/sign_in`) should **only be used for browser-facing routes**. API or machine clients should receive a plain 401/403 response without redirect.
113+:::
114+
115+#### Browser-facing routes (HTML, UI)
116+
117+For interactive browser routes where users should be redirected to sign in:
118+
119+```nginx
120+location / {
121+ auth_request /oauth2/auth;
122+ error_page 401 = @oauth2_signin;
123+ proxy_pass http://backend/;
124+}
125+
126+location @oauth2_signin {
127+ return 302 /oauth2/sign_in?rd=$scheme://$host$request_uri;
128+}
129+```
130+
131+#### API / Machine routes (no redirect)
132+
133+For API endpoints where clients expect a 401/403 status code (not a redirect):
134+
135+```nginx
136+location /api/ {
137+ auth_request /oauth2/auth;
138+ error_page 401 =401; # Pass through the 401 status
139+ proxy_pass http://backend/;
140+}
141+```
142+
143+This ensures:
144+- ✅ Browsers get a redirect and smooth login flow
145+- ✅ API clients fail fast with appropriate HTTP status codes
146+- ✅ `/oauth2/auth` remains a pure boolean oracle (2xx/401)
147+
80When you use ingress-nginx in Kubernetes, you can configure the same behavior with the following annotations on your Ingress resource:
148When you use ingress-nginx in Kubernetes, you can configure the same behavior with the following annotations on your Ingress resource:
81
149
82```yaml
150```yaml
docs/versioned_docs/version-7.11.x/configuration/integration.md+69−1
@@ -33,9 +33,15 @@ server {
33 proxy_pass_request_body off;
33 proxy_pass_request_body off;
34 }
34 }
35
35
36+ # Named location for handling OAuth2 sign-in redirects
37+ # This ensures the browser receives a proper 302 redirect that it will follow
38+ location @oauth2_signin {
39+ return 302 /oauth2/sign_in?rd=$scheme://$host$request_uri;
40+ }
41+
36 location / {
42 location / {
37 auth_request /oauth2/auth;
43 auth_request /oauth2/auth;
38− error_page 401 =403 /oauth2/sign_in;
44+ error_page 401 = @oauth2_signin;
39
45
40 # pass information via X-User and X-Email headers to backend,
46 # pass information via X-User and X-Email headers to backend,
41 # requires running with --set-xauthrequest flag
47 # requires running with --set-xauthrequest flag
@@ -77,6 +83,68 @@ server {
77}
83}
78```
84```
79
85
86+### Understanding the `error_page` redirect pattern
87+
88+The `auth_request` directive expects the authentication endpoint (`/oauth2/auth`) to return:
89+- **2xx**: Request is authenticated, allow access
90+- **401 or 403**: Request is not authenticated, deny access
91+
92+When a 401 is returned, nginx triggers the `error_page` directive. The recommended pattern uses a **named location** (`@oauth2_signin`) that returns a proper **302 redirect**:
93+
94+
95+```nginx
96+error_page 401 = @oauth2_signin;
97+
98+location @oauth2_signin {
99+ return 302 /oauth2/sign_in?rd=$scheme://$host$request_uri;
100+}
101+```
102+
103+:::warning Avoid `error_page 401 =403` with sign_in
104+Some older configurations use `error_page 401 =403 /oauth2/sign_in`. While this works for displaying the sign-in page, it returns a **403 status code** with a `Location` header. Browsers do not automatically follow redirects on 403 responses, which can cause issues when using `--skip-provider-button=true` (users see a "Found." link instead of being automatically redirected).
105+
106+The named location pattern above ensures the browser receives a standard **302 redirect** that works correctly with all oauth2-proxy configurations.
107+:::
108+
109+### Browser vs API Routes
110+
111+:::important When to use redirects
112+Redirecting authentication failures (302 to `/oauth2/sign_in`) should **only be used for browser-facing routes**. API or machine clients should receive a plain 401/403 response without redirect.
113+:::
114+
115+#### Browser-facing routes (HTML, UI)
116+
117+For interactive browser routes where users should be redirected to sign in:
118+
119+```nginx
120+location / {
121+ auth_request /oauth2/auth;
122+ error_page 401 = @oauth2_signin;
123+ proxy_pass http://backend/;
124+}
125+
126+location @oauth2_signin {
127+ return 302 /oauth2/sign_in?rd=$scheme://$host$request_uri;
128+}
129+```
130+
131+#### API / Machine routes (no redirect)
132+
133+For API endpoints where clients expect a 401/403 status code (not a redirect):
134+
135+```nginx
136+location /api/ {
137+ auth_request /oauth2/auth;
138+ error_page 401 =401; # Pass through the 401 status
139+ proxy_pass http://backend/;
140+}
141+```
142+
143+This ensures:
144+- ✅ Browsers get a redirect and smooth login flow
145+- ✅ API clients fail fast with appropriate HTTP status codes
146+- ✅ `/oauth2/auth` remains a pure boolean oracle (2xx/401)
147+
80When you use ingress-nginx in Kubernetes, you can configure the same behavior with the following annotations on your Ingress resource:
148When you use ingress-nginx in Kubernetes, you can configure the same behavior with the following annotations on your Ingress resource:
81
149
82```yaml
150```yaml
docs/versioned_docs/version-7.12.x/configuration/integration.md+69−1
@@ -33,9 +33,15 @@ server {
33 proxy_pass_request_body off;
33 proxy_pass_request_body off;
34 }
34 }
35
35
36+ # Named location for handling OAuth2 sign-in redirects
37+ # This ensures the browser receives a proper 302 redirect that it will follow
38+ location @oauth2_signin {
39+ return 302 /oauth2/sign_in?rd=$scheme://$host$request_uri;
40+ }
41+
36 location / {
42 location / {
37 auth_request /oauth2/auth;
43 auth_request /oauth2/auth;
38− error_page 401 =403 /oauth2/sign_in;
44+ error_page 401 = @oauth2_signin;
39
45
40 # pass information via X-User and X-Email headers to backend,
46 # pass information via X-User and X-Email headers to backend,
41 # requires running with --set-xauthrequest flag
47 # requires running with --set-xauthrequest flag
@@ -77,6 +83,68 @@ server {
77}
83}
78```
84```
79
85
86+### Understanding the `error_page` redirect pattern
87+
88+The `auth_request` directive expects the authentication endpoint (`/oauth2/auth`) to return:
89+- **2xx**: Request is authenticated, allow access
90+- **401 or 403**: Request is not authenticated, deny access
91+
92+When a 401 is returned, nginx triggers the `error_page` directive. The recommended pattern uses a **named location** (`@oauth2_signin`) that returns a proper **302 redirect**:
93+
94+
95+```nginx
96+error_page 401 = @oauth2_signin;
97+
98+location @oauth2_signin {
99+ return 302 /oauth2/sign_in?rd=$scheme://$host$request_uri;
100+}
101+```
102+
103+:::warning Avoid `error_page 401 =403` with sign_in
104+Some older configurations use `error_page 401 =403 /oauth2/sign_in`. While this works for displaying the sign-in page, it returns a **403 status code** with a `Location` header. Browsers do not automatically follow redirects on 403 responses, which can cause issues when using `--skip-provider-button=true` (users see a "Found." link instead of being automatically redirected).
105+
106+The named location pattern above ensures the browser receives a standard **302 redirect** that works correctly with all oauth2-proxy configurations.
107+:::
108+
109+### Browser vs API Routes
110+
111+:::important When to use redirects
112+Redirecting authentication failures (302 to `/oauth2/sign_in`) should **only be used for browser-facing routes**. API or machine clients should receive a plain 401/403 response without redirect.
113+:::
114+
115+#### Browser-facing routes (HTML, UI)
116+
117+For interactive browser routes where users should be redirected to sign in:
118+
119+```nginx
120+location / {
121+ auth_request /oauth2/auth;
122+ error_page 401 = @oauth2_signin;
123+ proxy_pass http://backend/;
124+}
125+
126+location @oauth2_signin {
127+ return 302 /oauth2/sign_in?rd=$scheme://$host$request_uri;
128+}
129+```
130+
131+#### API / Machine routes (no redirect)
132+
133+For API endpoints where clients expect a 401/403 status code (not a redirect):
134+
135+```nginx
136+location /api/ {
137+ auth_request /oauth2/auth;
138+ error_page 401 =401; # Pass through the 401 status
139+ proxy_pass http://backend/;
140+}
141+```
142+
143+This ensures:
144+- ✅ Browsers get a redirect and smooth login flow
145+- ✅ API clients fail fast with appropriate HTTP status codes
146+- ✅ `/oauth2/auth` remains a pure boolean oracle (2xx/401)
147+
80When you use ingress-nginx in Kubernetes, you can configure the same behavior with the following annotations on your Ingress resource:
148When you use ingress-nginx in Kubernetes, you can configure the same behavior with the following annotations on your Ingress resource:
81
149
82```yaml
150```yaml
docs/versioned_docs/version-7.13.x/configuration/integrations/nginx.md+68−1
@@ -43,7 +43,7 @@ server {
43
43
44 location / {
44 location / {
45 auth_request /oauth2/auth;
45 auth_request /oauth2/auth;
46− error_page 401 =403 /oauth2/sign_in;
46+ error_page 401 = @oauth2_signin;
47
47
48 # pass information via X-User and X-Email headers to backend,
48 # pass information via X-User and X-Email headers to backend,
49 # requires running with --set-xauthrequest flag
49 # requires running with --set-xauthrequest flag
@@ -82,9 +82,76 @@ server {
82 proxy_pass http://backend/;
82 proxy_pass http://backend/;
83 # or "root /path/to/site;" or "fastcgi_pass ..." etc
83 # or "root /path/to/site;" or "fastcgi_pass ..." etc
84 }
84 }
85+
86+ # Named location for handling OAuth2 sign-in redirects
87+ # This ensures the browser receives a proper 302 redirect that it will follow
88+ location @oauth2_signin {
89+ return 302 /oauth2/sign_in?rd=$scheme://$host$request_uri;
90+ }
91+}
92+```
93+
94+### Understanding the `error_page` redirect pattern
95+
96+The `auth_request` directive expects the authentication endpoint (`/oauth2/auth`) to return:
97+- **2xx**: Request is authenticated, allow access
98+- **401 or 403**: Request is not authenticated, deny access
99+
100+When a 401 is returned, nginx triggers the `error_page` directive. The recommended pattern uses a **named location** (`@oauth2_signin`) that returns a proper **302 redirect**:
101+
102+```nginx
103+error_page 401 = @oauth2_signin;
104+
105+location @oauth2_signin {
106+ return 302 /oauth2/sign_in?rd=$scheme://$host$request_uri;
85}
107}
86```
108```
87
109
110+:::warning Avoid `error_page 401 =403` with sign_in
111+Some older configurations use `error_page 401 =403 /oauth2/sign_in`. While this works for displaying the sign-in page, it returns a **403 status code** with a `Location` header. Browsers do not automatically follow redirects on 403 responses, which can cause issues when using `--skip-provider-button=true` (users see a "Found." link instead of being automatically redirected).
112+
113+The named location pattern above ensures the browser receives a standard **302 redirect** that works correctly with all oauth2-proxy configurations.
114+:::
115+
116+### Browser vs API Routes
117+
118+:::important When to use redirects
119+Redirecting authentication failures (302 to `/oauth2/sign_in`) should **only be used for browser-facing routes**. API or machine clients should receive a plain 401/403 response without redirect.
120+:::
121+
122+#### Browser-facing routes (HTML, UI)
123+
124+For interactive browser routes where users should be redirected to sign in:
125+
126+```nginx
127+location / {
128+ auth_request /oauth2/auth;
129+ error_page 401 = @oauth2_signin;
130+ proxy_pass http://backend/;
131+}
132+
133+location @oauth2_signin {
134+ return 302 /oauth2/sign_in?rd=$scheme://$host$request_uri;
135+}
136+```
137+
138+#### API / Machine routes (no redirect)
139+
140+For API endpoints where clients expect a 401/403 status code (not a redirect):
141+
142+```nginx
143+location /api/ {
144+ auth_request /oauth2/auth;
145+ error_page 401 =401; # Pass through the 401 status
146+ proxy_pass http://backend/;
147+}
148+```
149+
150+This ensures:
151+- ✅ Browsers get a redirect and smooth login flow
152+- ✅ API clients fail fast with appropriate HTTP status codes
153+- ✅ `/oauth2/auth` remains a pure boolean oracle (2xx/401)
154+
88When you use ingress-nginx in Kubernetes, you can configure the same behavior with the following annotations on your Ingress resource:
155When you use ingress-nginx in Kubernetes, you can configure the same behavior with the following annotations on your Ingress resource:
89
156
90```yaml
157```yaml
docs/versioned_docs/version-7.14.x/configuration/integrations/nginx.md+68−1
@@ -43,7 +43,7 @@ server {
43
43
44 location / {
44 location / {
45 auth_request /oauth2/auth;
45 auth_request /oauth2/auth;
46− error_page 401 =403 /oauth2/sign_in;
46+ error_page 401 = @oauth2_signin;
47
47
48 # pass information via X-User and X-Email headers to backend,
48 # pass information via X-User and X-Email headers to backend,
49 # requires running with --set-xauthrequest flag
49 # requires running with --set-xauthrequest flag
@@ -82,9 +82,76 @@ server {
82 proxy_pass http://backend/;
82 proxy_pass http://backend/;
83 # or "root /path/to/site;" or "fastcgi_pass ..." etc
83 # or "root /path/to/site;" or "fastcgi_pass ..." etc
84 }
84 }
85+
86+ # Named location for handling OAuth2 sign-in redirects
87+ # This ensures the browser receives a proper 302 redirect that it will follow
88+ location @oauth2_signin {
89+ return 302 /oauth2/sign_in?rd=$scheme://$host$request_uri;
90+ }
91+}
92+```
93+
94+### Understanding the `error_page` redirect pattern
95+
96+The `auth_request` directive expects the authentication endpoint (`/oauth2/auth`) to return:
97+- **2xx**: Request is authenticated, allow access
98+- **401 or 403**: Request is not authenticated, deny access
99+
100+When a 401 is returned, nginx triggers the `error_page` directive. The recommended pattern uses a **named location** (`@oauth2_signin`) that returns a proper **302 redirect**:
101+
102+```nginx
103+error_page 401 = @oauth2_signin;
104+
105+location @oauth2_signin {
106+ return 302 /oauth2/sign_in?rd=$scheme://$host$request_uri;
85}
107}
86```
108```
87
109
110+:::warning Avoid `error_page 401 =403` with sign_in
111+Some older configurations use `error_page 401 =403 /oauth2/sign_in`. While this works for displaying the sign-in page, it returns a **403 status code** with a `Location` header. Browsers do not automatically follow redirects on 403 responses, which can cause issues when using `--skip-provider-button=true` (users see a "Found." link instead of being automatically redirected).
112+
113+The named location pattern above ensures the browser receives a standard **302 redirect** that works correctly with all oauth2-proxy configurations.
114+:::
115+
116+### Browser vs API Routes
117+
118+:::important When to use redirects
119+Redirecting authentication failures (302 to `/oauth2/sign_in`) should **only be used for browser-facing routes**. API or machine clients should receive a plain 401/403 response without redirect.
120+:::
121+
122+#### Browser-facing routes (HTML, UI)
123+
124+For interactive browser routes where users should be redirected to sign in:
125+
126+```nginx
127+location / {
128+ auth_request /oauth2/auth;
129+ error_page 401 = @oauth2_signin;
130+ proxy_pass http://backend/;
131+}
132+
133+location @oauth2_signin {
134+ return 302 /oauth2/sign_in?rd=$scheme://$host$request_uri;
135+}
136+```
137+
138+#### API / Machine routes (no redirect)
139+
140+For API endpoints where clients expect a 401/403 status code (not a redirect):
141+
142+```nginx
143+location /api/ {
144+ auth_request /oauth2/auth;
145+ error_page 401 =401; # Pass through the 401 status
146+ proxy_pass http://backend/;
147+}
148+```
149+
150+This ensures:
151+- ✅ Browsers get a redirect and smooth login flow
152+- ✅ API clients fail fast with appropriate HTTP status codes
153+- ✅ `/oauth2/auth` remains a pure boolean oracle (2xx/401)
154+
88When you use ingress-nginx in Kubernetes, you can configure the same behavior with the following annotations on your Ingress resource:
155When you use ingress-nginx in Kubernetes, you can configure the same behavior with the following annotations on your Ingress resource:
89
156
90```yaml
157```yaml