{"record":{"id":"3b4a0031b890f7ac","repo":"amir20/dozzle","slug":"missing-token-parameter","errorCode":null,"errorMessage":"missing token parameter","messagePattern":"missing token parameter","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"internal/web/cloud.go","lineNumber":48,"sourceCode":"func (h *handler) requireCloudRole(next http.Handler) http.Handler {\n\treturn http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif h.config.Authorization.Provider != NONE {\n\t\t\tuser := auth.UserFromContext(r.Context())\n\t\t\tif user == nil || !user.Roles.Has(auth.Cloud) {\n\t\t\t\tlog.Warn().Msg(\"user is not permitted to manage cloud\")\n\t\t\t\thttp.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t\tnext.ServeHTTP(w, r)\n\t})\n}\n\nfunc (h *handler) cloudCallback(w http.ResponseWriter, r *http.Request) {\n\ttoken := r.URL.Query().Get(\"token\")\n\tfrom := r.URL.Query().Get(\"from\")\n\tif token == \"\" {\n\t\thttp.Error(w, \"missing token parameter\", http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tcloudURL := os.Getenv(\"DOLIGENCE_URL\")\n\tif cloudURL == \"\" {\n\t\tcloudURL = \"https://doligence.dozzle.dev\"\n\t}\n\n\texchangeURL := fmt.Sprintf(\"%s/api/exchange-token\", cloudURL)\n\n\tclient := cloudHTTPClient\n\treq, err := http.NewRequestWithContext(r.Context(), http.MethodPost, exchangeURL, nil)\n\tif err != nil {\n\t\tlog.Error().Err(err).Msg(\"Failed to create request\")\n\t\thttp.Error(w, \"failed to create request\", http.StatusInternalServerError)\n\t\treturn\n\t}\n\treq.Header.Set(\"User-Agent\", dispatcher.UserAgent)","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/amir20/dozzle/blob/d9463cbe21874e44ab79db6fa63e746ca7d22928/internal/web/cloud.go#L30-L66","documentation":"cloudCallback is the OAuth-style redirect handler for the Dozzle cloud (doligence) service. It reads `token` (and `from`) from the callback URL query string; if `token` is missing or empty it returns 400 with this message. The token is required to exchange for a cloud key on the remote service.","triggerScenarios":"Visiting /cloud/callback (or equivalent route) without a `token` query parameter, e.g. navigating directly to the callback URL, a truncated redirect URL, or a misconfigured cloud-side redirect that drops the query string.","commonSituations":"User bookmarks or shares the callback URL without params; reverse proxy strips query strings; the cloud service redirects incorrectly after login failure; copying the URL partially from the browser.","solutions":["Retry the cloud connect flow from the beginning so a fresh token is included in the redirect.","Check that the redirect URL reaching dozzle still contains ?token=... (inspect reverse proxy / cloud redirect config).","If a proxy strips query params, fix the proxy configuration to preserve the full request URI."],"exampleFix":"// before\nhttps://dozzle.example.com/cloud/callback\n// after\nhttps://dozzle.example.com/cloud/callback?token=<jwt>&from=agents","handlingStrategy":"validation","validationCode":"const url = new URL(window.location.href);\nif (!url.searchParams.get('token')) {\n    // restart the cloud connect flow instead of using this callback URL\n}","typeGuard":"function hasToken(params: URLSearchParams): params is URLSearchParams & { get(k: 'token'): string } {\n    return !!params.get('token');\n}","tryCatchPattern":null,"preventionTips":["Never bookmark or share the callback URL; always restart the flow from the UI.","Ensure proxies preserve query strings on redirects.","Validate the redirect URL construction on the cloud side."],"tags":["http-400","query-parameter","oauth-callback"],"backgroundTag":"missing-required-argument","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"}