ProxyAuth domain with forward_auth on localhost results in OIDC invalid_redirect_uri #177

Closed
opened 2025-11-25 13:50:02 -06:00 by tedtramonte · 5 comments
tedtramonte commented 2025-11-25 13:50:02 -06:00 (Migrated from github.com)

Describe the bug:

Trying to access a localhost domain/path covered by a ProxyAuth rule, with Caddy set to forward_auth, leads to an OIDC error.

To Reproduce:

Voidauth

One ProxyAuth domain */* with any group assigned or none at all

Caddy

Caddyfile, where $DOMAIN = localhost

(proxyauth) {
	forward_auth voidauth:3000 {
		uri /api/authz/forward-auth
		copy_headers Remote-User Remote-Groups Remote-Name Remote-Email
	}
}

id.{$DOMAIN} {
	reverse_proxy voidauth:3000
}

{$DOMAIN}, *.{$DOMAIN} {

	@organizr host home.{$DOMAIN} organizr.{$DOMAIN}
	handle @organizr {
		import proxyauth
		reverse_proxy organizr:80
	}

}

Test

Attempt to access https://organizr.localhost.

caddy-1     | 2025/11/25 19:41:17.180   DEBUG   http.handlers.reverse_proxy     selected upstream       {"dial": "voidauth:3000", "total_upstreams": 1}
caddy-1     | 2025/11/25 19:41:17.181   DEBUG   http.handlers.reverse_proxy     upstream roundtrip      {"upstream": "voidauth:3000", "duration": 0.001442837, "request": {"remote_ip": "172.20.0.1", "remote_port": "54232", "client_ip": "172.20.0.1", "proto": "HTTP/2.0", "method": "GET", "host": "organizr.localhost", "uri": "/api/authz/forward-auth", "headers": {"Sec-Fetch-Mode": ["navigate"], "Accept": ["text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"], "Priority": ["u=0, i"], "Sec-Gpc": ["1"], "Via": ["2.0 Caddy"], "X-Forwarded-Method": ["GET"], "Accept-Encoding": ["gzip, deflate, br, zstd"], "Cache-Control": ["no-cache"], "Dnt": ["1"], "Te": ["trailers"], "X-Forwarded-Proto": ["https"], "Upgrade-Insecure-Requests": ["1"], "Sec-Fetch-Site": ["none"], "X-Forwarded-Uri": ["/"], "User-Agent": ["Mozilla/5.0 (X11; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0"], "Sec-Fetch-Dest": ["document"], "Accept-Language": ["en-US,en;q=0.5"], "X-Forwarded-For": ["172.20.0.1"], "X-Forwarded-Host": ["organizr.localhost"], "Sec-Fetch-User": ["?1"], "Pragma": ["no-cache"]}, "tls": {"resumed": false, "version": 772, "cipher_suite": 4865, "proto": "h2", "server_name": "organizr.localhost"}}, "headers": {"Referrer-Policy": ["no-referrer"], "X-Download-Options": ["noopen"], "Connection": ["keep-alive"], "Cross-Origin-Opener-Policy": ["same-origin"], "X-Frame-Options": ["SAMEORIGIN"], "X-Ratelimit-Reset": ["1764099899"], "Content-Length": ["196"], "Keep-Alive": ["timeout=5"], "Content-Security-Policy": ["script-src 'self' 'unsafe-inline';img-src 'self' data: https:;font-src 'self' data:;style-src 'self' 'unsafe-inline';form-action 'self' https:;default-src 'self';base-uri 'self';frame-ancestors 'self';object-src 'none';script-src-attr 'none';upgrade-insecure-requests"], "Cross-Origin-Resource-Policy": ["same-origin"], "X-Content-Type-Options": ["nosniff"], "X-Dns-Prefetch-Control": ["off"], "X-Permitted-Cross-Domain-Policies": ["none"], "X-Xss-Protection": ["0"], "Location": ["https://id.localhost/oidc/auth?client_id=auth_internal_client&response_type=none&scope=openid&redirect_uri=https://organizr.localhost/&login_type=login"], "Content-Type": ["text/html; charset=utf-8"], "Origin-Agent-Cluster": ["?1"], "Strict-Transport-Security": ["max-age=31536000; includeSubDomains"], "X-Ratelimit-Limit": ["6000"], "X-Ratelimit-Remaining": ["5905"], "Date": ["Tue, 25 Nov 2025 19:41:17 GMT"], "Vary": ["Accept"]}, "status": 302}
caddy-1     | 2025/11/25 19:41:17.181   INFO    http.log.access.log0    handled request {"request": {"remote_ip": "172.20.0.1", "remote_port": "54232", "client_ip": "172.20.0.1", "proto": "HTTP/2.0", "method": "GET", "host": "organizr.localhost", "uri": "/", "headers": {"Accept-Language": ["en-US,en;q=0.5"], "Priority": ["u=0, i"], "Accept": ["text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"], "Accept-Encoding": ["gzip, deflate, br, zstd"], "Upgrade-Insecure-Requests": ["1"], "Pragma": ["no-cache"], "Te": ["trailers"], "Cache-Control": ["no-cache"], "User-Agent": ["Mozilla/5.0 (X11; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0"], "Sec-Fetch-Mode": ["navigate"], "Sec-Fetch-User": ["?1"], "Dnt": ["1"], "Sec-Fetch-Site": ["none"], "Sec-Gpc": ["1"], "Sec-Fetch-Dest": ["document"]}, "tls": {"resumed": false, "version": 772, "cipher_suite": 4865, "proto": "h2", "server_name": "organizr.localhost"}}, "bytes_read": 0, "user_id": "", "duration": 0.001642449, "size": 196, "status": 302, "resp_headers": {"Via": ["1.1 Caddy"], "Alt-Svc": ["h3=\":443\"; ma=2592000"], "X-Download-Options": ["noopen"], "X-Ratelimit-Reset": ["1764099899"], "X-Permitted-Cross-Domain-Policies": ["none"], "X-Xss-Protection": ["0"], "Location": ["https://id.localhost/oidc/auth?client_id=auth_internal_client&response_type=none&scope=openid&redirect_uri=https://organizr.localhost/&login_type=login"], "X-Ratelimit-Limit": ["6000"], "Content-Security-Policy": ["script-src 'self' 'unsafe-inline';img-src 'self' data: https:;font-src 'self' data:;style-src 'self' 'unsafe-inline';form-action 'self' https:;default-src 'self';base-uri 'self';frame-ancestors 'self';object-src 'none';script-src-attr 'none';upgrade-insecure-requests"], "Cross-Origin-Resource-Policy": ["same-origin"], "X-Content-Type-Options": ["nosniff"], "X-Dns-Prefetch-Control": ["off"], "Content-Type": ["text/html; charset=utf-8"], "Origin-Agent-Cluster": ["?1"], "Vary": ["Accept"], "Referrer-Policy": ["no-referrer"], "X-Frame-Options": ["SAMEORIGIN"], "X-Ratelimit-Remaining": ["5905"], "Date": ["Tue, 25 Nov 2025 19:41:17 GMT"], "Cross-Origin-Opener-Policy": ["same-origin"], "Content-Length": ["196"], "Strict-Transport-Security": ["max-age=31536000; includeSubDomains"]}}
caddy-1     | 2025/11/25 19:41:17.191   DEBUG   http.handlers.reverse_proxy     selected upstream       {"dial": "voidauth:3000", "total_upstreams": 1}
voidauth-1  | InvalidRedirectUri: invalid_redirect_uri
voidauth-1  |     at checkRedirectUri (file:///app/node_modules/oidc-provider/lib/actions/authorization/check_redirect_uri.js:32:13)
voidauth-1  |     at dispatch (/app/node_modules/koa-compose/index.js:42:32)
voidauth-1  |     at checkOpenIdScope (file:///app/node_modules/oidc-provider/lib/actions/authorization/check_openid_scope.js:23:12)
voidauth-1  |     at dispatch (/app/node_modules/koa-compose/index.js:42:32)
voidauth-1  |     at checkScope (file:///app/node_modules/oidc-provider/lib/actions/authorization/check_scope.js:52:10)
voidauth-1  |     at dispatch (/app/node_modules/koa-compose/index.js:42:32)
voidauth-1  |     at checkPrompt (file:///app/node_modules/oidc-provider/lib/actions/authorization/check_prompt.js:24:10)
voidauth-1  |     at dispatch (/app/node_modules/koa-compose/index.js:42:32)
voidauth-1  |     at assignDefaults (file:///app/node_modules/oidc-provider/lib/actions/authorization/assign_defaults.js:16:10)
voidauth-1  |     at dispatch (/app/node_modules/koa-compose/index.js:42:32) {
voidauth-1  |   allow_redirect: false,
voidauth-1  |   error: 'invalid_redirect_uri',
voidauth-1  |   status: 400,
voidauth-1  |   statusCode: 400,
voidauth-1  |   expose: true,
voidauth-1  |   error_description: "redirect_uri did not match any of the client's registered redirect_uris"
voidauth-1  | }
caddy-1     | 2025/11/25 19:41:17.193   DEBUG   http.handlers.reverse_proxy     upstream roundtrip      {"upstream": "voidauth:3000", "duration": 0.002020984, "request": {"remote_ip": "172.20.0.1", "remote_port": "54248", "client_ip": "172.20.0.1", "proto": "HTTP/2.0", "method": "GET", "host": "id.localhost", "uri": "/oidc/auth?client_id=auth_internal_client&response_type=none&scope=openid&redirect_uri=https://organizr.localhost/&login_type=login", "headers": {"Pragma": ["no-cache"], "User-Agent": ["Mozilla/5.0 (X11; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0"], "X-Forwarded-For": ["172.20.0.1"], "Sec-Fetch-User": ["?1"], "Accept-Language": ["en-US,en;q=0.5"], "Upgrade-Insecure-Requests": ["1"], "Sec-Fetch-Dest": ["document"], "X-Forwarded-Host": ["id.localhost"], "Via": ["2.0 Caddy"], "Priority": ["u=0, i"], "Cache-Control": ["no-cache"], "Accept": ["text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"], "Sec-Fetch-Mode": ["navigate"], "Sec-Fetch-Site": ["none"], "X-Forwarded-Proto": ["https"], "Accept-Encoding": ["gzip, deflate, br, zstd"], "Dnt": ["1"], "Te": ["trailers"], "Sec-Gpc": ["1"]}, "tls": {"resumed": false, "version": 772, "cipher_suite": 4865, "proto": "h2", "server_name": "id.localhost"}}, "headers": {"Origin-Agent-Cluster": ["?1"], "Referrer-Policy": ["no-referrer"], "X-Ratelimit-Remaining": ["5904"], "Content-Security-Policy": ["script-src 'self' 'unsafe-inline';img-src 'self' data: https:;font-src 'self' data:;style-src 'self' 'unsafe-inline';form-action 'self' https:;default-src 'self';base-uri 'self';frame-ancestors 'self';object-src 'none';script-src-attr 'none';upgrade-insecure-requests"], "Cross-Origin-Resource-Policy": ["same-origin"], "Strict-Transport-Security": ["max-age=31536000; includeSubDomains"], "X-Dns-Prefetch-Control": ["off"], "X-Frame-Options": ["SAMEORIGIN"], "X-Permitted-Cross-Domain-Policies": ["none"], "X-Ratelimit-Limit": ["6000"], "Content-Length": ["170"], "Cross-Origin-Opener-Policy": ["same-origin"], "X-Download-Options": ["noopen"], "X-Xss-Protection": ["0"], "Date": ["Tue, 25 Nov 2025 19:41:17 GMT"], "Content-Type": ["application/json; charset=utf-8"], "Connection": ["keep-alive"], "Keep-Alive": ["timeout=5"], "X-Content-Type-Options": ["nosniff"], "X-Ratelimit-Reset": ["1764099899"], "Cache-Control": ["no-store"]}, "status": 500}
caddy-1     | 2025/11/25 19:41:17.231   DEBUG   http.handlers.reverse_proxy     selected upstream       {"dial": "voidauth:3000", "total_upstreams": 1}
caddy-1     | 2025/11/25 19:41:17.233   DEBUG   http.handlers.reverse_proxy     upstream roundtrip      {"upstream": "voidauth:3000", "duration": 0.001172834, "request": {"remote_ip": "172.20.0.1", "remote_port": "39626", "client_ip": "172.20.0.1", "proto": "HTTP/2.0", "method": "GET", "host": "id.localhost", "uri": "/favicon.ico", "headers": {"Sec-Fetch-Site": ["cross-site"], "User-Agent": ["Mozilla/5.0 (X11; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0"], "Priority": ["u=6"], "X-Forwarded-Proto": ["https"], "X-Forwarded-Host": ["id.localhost"], "Sec-Fetch-Dest": ["image"], "Pragma": ["no-cache"], "Cache-Control": ["no-cache"], "Dnt": ["1"], "Via": ["2.0 Caddy"], "Sec-Gpc": ["1"], "Accept": ["image/avif,image/webp,image/png,image/svg+xml,image/*;q=0.8,*/*;q=0.5"], "Sec-Fetch-Mode": ["no-cors"], "Te": ["trailers"], "Accept-Language": ["en-US,en;q=0.5"], "Accept-Encoding": ["gzip, deflate, br, zstd"], "X-Forwarded-For": ["172.20.0.1"]}, "tls": {"resumed": false, "version": 772, "cipher_suite": 4865, "proto": "h2", "server_name": "id.localhost"}}, "headers": {"Cross-Origin-Opener-Policy": ["same-origin"], "Origin-Agent-Cluster": ["?1"], "Referrer-Policy": ["no-referrer"], "X-Frame-Options": ["SAMEORIGIN"], "X-Xss-Protection": ["0"], "X-Ratelimit-Reset": ["1764099899"], "Etag": ["W/\"d93-AUEB70DUqqgVNwgBKIKWDe9Ktls\""], "Keep-Alive": ["timeout=5"], "Content-Security-Policy": ["script-src 'self' 'unsafe-inline';img-src 'self' data: https:;font-src 'self' data:;style-src 'self' 'unsafe-inline';form-action 'self' https:;default-src 'self';base-uri 'self';frame-ancestors 'self';object-src 'none';script-src-attr 'none';upgrade-insecure-requests"], "X-Download-Options": ["noopen"], "Date": ["Tue, 25 Nov 2025 19:41:17 GMT"], "Content-Type": ["text/html; charset=utf-8"], "Content-Length": ["3475"], "Connection": ["keep-alive"], "Strict-Transport-Security": ["max-age=31536000; includeSubDomains"], "X-Content-Type-Options": ["nosniff"], "X-Dns-Prefetch-Control": ["off"], "X-Ratelimit-Limit": ["6000"], "X-Ratelimit-Remaining": ["5903"], "Cross-Origin-Resource-Policy": ["same-origin"], "X-Permitted-Cross-Domain-Policies": ["none"]}, "status": 200}

Expected behavior:

I assume Voidauth should be sending me to the login page. The logs and screenshot were taken from an incognito window, so a fresh session. I don't know why it's going to an OIDC flow.

Database Driver:

SQLite

Screenshots:

Image

Additional context:

I might just be an idiot, this stuff is far outside my realm of expertise. It's possible this is just a limitation of using localhost as a domain? This was just for evaluating functionality before moving to production. I decided to YOLO it and things seem to work fine using my real domain.

### Describe the bug: <!-- A clear description of the bug --> Trying to access a localhost domain/path covered by a ProxyAuth rule, with Caddy set to forward_auth, leads to an OIDC error. ### To Reproduce: #### Voidauth One ProxyAuth domain `*/*` with any group assigned or none at all #### Caddy Caddyfile, where `$DOMAIN` = `localhost` ```Caddyfile (proxyauth) { forward_auth voidauth:3000 { uri /api/authz/forward-auth copy_headers Remote-User Remote-Groups Remote-Name Remote-Email } } id.{$DOMAIN} { reverse_proxy voidauth:3000 } {$DOMAIN}, *.{$DOMAIN} { @organizr host home.{$DOMAIN} organizr.{$DOMAIN} handle @organizr { import proxyauth reverse_proxy organizr:80 } } ``` #### Test Attempt to access `https://organizr.localhost`. ``` caddy-1 | 2025/11/25 19:41:17.180 DEBUG http.handlers.reverse_proxy selected upstream {"dial": "voidauth:3000", "total_upstreams": 1} caddy-1 | 2025/11/25 19:41:17.181 DEBUG http.handlers.reverse_proxy upstream roundtrip {"upstream": "voidauth:3000", "duration": 0.001442837, "request": {"remote_ip": "172.20.0.1", "remote_port": "54232", "client_ip": "172.20.0.1", "proto": "HTTP/2.0", "method": "GET", "host": "organizr.localhost", "uri": "/api/authz/forward-auth", "headers": {"Sec-Fetch-Mode": ["navigate"], "Accept": ["text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"], "Priority": ["u=0, i"], "Sec-Gpc": ["1"], "Via": ["2.0 Caddy"], "X-Forwarded-Method": ["GET"], "Accept-Encoding": ["gzip, deflate, br, zstd"], "Cache-Control": ["no-cache"], "Dnt": ["1"], "Te": ["trailers"], "X-Forwarded-Proto": ["https"], "Upgrade-Insecure-Requests": ["1"], "Sec-Fetch-Site": ["none"], "X-Forwarded-Uri": ["/"], "User-Agent": ["Mozilla/5.0 (X11; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0"], "Sec-Fetch-Dest": ["document"], "Accept-Language": ["en-US,en;q=0.5"], "X-Forwarded-For": ["172.20.0.1"], "X-Forwarded-Host": ["organizr.localhost"], "Sec-Fetch-User": ["?1"], "Pragma": ["no-cache"]}, "tls": {"resumed": false, "version": 772, "cipher_suite": 4865, "proto": "h2", "server_name": "organizr.localhost"}}, "headers": {"Referrer-Policy": ["no-referrer"], "X-Download-Options": ["noopen"], "Connection": ["keep-alive"], "Cross-Origin-Opener-Policy": ["same-origin"], "X-Frame-Options": ["SAMEORIGIN"], "X-Ratelimit-Reset": ["1764099899"], "Content-Length": ["196"], "Keep-Alive": ["timeout=5"], "Content-Security-Policy": ["script-src 'self' 'unsafe-inline';img-src 'self' data: https:;font-src 'self' data:;style-src 'self' 'unsafe-inline';form-action 'self' https:;default-src 'self';base-uri 'self';frame-ancestors 'self';object-src 'none';script-src-attr 'none';upgrade-insecure-requests"], "Cross-Origin-Resource-Policy": ["same-origin"], "X-Content-Type-Options": ["nosniff"], "X-Dns-Prefetch-Control": ["off"], "X-Permitted-Cross-Domain-Policies": ["none"], "X-Xss-Protection": ["0"], "Location": ["https://id.localhost/oidc/auth?client_id=auth_internal_client&response_type=none&scope=openid&redirect_uri=https://organizr.localhost/&login_type=login"], "Content-Type": ["text/html; charset=utf-8"], "Origin-Agent-Cluster": ["?1"], "Strict-Transport-Security": ["max-age=31536000; includeSubDomains"], "X-Ratelimit-Limit": ["6000"], "X-Ratelimit-Remaining": ["5905"], "Date": ["Tue, 25 Nov 2025 19:41:17 GMT"], "Vary": ["Accept"]}, "status": 302} caddy-1 | 2025/11/25 19:41:17.181 INFO http.log.access.log0 handled request {"request": {"remote_ip": "172.20.0.1", "remote_port": "54232", "client_ip": "172.20.0.1", "proto": "HTTP/2.0", "method": "GET", "host": "organizr.localhost", "uri": "/", "headers": {"Accept-Language": ["en-US,en;q=0.5"], "Priority": ["u=0, i"], "Accept": ["text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"], "Accept-Encoding": ["gzip, deflate, br, zstd"], "Upgrade-Insecure-Requests": ["1"], "Pragma": ["no-cache"], "Te": ["trailers"], "Cache-Control": ["no-cache"], "User-Agent": ["Mozilla/5.0 (X11; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0"], "Sec-Fetch-Mode": ["navigate"], "Sec-Fetch-User": ["?1"], "Dnt": ["1"], "Sec-Fetch-Site": ["none"], "Sec-Gpc": ["1"], "Sec-Fetch-Dest": ["document"]}, "tls": {"resumed": false, "version": 772, "cipher_suite": 4865, "proto": "h2", "server_name": "organizr.localhost"}}, "bytes_read": 0, "user_id": "", "duration": 0.001642449, "size": 196, "status": 302, "resp_headers": {"Via": ["1.1 Caddy"], "Alt-Svc": ["h3=\":443\"; ma=2592000"], "X-Download-Options": ["noopen"], "X-Ratelimit-Reset": ["1764099899"], "X-Permitted-Cross-Domain-Policies": ["none"], "X-Xss-Protection": ["0"], "Location": ["https://id.localhost/oidc/auth?client_id=auth_internal_client&response_type=none&scope=openid&redirect_uri=https://organizr.localhost/&login_type=login"], "X-Ratelimit-Limit": ["6000"], "Content-Security-Policy": ["script-src 'self' 'unsafe-inline';img-src 'self' data: https:;font-src 'self' data:;style-src 'self' 'unsafe-inline';form-action 'self' https:;default-src 'self';base-uri 'self';frame-ancestors 'self';object-src 'none';script-src-attr 'none';upgrade-insecure-requests"], "Cross-Origin-Resource-Policy": ["same-origin"], "X-Content-Type-Options": ["nosniff"], "X-Dns-Prefetch-Control": ["off"], "Content-Type": ["text/html; charset=utf-8"], "Origin-Agent-Cluster": ["?1"], "Vary": ["Accept"], "Referrer-Policy": ["no-referrer"], "X-Frame-Options": ["SAMEORIGIN"], "X-Ratelimit-Remaining": ["5905"], "Date": ["Tue, 25 Nov 2025 19:41:17 GMT"], "Cross-Origin-Opener-Policy": ["same-origin"], "Content-Length": ["196"], "Strict-Transport-Security": ["max-age=31536000; includeSubDomains"]}} caddy-1 | 2025/11/25 19:41:17.191 DEBUG http.handlers.reverse_proxy selected upstream {"dial": "voidauth:3000", "total_upstreams": 1} voidauth-1 | InvalidRedirectUri: invalid_redirect_uri voidauth-1 | at checkRedirectUri (file:///app/node_modules/oidc-provider/lib/actions/authorization/check_redirect_uri.js:32:13) voidauth-1 | at dispatch (/app/node_modules/koa-compose/index.js:42:32) voidauth-1 | at checkOpenIdScope (file:///app/node_modules/oidc-provider/lib/actions/authorization/check_openid_scope.js:23:12) voidauth-1 | at dispatch (/app/node_modules/koa-compose/index.js:42:32) voidauth-1 | at checkScope (file:///app/node_modules/oidc-provider/lib/actions/authorization/check_scope.js:52:10) voidauth-1 | at dispatch (/app/node_modules/koa-compose/index.js:42:32) voidauth-1 | at checkPrompt (file:///app/node_modules/oidc-provider/lib/actions/authorization/check_prompt.js:24:10) voidauth-1 | at dispatch (/app/node_modules/koa-compose/index.js:42:32) voidauth-1 | at assignDefaults (file:///app/node_modules/oidc-provider/lib/actions/authorization/assign_defaults.js:16:10) voidauth-1 | at dispatch (/app/node_modules/koa-compose/index.js:42:32) { voidauth-1 | allow_redirect: false, voidauth-1 | error: 'invalid_redirect_uri', voidauth-1 | status: 400, voidauth-1 | statusCode: 400, voidauth-1 | expose: true, voidauth-1 | error_description: "redirect_uri did not match any of the client's registered redirect_uris" voidauth-1 | } caddy-1 | 2025/11/25 19:41:17.193 DEBUG http.handlers.reverse_proxy upstream roundtrip {"upstream": "voidauth:3000", "duration": 0.002020984, "request": {"remote_ip": "172.20.0.1", "remote_port": "54248", "client_ip": "172.20.0.1", "proto": "HTTP/2.0", "method": "GET", "host": "id.localhost", "uri": "/oidc/auth?client_id=auth_internal_client&response_type=none&scope=openid&redirect_uri=https://organizr.localhost/&login_type=login", "headers": {"Pragma": ["no-cache"], "User-Agent": ["Mozilla/5.0 (X11; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0"], "X-Forwarded-For": ["172.20.0.1"], "Sec-Fetch-User": ["?1"], "Accept-Language": ["en-US,en;q=0.5"], "Upgrade-Insecure-Requests": ["1"], "Sec-Fetch-Dest": ["document"], "X-Forwarded-Host": ["id.localhost"], "Via": ["2.0 Caddy"], "Priority": ["u=0, i"], "Cache-Control": ["no-cache"], "Accept": ["text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"], "Sec-Fetch-Mode": ["navigate"], "Sec-Fetch-Site": ["none"], "X-Forwarded-Proto": ["https"], "Accept-Encoding": ["gzip, deflate, br, zstd"], "Dnt": ["1"], "Te": ["trailers"], "Sec-Gpc": ["1"]}, "tls": {"resumed": false, "version": 772, "cipher_suite": 4865, "proto": "h2", "server_name": "id.localhost"}}, "headers": {"Origin-Agent-Cluster": ["?1"], "Referrer-Policy": ["no-referrer"], "X-Ratelimit-Remaining": ["5904"], "Content-Security-Policy": ["script-src 'self' 'unsafe-inline';img-src 'self' data: https:;font-src 'self' data:;style-src 'self' 'unsafe-inline';form-action 'self' https:;default-src 'self';base-uri 'self';frame-ancestors 'self';object-src 'none';script-src-attr 'none';upgrade-insecure-requests"], "Cross-Origin-Resource-Policy": ["same-origin"], "Strict-Transport-Security": ["max-age=31536000; includeSubDomains"], "X-Dns-Prefetch-Control": ["off"], "X-Frame-Options": ["SAMEORIGIN"], "X-Permitted-Cross-Domain-Policies": ["none"], "X-Ratelimit-Limit": ["6000"], "Content-Length": ["170"], "Cross-Origin-Opener-Policy": ["same-origin"], "X-Download-Options": ["noopen"], "X-Xss-Protection": ["0"], "Date": ["Tue, 25 Nov 2025 19:41:17 GMT"], "Content-Type": ["application/json; charset=utf-8"], "Connection": ["keep-alive"], "Keep-Alive": ["timeout=5"], "X-Content-Type-Options": ["nosniff"], "X-Ratelimit-Reset": ["1764099899"], "Cache-Control": ["no-store"]}, "status": 500} caddy-1 | 2025/11/25 19:41:17.231 DEBUG http.handlers.reverse_proxy selected upstream {"dial": "voidauth:3000", "total_upstreams": 1} caddy-1 | 2025/11/25 19:41:17.233 DEBUG http.handlers.reverse_proxy upstream roundtrip {"upstream": "voidauth:3000", "duration": 0.001172834, "request": {"remote_ip": "172.20.0.1", "remote_port": "39626", "client_ip": "172.20.0.1", "proto": "HTTP/2.0", "method": "GET", "host": "id.localhost", "uri": "/favicon.ico", "headers": {"Sec-Fetch-Site": ["cross-site"], "User-Agent": ["Mozilla/5.0 (X11; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0"], "Priority": ["u=6"], "X-Forwarded-Proto": ["https"], "X-Forwarded-Host": ["id.localhost"], "Sec-Fetch-Dest": ["image"], "Pragma": ["no-cache"], "Cache-Control": ["no-cache"], "Dnt": ["1"], "Via": ["2.0 Caddy"], "Sec-Gpc": ["1"], "Accept": ["image/avif,image/webp,image/png,image/svg+xml,image/*;q=0.8,*/*;q=0.5"], "Sec-Fetch-Mode": ["no-cors"], "Te": ["trailers"], "Accept-Language": ["en-US,en;q=0.5"], "Accept-Encoding": ["gzip, deflate, br, zstd"], "X-Forwarded-For": ["172.20.0.1"]}, "tls": {"resumed": false, "version": 772, "cipher_suite": 4865, "proto": "h2", "server_name": "id.localhost"}}, "headers": {"Cross-Origin-Opener-Policy": ["same-origin"], "Origin-Agent-Cluster": ["?1"], "Referrer-Policy": ["no-referrer"], "X-Frame-Options": ["SAMEORIGIN"], "X-Xss-Protection": ["0"], "X-Ratelimit-Reset": ["1764099899"], "Etag": ["W/\"d93-AUEB70DUqqgVNwgBKIKWDe9Ktls\""], "Keep-Alive": ["timeout=5"], "Content-Security-Policy": ["script-src 'self' 'unsafe-inline';img-src 'self' data: https:;font-src 'self' data:;style-src 'self' 'unsafe-inline';form-action 'self' https:;default-src 'self';base-uri 'self';frame-ancestors 'self';object-src 'none';script-src-attr 'none';upgrade-insecure-requests"], "X-Download-Options": ["noopen"], "Date": ["Tue, 25 Nov 2025 19:41:17 GMT"], "Content-Type": ["text/html; charset=utf-8"], "Content-Length": ["3475"], "Connection": ["keep-alive"], "Strict-Transport-Security": ["max-age=31536000; includeSubDomains"], "X-Content-Type-Options": ["nosniff"], "X-Dns-Prefetch-Control": ["off"], "X-Ratelimit-Limit": ["6000"], "X-Ratelimit-Remaining": ["5903"], "Cross-Origin-Resource-Policy": ["same-origin"], "X-Permitted-Cross-Domain-Policies": ["none"]}, "status": 200} ``` ### Expected behavior: I assume Voidauth should be sending me to the login page. The logs and screenshot were taken from an incognito window, so a fresh session. I don't know why it's going to an OIDC flow. ### Database Driver: SQLite ### Screenshots: <img width="1915" height="597" alt="Image" src="https://github.com/user-attachments/assets/15900026-5440-4982-baeb-319f675185f2" /> ### Additional context: I might just be an idiot, this stuff is far outside my realm of expertise. It's possible this is just a limitation of using localhost as a domain? This was just for evaluating functionality before moving to production. I decided to YOLO it and things seem to work fine using my real domain.
notquitenothing commented 2025-11-30 14:35:10 -06:00 (Migrated from github.com)

Hello! Thank you for opening an issue and writing out your config and logs, it helps a lot with troubleshooting. That is a weird error you are getting, I wonder if it could be due to using *.localhost for testing? Part of the ProxyAuth process does use the same validators for redirecting as the OIDC Clients, but you should never see this error. Internally large parts of the ProxyAuth process have changed in the latest release however, so if you get the chance to re-test after updating to v1.5.0 please let me know if you are still getting an error, and if the error message has changed.

Hello! Thank you for opening an issue and writing out your config and logs, it helps a lot with troubleshooting. That is a weird error you are getting, I wonder if it could be due to using *.localhost for testing? Part of the ProxyAuth process does use the same validators for redirecting as the OIDC Clients, but you should never see this error. Internally large parts of the ProxyAuth process have changed in the latest release however, so if you get the chance to re-test after updating to [v1.5.0](https://github.com/voidauth/voidauth/releases/tag/v1.5.0) please let me know if you are still getting an error, and if the error message has changed.
tedtramonte commented 2025-11-30 14:53:36 -06:00 (Migrated from github.com)

The error has definitely changed!

Again, with ProxyAuth set to */* and accessing any subdomain, in this example it's home.localhost I now see:

error "ProxyAuth root hostname home.localhost does not equal APP_URL root hostname id.localhost"

Which is a 400 response to the GET request to home.localhost. I don't see Caddy attempting to actually perform the forward_auth and redirect to id.localhost, as I saw in my original post.

The error has definitely changed! Again, with ProxyAuth set to `*/*` and accessing any subdomain, in this example it's home.localhost I now see: `error "ProxyAuth root hostname home.localhost does not equal APP_URL root hostname id.localhost"` Which is a 400 response to the GET request to home.localhost. I don't see Caddy attempting to actually perform the forward_auth and redirect to id.localhost, as I saw in my original post.
notquitenothing commented 2025-11-30 16:08:30 -06:00 (Migrated from github.com)

Interesting! I wasn't actually expecting you to get that error, but it explains what is going on. There is a long answer below, but the short answer is that VoidAuth doesn't think that it would be able to set the required session cookie from id.localhost that could be read from home.localhost in order for ProxyAuth to work. It is either correct and it would not be able to set a cookie on localhost that could be read by both, or there is an issue and this could actually work. Either way, you should not see this error in a real environment where you own the domain ex. id.example.com and home.example.com would both have base domain example.com and all would be well.

Please let me know if you also see this error in a non-testing environment where you are using a real domain.

Longer Answer Here:
ProxyAuth depends upon VoidAuth (accessed from id.example.com) being able to set a cookie (x-voidauth-session-uid) on its base domain (example.com) and that cookie be read by the reverse-proxy while accessing the protected domain (home.example.com). That 'sticky' cookie that can be set by VoidAuth and read by reverse-proxy drives the ForwardAuth process in every SSO provider. In practice, that means that VoidAuth can only protect sites that are on the same base domain, otherwise browsers will reject the cookie and you will be sent back to the login page or in a never-ending loop. To prevent this, VoidAuth will show that error if you are attempting to protect a domain that does not share a base domain with the $APP_URL. In this case, I would have expected the base domain of both id.localhost and home.localhost to be localhost, though things always get weird with cookies and localhost.

Interesting! I wasn't actually expecting you to get that error, but it explains what is going on. There is a long answer below, but the short answer is that VoidAuth doesn't think that it would be able to set the required session cookie from `id.localhost` that could be read from `home.localhost` in order for ProxyAuth to work. It is either correct and it would not be able to set a cookie on `localhost` that could be read by both, or there is an issue and this could actually work. Either way, you should not see this error in a real environment where you own the domain ex. `id.example.com` and `home.example.com` would both have base domain `example.com` and all would be well. Please let me know if you also see this error in a non-testing environment where you are using a real domain. Longer Answer Here: ProxyAuth depends upon VoidAuth (accessed from `id.example.com`) being able to set a cookie (`x-voidauth-session-uid`) on its base domain (`example.com`) and that cookie be read by the reverse-proxy while accessing the protected domain (`home.example.com`). That 'sticky' cookie that can be set by VoidAuth and read by reverse-proxy drives the ForwardAuth process in every SSO provider. In practice, that means that VoidAuth can only protect sites that are on the same base domain, otherwise browsers will reject the cookie and you will be sent back to the login page or in a never-ending loop. To prevent this, VoidAuth will show that error if you are attempting to protect a domain that does not share a base domain with the `$APP_URL`. In this case, I would have expected the base domain of both `id.localhost` and `home.localhost` to be `localhost`, though things always get weird with cookies and localhost.
tedtramonte commented 2025-11-30 16:22:05 -06:00 (Migrated from github.com)

I see, that definitely explains the message. It does all work fine in production at my real domain.

The briefest of searches lead me to https://stackoverflow.com/a/74554894 which indicates cookie sharing across subdomains needs to be done with a domain on a global TLD.

I'd test the workaround with localhost.com pointed to 127.0.0.1 but Caddy has special logic for the domain localhost and I think I just blew up my letsencrypt ratelimit trying to issue certs for localhost.com lol

I suspect it would work just fine though and that your implementation isn't at fault. Not sure if there's anything actionable here. Maybe a more clear error message? Or a callout in the docs? Or nothing at all.

I see, that definitely explains the message. It does all work fine in production at my real domain. The briefest of searches lead me to https://stackoverflow.com/a/74554894 which indicates cookie sharing across subdomains needs to be done with a domain on a global TLD. I'd test the workaround with localhost.com pointed to 127.0.0.1 but Caddy has special logic for the domain localhost and I think I just blew up my letsencrypt ratelimit trying to issue certs for localhost.com lol I suspect it would work just fine though and that your implementation isn't at fault. Not sure if there's anything actionable here. Maybe a more clear error message? Or a callout in the docs? Or nothing at all.
tedtramonte commented 2025-12-01 09:56:33 -06:00 (Migrated from github.com)

Playing around some more, setting $DOMAIN=localhost.localhost allows everything to work with no other configuration needed, the only practical difference is I access services as https://home.localhost.localhost for example. This works great for testing and evaluating VoidAuth itself as well as service integrations.

Feel free to close this issue if you don't want to add this as a suggestion somewhere. I think this issue has enough keywords that anyone in this niche will stumble on it and find my solution.

Playing around some more, setting `$DOMAIN=localhost.localhost` allows everything to work with no other configuration needed, the only practical difference is I access services as https://home.localhost.localhost for example. This works great for testing and evaluating VoidAuth itself as well as service integrations. Feel free to close this issue if you don't want to add this as a suggestion somewhere. I think this issue has enough keywords that anyone in this niche will stumble on it and find my solution.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
adam/gate#177
No description provided.