{"record":{"id":"213d2987d8daed3c","repo":"dutchcoders/transfer.sh","slug":"not-authorized","errorCode":null,"errorMessage":"Not authorized","messagePattern":"Not authorized","errorType":"http","errorClass":null,"httpStatus":401,"severity":"error","filePath":"server/handlers.go","lineNumber":1379,"sourceCode":"\n\t\t\ts.htpasswdFile = htpasswdFile\n\t\t}\n\n\t\tif s.authIPFilter == nil && s.authIPFilterOptions != nil {\n\t\t\ts.authIPFilter = newIPFilter(s.authIPFilterOptions)\n\t\t}\n\n\t\tw.Header().Set(\"WWW-Authenticate\", \"Basic realm=\\\"Restricted\\\"\")\n\n\t\tvar authorized bool\n\t\tif s.authIPFilter != nil {\n\t\t\tremoteIP := realip.FromRequest(r)\n\t\t\tauthorized = s.authIPFilter.Allowed(remoteIP)\n\t\t}\n\n\t\tusername, password, authOK := r.BasicAuth()\n\t\tif !authOK && !authorized {\n\t\t\thttp.Error(w, \"Not authorized\", http.StatusUnauthorized)\n\t\t\treturn\n\t\t}\n\n\t\tif !authorized && username == s.authUser && password == s.authPass {\n\t\t\tauthorized = true\n\t\t}\n\n\t\tif !authorized && s.htpasswdFile != nil {\n\t\t\tauthorized = s.htpasswdFile.Match(username, password)\n\t\t}\n\n\t\tif !authorized {\n\t\t\thttp.Error(w, \"Not authorized\", http.StatusUnauthorized)\n\t\t\treturn\n\t\t}\n\n\t\th.ServeHTTP(w, r)\n\t}","sourceCodeStart":1361,"sourceCodeEnd":1397,"githubUrl":"https://github.com/dutchcoders/transfer.sh/blob/c37bfd95797fd6da8a6da53fc13d191994b3f687/server/handlers.go#L1361-L1397","documentation":"The auth middleware requires either a successful Basic Auth parse or prior authorization (e.g. IP filter allowlist). If the request has no valid Authorization header and the client IP is not pre-authorized, it responds 401 'Not authorized'.","triggerScenarios":"Request without an Authorization: Basic header (authOK false) while the remote IP was not already authorized by the IP filter, on a server configured with authUser/authPass or htpasswd protection.","commonSituations":"Client omitted credentials entirely; browser fetch() calls dropping credentials without credentials:'include'; API clients hitting a protected endpoint directly; reverse proxy stripping the Authorization header.","solutions":["Send Basic Auth credentials, e.g. curl -u user:pass https://linx/...","For browsers, set fetch(url, {credentials:'include'}) so saved credentials are sent","Check that no reverse proxy in front strips or rewrites the Authorization header","If access should be IP-based, add the client IP to the configured IP filter allowlist","Verify username/password spelling and that they match authUser/authPass or an htpasswd entry"],"exampleFix":"// before\nfetch('https://linx/upload', {method:'POST', body:form})\n// after\nconst auth = btoa('user:pass')\nfetch('https://linx/upload', {method:'POST', body:form, headers:{Authorization:'Basic '+auth}})","handlingStrategy":"try-catch","validationCode":"// client side: confirm credentials are being sent before the request\nif (!authHeader) throw new Error('No Basic credentials configured');\nfetch(url, {headers: {Authorization: authHeader}})","typeGuard":"null","tryCatchPattern":"try {\n  const res = await fetch(url, {headers: {Authorization: 'Basic ' + btoa(user + ':' + pass)}, credentials: 'include'});\n  if (res.status === 401) throw new Error('Not authorized: check credentials or IP allowlist');\n} catch (err) {\n  // prompt for credentials or fall back to an allowed network/IP\n}","preventionTips":["Always send the Authorization header on protected endpoints; use credentials:'include' for browser fetch","Confirm no proxy strips Authorization headers","Add client IPs to the allowlist when relying on IP-based authorization","Handle 401 centrally to prompt for credentials"],"tags":["http-401","basic-auth","authentication"],"backgroundTag":"http-401-unauthorized","analyzedSha":"c37bfd95797fd6da8a6da53fc13d191994b3f687","analyzedAt":"2026-09-05T10:21:07.548Z","contentChangedAt":"2026-09-05T10:21:07.548Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}