{"record":{"id":"7e456d9de55a7a16","repo":"amir20/dozzle","slug":"unauthorized-user","errorCode":null,"errorMessage":"Unauthorized user","messagePattern":"Unauthorized user","errorType":"http","errorClass":null,"httpStatus":401,"severity":"error","filePath":"internal/web/index.go","lineNumber":80,"sourceCode":"\nfunc (h *handler) executeTemplate(w http.ResponseWriter, req *http.Request) {\n\tbase := \"\"\n\tif h.config.Base != \"/\" {\n\t\tbase = h.config.Base\n\t}\n\n\tuser := auth.UserFromContext(req.Context())\n\n\t// Handle unauthorized cases early\n\tif user == nil {\n\t\tswitch h.config.Authorization.Provider {\n\t\tcase FORWARD_PROXY:\n\t\t\tlog.Error().Msg(\"Unable to find remote user. Please check your proxy configuration. Expecting headers Remote-Email, Remote-User, Remote-Name.\")\n\t\t\tlog.Debug().Str(\"url\", req.URL.String()).Msg(\"Dumping all headers for request\")\n\t\t\tfor k, v := range req.Header {\n\t\t\t\tlog.Debug().Strs(k, v).Send()\n\t\t\t}\n\t\t\thttp.Error(w, \"Unauthorized user\", http.StatusUnauthorized)\n\t\t\treturn\n\t\tcase SIMPLE:\n\t\t\tif req.URL.Path != \"login\" {\n\t\t\t\tlog.Debug().Str(\"url\", req.URL.String()).Msg(\"Redirecting to login page\")\n\t\t\t\thttp.Redirect(w, req, path.Clean(h.config.Base+\"/login\")+\"?redirectUrl=/\"+req.URL.String(), http.StatusTemporaryRedirect)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\tconfig := map[string]any{\n\t\t\"base\": base,\n\t}\n\n\t// Build full config when authorized (no auth or authenticated user)\n\tif h.config.Authorization.Provider == NONE || user != nil {\n\t\thosts := h.hostService.Hosts()\n\t\tsort.Slice(hosts, func(i, j int) bool {","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/amir20/dozzle/blob/d9463cbe21874e44ab79db6fa63e746ca7d22928/internal/web/index.go#L62-L98","documentation":"In forward-proxy auth mode, executeTemplate requires the authenticating proxy to inject Remote-Email, Remote-User, and Remote-Name headers. When none are present the request is rejected with 401 \"Unauthorized user\" because Dozzle cannot identify the user.","triggerScenarios":"Accessing any Dozzle page through a forward-proxy setup where the proxy does not set the Remote-* headers (unauthenticated request, misconfigured authelia/authentik bypass, direct access bypassing the proxy).","commonSituations":"Reaching Dozzle directly on its port instead of through the auth proxy; proxy configured but its forwarded header names customized without mapping; auth provider session expired and proxy let the request through unauthenticated.","solutions":["Access Dozzle only through the authenticating reverse proxy, not its exposed port.","Configure the proxy to forward Remote-Email, Remote-User, and Remote-Name headers.","Re-authenticate with the proxy provider if the session expired."],"exampleFix":"# before (nginx, no headers)\nproxy_pass http://dozzle:8080;\n# after\nproxy_set_header Remote-User $remote_user;\nproxy_set_header Remote-Email $remote_user@example.com;\nproxy_set_header Remote-Name $remote_user;\nproxy_pass http://dozzle:8080;","handlingStrategy":"validation","validationCode":"// client-side: detect the 401 and redirect through the proxy login\nconst res = await fetch('/', { redirect: 'manual' });\nif (res.status === 401) location.href = '/login-path-of-your-proxy';","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never expose Dozzle's port directly; route all traffic through the auth proxy.","Verify the proxy forwards Remote-User, Remote-Email, Remote-Name headers.","Check proxy logs when 401s cluster around session expiry."],"tags":["auth","proxy","http"],"backgroundTag":"authentication-required","analyzedSha":"d9463cbe21874e44ab79db6fa63e746ca7d22928","analyzedAt":"2026-09-07T10:08:55.855Z","contentChangedAt":"2026-09-07T10:08:55.855Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}