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)

* docs(nginx): Clarify auth_request redirect pattern with named location Update the nginx integration documentation to recommend using a named location (@oauth2_signin) for the error_page directive instead of the previous 'error_page 401 =403' approach. The named location pattern ensures the browser receives a proper 302 redirect, which is required for --skip-provider-button=true to work correctly. The previous pattern (error_page 401 =403 /oauth2/sign_in) returned a 403 status with a Location header. Browsers do not auto-follow redirects on 403 responses, causing users to see a 'Found.' link instead of being automatically redirected to the IdP. Changes: - Updated main nginx example to use @oauth2_signin named location - Added 'Understanding the error_page redirect pattern' section - Added warning about the limitations of 'error_page 401 =403' - Updated local test environment (contrib/local-environment/nginx.conf) Refs: #334 Signed-off-by: Stefan Markmann <stefan@markmann.net> * docs: clarify browser vs API routes for nginx auth_request redirects Add new "Browser vs API Routes" section explaining: - Use 302 redirect to /oauth2/sign_in only for browser-facing routes - Use 401/403 without redirect for API/machine clients This ensures: - Browsers get a redirect and smooth login flow - API clients fail fast with appropriate HTTP status codes - /oauth2/auth remains a pure boolean oracle (2xx/401) Signed-off-by: Stefan Markmann <stefan@markmann.net> Signed-off-by: Jan Larwig <jan@larwig.com> --------- Signed-off-by: Stefan Markmann <stefan@markmann.net> Signed-off-by: Jan Larwig <jan@larwig.com>

commitdcc7970a5f214ec83cecb438871945feebf07286 authorStefan Markmann <50301139+StefanMarkmann@users.noreply.github.com> dateSun 18 Jan 2026, 00:55 (8 months ago) parentcf5d34a
8 files changed+431−20
CHANGELOG.md+2−1 contrib/local-environment/nginx.conf+18−13 docs/docs/configuration/integrations/nginx.md+68−1 docs/versioned_docs/version-7.10.x/configuration/integration.md+69−1 docs/versioned_docs/version-7.11.x/configuration/integration.md+69−1 docs/versioned_docs/version-7.12.x/configuration/integration.md+69−1 docs/versioned_docs/version-7.13.x/configuration/integrations/nginx.md+68−1 docs/versioned_docs/version-7.14.x/configuration/integrations/nginx.md+68−1
CHANGELOG.md+2−1
@@ -8,7 +8,8 @@
88
99## Changes since v7.14.1
1010
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)
1213
1314# V7.14.1
1415
contrib/local-environment/nginx.conf+18−13
@@ -18,17 +18,20 @@ server {
1818
1919 auth_request /internal-auth/oauth2/auth;
2020
21− # If the auth_request denies the request (401), redirect to the sign_in page
22− # and include the final rd URL back to the user's original request.
23− error_page 401 =403 http://oauth2-proxy.oauth2-proxy.localhost/oauth2/sign_in?rd=$scheme://$host$request_uri;
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;
21+ # On 401, redirect to the sign_in page via a named location
22+ # This ensures a proper 302 redirect that browsers will follow
23+ error_page 401 = @oauth2_signin;
2724
2825 location / {
2926 proxy_pass http://httpbin/;
3027 }
3128
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+
3235 # auth_request must be a URI so this allows an internal path to then proxy to
3336 # the real auth_request path.
3437 # The trailing /'s are required so that nginx strips the prefix before proxying.
@@ -52,18 +55,20 @@ server {
5255 location / {
5356 auth_request /internal-auth/oauth2/auth;
5457
55− # If the auth_request denies the request (401), redirect to the sign_in page
56− # and include the final rd URL back to the user's original request.
57− error_page 401 =403 http://oauth2-proxy.oauth2-proxy.localhost/oauth2/sign_in?rd=$scheme://$host$request_uri;
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−
58+ # On 401, redirect to the sign_in page via a named location
59+ # This ensures a proper 302 redirect that browsers will follow
60+ error_page 401 = @oauth2_signin;
6261
6362 root /usr/share/nginx/html;
6463 index index.html index.htm;
6564 }
6665
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+
6772 # redirect server error pages to the static page /50x.html
6873 error_page 500 502 503 504 /50x.html;
6974 location = /50x.html {
docs/docs/configuration/integrations/nginx.md+68−1
@@ -43,7 +43,7 @@ server {
4343
4444 location / {
4545 auth_request /oauth2/auth;
46− error_page 401 =403 /oauth2/sign_in;
46+ error_page 401 = @oauth2_signin;
4747
4848 # pass information via X-User and X-Email headers to backend,
4949 # requires running with --set-xauthrequest flag
@@ -82,9 +82,76 @@ server {
8282 proxy_pass http://backend/;
8383 # or "root /path/to/site;" or "fastcgi_pass ..." etc
8484 }
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;
85107}
86108```
87109
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+
88155When you use ingress-nginx in Kubernetes, you can configure the same behavior with the following annotations on your Ingress resource:
89156
90157```yaml
docs/versioned_docs/version-7.10.x/configuration/integration.md+69−1
@@ -33,9 +33,15 @@ server {
3333 proxy_pass_request_body off;
3434 }
3535
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+
3642 location / {
3743 auth_request /oauth2/auth;
38− error_page 401 =403 /oauth2/sign_in;
44+ error_page 401 = @oauth2_signin;
3945
4046 # pass information via X-User and X-Email headers to backend,
4147 # requires running with --set-xauthrequest flag
@@ -77,6 +83,68 @@ server {
7783}
7884```
7985
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+
80148When you use ingress-nginx in Kubernetes, you can configure the same behavior with the following annotations on your Ingress resource:
81149
82150```yaml
docs/versioned_docs/version-7.11.x/configuration/integration.md+69−1
@@ -33,9 +33,15 @@ server {
3333 proxy_pass_request_body off;
3434 }
3535
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+
3642 location / {
3743 auth_request /oauth2/auth;
38− error_page 401 =403 /oauth2/sign_in;
44+ error_page 401 = @oauth2_signin;
3945
4046 # pass information via X-User and X-Email headers to backend,
4147 # requires running with --set-xauthrequest flag
@@ -77,6 +83,68 @@ server {
7783}
7884```
7985
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+
80148When you use ingress-nginx in Kubernetes, you can configure the same behavior with the following annotations on your Ingress resource:
81149
82150```yaml
docs/versioned_docs/version-7.12.x/configuration/integration.md+69−1
@@ -33,9 +33,15 @@ server {
3333 proxy_pass_request_body off;
3434 }
3535
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+
3642 location / {
3743 auth_request /oauth2/auth;
38− error_page 401 =403 /oauth2/sign_in;
44+ error_page 401 = @oauth2_signin;
3945
4046 # pass information via X-User and X-Email headers to backend,
4147 # requires running with --set-xauthrequest flag
@@ -77,6 +83,68 @@ server {
7783}
7884```
7985
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+
80148When you use ingress-nginx in Kubernetes, you can configure the same behavior with the following annotations on your Ingress resource:
81149
82150```yaml
docs/versioned_docs/version-7.13.x/configuration/integrations/nginx.md+68−1
@@ -43,7 +43,7 @@ server {
4343
4444 location / {
4545 auth_request /oauth2/auth;
46− error_page 401 =403 /oauth2/sign_in;
46+ error_page 401 = @oauth2_signin;
4747
4848 # pass information via X-User and X-Email headers to backend,
4949 # requires running with --set-xauthrequest flag
@@ -82,9 +82,76 @@ server {
8282 proxy_pass http://backend/;
8383 # or "root /path/to/site;" or "fastcgi_pass ..." etc
8484 }
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;
85107}
86108```
87109
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+
88155When you use ingress-nginx in Kubernetes, you can configure the same behavior with the following annotations on your Ingress resource:
89156
90157```yaml
docs/versioned_docs/version-7.14.x/configuration/integrations/nginx.md+68−1
@@ -43,7 +43,7 @@ server {
4343
4444 location / {
4545 auth_request /oauth2/auth;
46− error_page 401 =403 /oauth2/sign_in;
46+ error_page 401 = @oauth2_signin;
4747
4848 # pass information via X-User and X-Email headers to backend,
4949 # requires running with --set-xauthrequest flag
@@ -82,9 +82,76 @@ server {
8282 proxy_pass http://backend/;
8383 # or "root /path/to/site;" or "fastcgi_pass ..." etc
8484 }
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;
85107}
86108```
87109
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+
88155When you use ingress-nginx in Kubernetes, you can configure the same behavior with the following annotations on your Ingress resource:
89156
90157```yaml