{"record":{"id":"315d0fea8ca5305e","repo":"languagetool-org/languagetool","slug":"expected-basic-authentication","errorCode":null,"errorMessage":"Expected Basic Authentication","messagePattern":"Expected Basic Authentication","errorType":"http","errorClass":"AuthException","httpStatus":401,"severity":"error","filePath":"languagetool-server/src/main/java/org/languagetool/server/ApiV2.java","lineNumber":360,"sourceCode":"\n  /*\n   * Provide information on user that requests this, e.g. for add-on to acquire token + other information\n   * Expects user + password via HTTP Basic Auth\n   */\n  private void handleGetUserInfoRequest(HttpExchange httpExchange, Map<String, String> parameters, HTTPServerConfig config) throws Exception {\n    if (httpExchange.getRequestMethod().equalsIgnoreCase(\"options\")) {\n      ServerTools.setAllowOrigin(httpExchange, allowOriginUrl);\n      httpExchange.getResponseHeaders().put(\"Access-Control-Allow-Methods\", Collections.singletonList(\"GET, OPTIONS\"));\n      List<String> requestHeaders = httpExchange.getRequestHeaders().get(\"Access-Control-Request-Headers\");\n      if (requestHeaders != null) {\n        httpExchange.getResponseHeaders().put(\"Access-Control-Allow-Headers\", Collections.singletonList(String.join(\", \", requestHeaders)));\n      }\n      httpExchange.sendResponseHeaders(HttpURLConnection.HTTP_NO_CONTENT, -1);\n      ServerMetricsCollector.getInstance().logResponse(HttpURLConnection.HTTP_NO_CONTENT);\n    } else {\n      ensureGetMethod(httpExchange, \"/users/me\");\n      if (!httpExchange.getRequestHeaders().containsKey(\"Authorization\")) {\n        throw new AuthException(\"Expected Basic Authentication\");\n      }\n      String authParameter = parameters.getOrDefault(\"authMethod\", \"password\");\n      if (!(authParameter.equals(\"password\") || \n            authParameter.equals(\"apiKey\") || \n            authParameter.equals(\"addonToken\"))) {\n        throw new IllegalArgumentException(\"Unknown authMethod: \" + authParameter);\n      }\n\n      String authHeader = httpExchange.getRequestHeaders().getFirst(\"Authorization\");\n      BasicAuthentication basicAuthentication = new BasicAuthentication(authHeader);\n      String user = basicAuthentication.getUser();\n      String password = basicAuthentication.getPassword();\n      UserInfoEntry userInfo = null;\n\n      if (authParameter.equals(\"password\")) {\n        userInfo = DatabaseAccess.getInstance().getUserInfoWithPassword(user, password);\n      } else if (authParameter.equals(\"addonToken\")) {\n        userInfo = DatabaseAccess.getInstance().getUserInfoWithAddonToken(user, password);","sourceCodeStart":342,"sourceCodeEnd":378,"githubUrl":"https://github.com/languagetool-org/languagetool/blob/2e990059ce67d5e2a0f7f7ca5d31160c6709df4b/languagetool-server/src/main/java/org/languagetool/server/ApiV2.java#L342-L378","documentation":"GET /v2/users/me authenticates the caller via the HTTP 'Authorization' header (Basic Authentication). handleGetUserInfoRequest checks the header first and throws an AuthException when it is absent, because user information can never be resolved without credentials.","triggerScenarios":"GET /v2/users/me with username/token only as query parameters and no Authorization header; HTTP clients stripping the header after redirects; API explorers that do not send Basic auth headers.","commonSituations":"Browsers or fetch calls omitting the header; reverse proxies removing Authorization headers; tests built against an anonymous server setup then pointed at the authenticated endpoint.","solutions":["Add an Authorization: Basic base64(user:password) header to the request.","Prefer the header over query-parameter credentials for /users/me, as the header is mandatory here.","Check that redirects (302) preserve the Authorization header or re-attach it manually.","Verify no proxy or CORS preflight configuration strips the header."],"exampleFix":"// before\ncurl https://server/v2/users/me?username=jane&token=abc\n// after\ncurl -u jane:abc https://server/v2/users/me","handlingStrategy":"validation","validationCode":"const headers = { Authorization: 'Basic ' + btoa(user + ':' + token) };\nif (!headers.Authorization) throw new Error('users/me requires a Basic Authorization header');","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always set the Authorization header for /v2/users/me.","Use credentials helpers (curl -u, HTTP basic auth options) rather than hand-built headers.","Confirm proxies/redirects do not strip the Authorization header."],"tags":["http","authentication","rest-api","languagetool"],"backgroundTag":"authentication-required","analyzedSha":"2e990059ce67d5e2a0f7f7ca5d31160c6709df4b","analyzedAt":"2026-09-06T09:20:17.015Z","contentChangedAt":"2026-09-06T09:20:17.015Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}