[GH-ISSUE #5626] Reverse Proxy doesn't set path of auth cookie #11811

Closed
opened 2026-08-05 01:31:08 -04:00 by saavagebueno · 6 comments
Owner

Originally created by @patrickpichler on GitHub (Mar 18, 2026).
Original GitHub issue: https://github.com/netbirdio/netbird/issues/5626

Describe the problem

The cookie set by the auth control of the reverse proxy is missing the Path options (src). According to MDN if the path is omitted, the browser will fill in the path component of the request URL (docs).

This causes issues with services such as Immichs share feature, as the share URL will look like example.com/share/aaabbcccc, but when opening it, it will also try to load resources from example.com/_app/xyz. Since the cookie is set with path /share, the requests to /_app will fail with 401.

To Reproduce

Steps to reproduce the behavior:

  1. Host some kind of webserver (for example this dummy one using ncat: while true ; do ncat -l -p 1500 -c 'echo "HTTP/1.1 200 OK\n\n $(date)"'; done)
  2. Expose it as a reverse proxy service protected by authentication
  3. Navigate to /hello/world and authenticate
  4. Navigate to /foo/bar and observe that you need to authenticate again

Expected behavior

Authentication should only happen once.

Are you using NetBird Cloud?

NetBird Cloud

NetBird version

0.65.3

Is any other VPN software installed?

No

Have you tried these troubleshooting steps?

  • Reviewed client troubleshooting (not applicable)
  • Checked for newer NetBird versions
  • Searched for similar issues on GitHub (including closed ones)
  • Restarted the NetBird client
  • Disabled other VPN software
  • Checked firewall settings
Originally created by @patrickpichler on GitHub (Mar 18, 2026). Original GitHub issue: https://github.com/netbirdio/netbird/issues/5626 **Describe the problem** The cookie set by the auth control of the reverse proxy is missing the `Path` options ([src](https://github.com/netbirdio/netbird/blob/80a8816b1dbb46d9dd3525f54abdb948ce04da66/proxy/internal/auth/middleware.go#L413)). According to MDN if the path is omitted, the browser will fill in the path component of the request URL ([docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Set-Cookie#pathpath-value)). This causes issues with services such as [Immich](https://github.com/immich-app/immich)s share feature, as the share URL will look like `example.com/share/aaabbcccc`, but when opening it, it will also try to load resources from `example.com/_app/xyz`. Since the cookie is set with path `/share`, the requests to `/_app` will fail with `401`. **To Reproduce** Steps to reproduce the behavior: 1. Host some kind of webserver (for example this dummy one using `ncat`: `while true ; do ncat -l -p 1500 -c 'echo "HTTP/1.1 200 OK\n\n $(date)"'; done`) 2. Expose it as a reverse proxy service protected by authentication 3. Navigate to `/hello/world` and authenticate 4. Navigate to `/foo/bar` and observe that you need to authenticate again **Expected behavior** Authentication should only happen once. **Are you using NetBird Cloud?** NetBird Cloud **NetBird version** `0.65.3` **Is any other VPN software installed?** No **Have you tried these troubleshooting steps?** - [ ] Reviewed [client troubleshooting](https://docs.netbird.io/how-to/troubleshooting-client) (not applicable) - [x] Checked for newer NetBird versions - [x] Searched for similar issues on GitHub (including closed ones) - [x] Restarted the NetBird client - [x] Disabled other VPN software - [x] Checked firewall settings
saavagebueno added the triage-needed label 2026-08-05 01:31:08 -04:00
Author
Owner

@patrickpichler commented on GitHub (Mar 18, 2026):

I think the following patch should fix the issue, I didn't have time to fully test it yet though 🙂

diff --git a/proxy/internal/auth/middleware.go b/proxy/internal/auth/middleware.go
index 670cafb6..31c301d6 100644
--- a/proxy/internal/auth/middleware.go
+++ b/proxy/internal/auth/middleware.go
@@ -417,6 +417,7 @@ func setSessionCookie(w http.ResponseWriter, token string, expiration time.Durat
 		Secure:   true,
 		SameSite: http.SameSiteLaxMode,
 		MaxAge:   int(expiration.Seconds()),
+		Path:     "/",
 	})
 }
<!-- gh-comment-id:4085110158 --> @patrickpichler commented on GitHub (Mar 18, 2026): I __think__ the following patch should fix the issue, I didn't have time to fully test it yet though 🙂 ```diff diff --git a/proxy/internal/auth/middleware.go b/proxy/internal/auth/middleware.go index 670cafb6..31c301d6 100644 --- a/proxy/internal/auth/middleware.go +++ b/proxy/internal/auth/middleware.go @@ -417,6 +417,7 @@ func setSessionCookie(w http.ResponseWriter, token string, expiration time.Durat Secure: true, SameSite: http.SameSiteLaxMode, MaxAge: int(expiration.Seconds()), + Path: "/", }) } ```
Author
Owner

@vldmr-k commented on GitHub (Mar 19, 2026):

@patrickpichler I got the same problem, after password/sso auth I see in the browser session path

/init-url

Instead of

/

And when I change url from /first-url to / everything is good.

So, your patch is in PR or it your local hack?

<!-- gh-comment-id:4090746026 --> @vldmr-k commented on GitHub (Mar 19, 2026): @patrickpichler I got the same problem, after password/sso auth I see in the browser session path ``` /init-url ``` Instead of ``` / ``` And when I change url from `/first-url` to `/` everything is good. So, your patch is in PR or it your local hack?
Author
Owner

@patrickpichler commented on GitHub (Mar 19, 2026):

I didn't open a PR yet, as I didn't have time to fully test it. At least in theory it should fix the issue. I am not sure if I have time today to test the change, so if you have a local dev setup to quickly test this, feel free to copy the patch 😅

<!-- gh-comment-id:4090989174 --> @patrickpichler commented on GitHub (Mar 19, 2026): I didn't open a PR yet, as I didn't have time to fully test it. At least in theory it should fix the issue. I am not sure if I have time today to test the change, so if you have a local dev setup to quickly test this, feel free to copy the patch 😅
Author
Owner

@alsruf36 commented on GitHub (Apr 18, 2026):

@patrickpichler Still reproducing this on v0.68.1 (and confirmed v0.68.2 + current main are identical here).

For context, this was actually flagged by CodeRabbit during the review of #5587 — see this review comment on proxy/internal/auth/middleware.go:

Leaving Path empty makes the cookie scope depend on the request URI. A successful auth on /foo/bar won't reliably carry to sibling routes on the same service, and this helper is now shared by both interactive and header-auth flows.

It was posted as an "outside diff range" comment, which I'm guessing is why it didn't get picked up before merge. The suggested one-liner was:

http.SetCookie(w, &http.Cookie{
    Name:     auth.SessionCookieName,
    Value:    token,
    Path:     "/",
    HttpOnly: true,
    Secure:   true,
    SameSite: http.SameSiteLaxMode,
    MaxAge:   int(expiration.Seconds()),
})

In practice this is pretty disruptive for real-world usage behind the reverse proxy. Any app that serves resources from multiple paths (SPAs with /api/* + /_app/*, share links like Immich's /share/..., anything that deep-links into a subpath) forces users into this workflow:

  1. Hit the intended URL (e.g. domain/app/page) → 401
  2. Manually navigate to domain/ → authenticate
  3. Navigate back to domain/app/page

Shared/bookmarked deep links effectively don't work, and it's not obvious to end users what's happening — they just see a broken redirect loop or a bare 401.

Happy to open a PR with the one-line fix if that helps move things along.

<!-- gh-comment-id:4272819283 --> @alsruf36 commented on GitHub (Apr 18, 2026): @patrickpichler Still reproducing this on `v0.68.1` (and confirmed `v0.68.2` + current `main` are identical here). For context, this was actually flagged by CodeRabbit during the review of #5587 — see [this review comment](https://github.com/netbirdio/netbird/pull/5587#pullrequestreview-3952294572) on `proxy/internal/auth/middleware.go`: > Leaving `Path` empty makes the cookie scope depend on the request URI. A successful auth on `/foo/bar` won't reliably carry to sibling routes on the same service, and this helper is now shared by both interactive and header-auth flows. It was posted as an "outside diff range" comment, which I'm guessing is why it didn't get picked up before merge. The suggested one-liner was: ```go http.SetCookie(w, &http.Cookie{ Name: auth.SessionCookieName, Value: token, Path: "/", HttpOnly: true, Secure: true, SameSite: http.SameSiteLaxMode, MaxAge: int(expiration.Seconds()), }) ``` In practice this is pretty disruptive for real-world usage behind the reverse proxy. Any app that serves resources from multiple paths (SPAs with `/api/*` + `/_app/*`, share links like Immich's `/share/...`, anything that deep-links into a subpath) forces users into this workflow: 1. Hit the intended URL (e.g. `domain/app/page`) → 401 2. Manually navigate to `domain/` → authenticate 3. Navigate back to `domain/app/page` Shared/bookmarked deep links effectively don't work, and it's not obvious to end users what's happening — they just see a broken redirect loop or a bare 401. Happy to open a PR with the one-line fix if that helps move things along.
Author
Owner

@patrickpichler commented on GitHub (Apr 18, 2026):

@alsruf36 I sadly didn't have time (or the setup) to test if setting the cookie path will fix the issue for real. So if you can quickly verify that it is working, feel free to open the PR 😅

<!-- gh-comment-id:4272891894 --> @patrickpichler commented on GitHub (Apr 18, 2026): @alsruf36 I sadly didn't have time (or the setup) to test if setting the cookie path will fix the issue for real. So if you can quickly verify that it is working, feel free to open the PR 😅
Author
Owner

@alsruf36 commented on GitHub (Apr 18, 2026):

@patrickpichler Verified locally — built netbird-proxy from a branch with the Path: "/" fix and ran it against my existing v0.68.1 deployment. The broken PWA / deep-link flow is resolved: session cookie is now scoped to /, sibling paths stop 401'ing, and the root-priming workaround is no longer needed.

<!-- gh-comment-id:4272999651 --> @alsruf36 commented on GitHub (Apr 18, 2026): @patrickpichler Verified locally — built `netbird-proxy` from a branch with the `Path: "/"` fix and ran it against my existing `v0.68.1` deployment. The broken PWA / deep-link flow is resolved: session cookie is now scoped to `/`, sibling paths stop 401'ing, and the root-priming workaround is no longer needed.
Sign in to join this conversation.
No Label triage-needed
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: DYNR/netbird#11811