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.

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