Skip to content

Forward-auth login redirect drops the original request's query string #1060

Description

@TechieOllie

Summary

When a resource protected by forward-auth is requested with a query string (e.g. GET /search?q=hello) while the user is unauthenticated, the redirect_uri tinyauth builds for the login page silently drops the query string. After a successful login the user lands on /search instead of /search?q=hello.

This breaks anything that relies on GET query parameters behind tinyauth — most notably self-hosted search engines (e.g. Degoog, a self-hosted metasearch engine), where the very first unauthenticated search always comes back empty.

Root cause

In internal/controller/proxy_controller.go, getProxyContext explicitly strips the query string when parsing the forwarded request path:

// remove any query params from the request path
upath, err := url.Parse(ctx.Path)
...
ctx.Path = path.Clean(upath.Path)

proxyHandler then builds the login redirect purely from that already-stripped path:

RedirectURI: fmt.Sprintf("%s://%s%s", proxyCtx.Proto, proxyCtx.Host, proxyCtx.Path),

proxyCtx.Path never contains a query string by the time RedirectURI is built, regardless of proxy type (Caddy/Traefik/Nginx/Envoy), since the stripping happens in the shared getProxyContext path before any proxy-specific branching.

Confirmed present on main as of 2026-08, not just an old release.

Reproduction

  1. Put a search engine (e.g. Degoog, a self-hosted metasearch engine) behind Caddy forward_auth → tinyauth (uri /api/auth/caddy).
  2. While logged out, request https://search.example.com/search?q=hello.
  3. Get redirected to tinyauth's login page. Inspect the URL: redirect_uri=https%3A%2F%2Fsearch.example.com%2Fsearch — no q param.
  4. Log in.
  5. Land on https://search.example.com/search with an empty query instead of results for "hello".

Expected behavior

redirect_uri should preserve the full original request (path + query string), so the user lands back exactly where they started after logging in.

Note

This was found with AI assistance (Claude) while debugging the symptom above, and I traced it down to the code quoted here myself. I'm not a Go developer and don't know this codebase's history, so I can't tell whether getProxyContext stripping the query string is a deliberate defensive measure (e.g. against some kind of injection via the redirect target) or just an oversight. Flagging that explicitly in case it's the former — apologies if this turns out to be working as intended, and thanks for taking a look either way.

Activity

  1. dosubot commented on Aug 5, 2026

    @dosubot

    Hi @TechieOllie! I'm Dosu and I'm helping the Tinyauth team.

    Your analysis is spot-on. The query-string stripping in getProxyContext is confirmed in the code — url.Parse is used to extract only upath.Path, discarding the query entirely, and the RedirectURI is then built from that already-cleaned path [1] [2].

    To your question about whether this is intentional or an oversight: the stripping was deliberately introduced (or at least deliberately solidified) very recently in PR #1055 (merged July 30, 2026), titled "fix: clean request path before acls." The purpose was security — preventing ACL bypasses via crafted query parameters or path manipulation. The PR includes tests for query-string bypass attempts, encoded characters, and dot-segment traversals.

    So the stripping itself is intentional for ACL evaluation, but the side-effect of losing the query string in the RedirectURI looks like an oversight — the cleaned path is reused for both ACL matching and redirect construction, when ideally the original query string would be preserved for the redirect while still being stripped for ACL checks. There's no existing issue or PR specifically tracking this redirect behavior.

    For context, a related (but distinct) query-parameter bug in the OIDC controller was fixed in v5.1.0-rc.2 via PR #1003 — that one ensured existing query params in OIDC redirect URIs weren't clobbered during callback construction. A similar approach could work here: preserve the raw query string separately before cleaning the path for ACLs, then re-attach it when building RedirectURI.

    To reply, just mention @dosu.


    Docs are dead. Just use Dosu.

    Leave Feedback Ask Dosu about tinyauth Share Dosu with your team

  2. steveiliop56 commented on Aug 5, 2026

    @steveiliop56
    Member

    Hello @TechieOllie,

    Yeah you are correct that's a bug. It was indeed added as a security measure as mentioned by the bot. Will try to release a fix later this month.

  3. TechieOllie commented on Aug 5, 2026

    @TechieOllie
    Author

    Thank you, look forward to the fix !

    Keep on keeping on !

  4. steveiliop56 commented on Aug 13, 2026

    @steveiliop56
    Member

    Fixed with #1068! Thank you for reporting!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions