{"record":{"id":"50d100d6ad3d4ca6","repo":"gotify/server","slug":"basic-auth-required","errorCode":null,"errorMessage":"basic auth required","messagePattern":"basic auth required","errorType":"http","errorClass":null,"httpStatus":401,"severity":"error","filePath":"api/session.go","lineNumber":69,"sourceCode":"//\t        type: string\n//\t        description: session cookie\n//\t  401:\n//\t    description: Unauthorized\n//\t    schema:\n//\t        $ref: \"#/definitions/Error\"\n//\t  403:\n//\t    description: Forbidden\n//\t    schema:\n//\t        $ref: \"#/definitions/Error\"\nfunc (a *SessionAPI) Login(ctx *gin.Context) {\n\tif !a.LocalAuthEnabled {\n\t\tctx.AbortWithError(403, errors.New(\"local authentication is disabled\"))\n\t\treturn\n\t}\n\n\tname, pass, ok := ctx.Request.BasicAuth()\n\tif !ok {\n\t\tctx.AbortWithError(401, errors.New(\"basic auth required\"))\n\t\treturn\n\t}\n\n\tuser, err := a.DB.GetUserByName(name)\n\tif err != nil {\n\t\tctx.AbortWithError(500, err)\n\t\treturn\n\t}\n\tif user == nil || !password.ComparePassword(user.Pass, []byte(pass)) {\n\t\tctx.AbortWithError(401, errors.New(\"invalid credentials\"))\n\t\treturn\n\t}\n\n\tclientParams := ClientParams{}\n\tif err := ctx.Bind(&clientParams); err != nil {\n\t\treturn\n\t}\n","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/gotify/server/blob/14bfc256276775c425f988d621dccfe705de18ac/api/session.go#L51-L87","documentation":"This error is returned by the Login endpoint (SessionAPI.Login) when the HTTP request carries no Basic Authentication credentials at all. gin's ctx.Request.BasicAuth() fails to parse an Authorization header of type 'Basic', so the handler aborts with 401 before ever looking up the user. It is an authentication-transport problem, not a wrong-password problem.","triggerScenarios":"POST to the login/session endpoint without an Authorization header; using a Bearer token, cookie, or custom header instead of 'Authorization: Basic base64(user:pass)'; a client/proxy stripping the Authorization header; malformed base64 or a colon-less username so BasicAuth() returns ok=false.","commonSituations":"Clients using OAuth/bearer flows against an API that only accepts basic auth; curl users forgetting -u user:pass; reverse proxies (nginx) configured with their own basic-auth layer consuming the header; frontend fetch calls setting headers: {'Content-Type': 'json'} but never the Authorization header; API changes where token-based login replaced basic auth.","solutions":["Send a proper Basic auth header: curl -u name:pass ... or Authorization: Basic <base64(name:pass)>","Verify the header survives to the backend (no proxy stripping it); check with curl -v","base64-encode username:password correctly (username may contain a colon; encode as 'user:pass')","If token auth is intended, use the endpoint/route that accepts client tokens instead of the local-login basic-auth route"],"exampleFix":"// before\nfetch('/api/session', { method: 'POST' })\n// after\nfetch('/api/session', { method: 'POST', headers: { 'Authorization': 'Basic ' + btoa(username + ':' + password) } })","handlingStrategy":"validation","validationCode":"function hasBasicAuth(headers) {\n  const h = headers['Authorization'] || headers['authorization'] || '';\n  return /^Basic\\s+[A-Za-z0-9+/=]+$/.test(h);\n}\nif (!hasBasicAuth(myHeaders)) throw new Error('attach Authorization: Basic base64(user:pass) before calling login');","typeGuard":"function isBasicAuthHeader(v) {\n  return typeof v === 'string' && /^Basic\\s+[A-Za-z0-9+/=]+$/.test(v);\n}","tryCatchPattern":null,"preventionTips":["Always build the Authorization header with a battle-tested helper (btoa/axios auth config), never by hand","Use curl -v once to confirm the header reaches the server unstripped","Document that the login endpoint only accepts Basic auth, not Bearer tokens","Check proxies (nginx/ingress) for auth modules that consume the Authorization header"],"tags":["http","authentication","basic-auth","gin"],"backgroundTag":"missing-basic-auth-credentials","analyzedSha":"14bfc256276775c425f988d621dccfe705de18ac","analyzedAt":"2026-09-05T12:52:36.781Z","contentChangedAt":"2026-09-05T12:52:36.781Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}