{"record":{"id":"b6d3e8d83c9bf6d9","repo":"SonarSource/sonarqube","slug":"user-is-not-authenticated","errorCode":null,"errorMessage":"User is not authenticated","messagePattern":"User is not authenticated","errorType":"exception","errorClass":"UnauthorizedException","httpStatus":401,"severity":"error","filePath":"server/sonar-webserver-auth/src/main/java/org/sonar/server/user/ThreadLocalUserSession.java","lineNumber":45,"sourceCode":"import org.sonar.db.entity.EntityDto;\nimport org.sonar.db.permission.GlobalPermission;\nimport org.sonar.db.permission.ProjectPermission;\nimport org.sonar.db.user.GroupDto;\nimport org.sonar.server.exceptions.UnauthorizedException;\n\n/**\n * Part of the current HTTP session\n */\npublic class ThreadLocalUserSession implements UserSession {\n\n  private static final ThreadLocal<UserSession> DELEGATE = new ThreadLocal<>();\n\n  public UserSession get() {\n    UserSession session = DELEGATE.get();\n    if (session != null) {\n      return session;\n    }\n    throw new UnauthorizedException(\"User is not authenticated\");\n  }\n\n  public void set(UserSession session) {\n    DELEGATE.set(session);\n  }\n\n  public void unload() {\n    DELEGATE.remove();\n  }\n\n  public boolean hasSession() {\n    return DELEGATE.get() != null;\n  }\n\n  @Override\n  @CheckForNull\n  public Long getLastSonarlintConnectionDate() {\n    return get().getLastSonarlintConnectionDate();","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/ThreadLocalUserSession.java#L27-L63","documentation":"ThreadLocalUserSession.get() is the accessor for the request-scoped UserSession stored in a ThreadLocal. When get() is called before any session has been bound to the current thread (DELEGATE.get() returns null), it throws UnauthorizedException('User is not authenticated'). The server uses this to signal that the current request carries no valid user session.","triggerScenarios":"Calling any accessor (getLogin, getUuid, getName, getGroups, getIdentityProvider, getLastSonarlintConnectionDate) on ThreadLocalUserSession for a request with no authenticated session, e.g. anonymous request to an endpoint requiring authentication, or a missing/invalid credentials header.","commonSituations":"Scripts or clients calling the SonarQube web API without a token; an expired/revoked token; provisioning or background threads that never set a session before querying user info.","solutions":["Authenticate the request: pass a valid user token ('Authorization: Bearer <token>') or basic credentials to the API call","Check authentication requirements of the endpoint and use an endpoint that permits anonymous access, or enable anonymous access in server settings if intended","Verify the token was not revoked/expired and belongs to an active user (Admin > Security > Users)","In server-side code, ensure UserSession is set via ThreadLocalUserSession.set() before calling accessors"],"exampleFix":"// before\ncurl http://sonar.example.org/api/users/current\n// after\ncurl -u \"mytoken:\" http://sonar.example.org/api/users/current","handlingStrategy":"try-catch","validationCode":"// client: prefer a cheap auth probe before dependent calls\nconst res = await fetch(`${baseUrl}/api/authentication/validate`, { headers: { Authorization: `Bearer ${token}` } });\nif (!res.ok || !(await res.json()).valid) throw new Error('Not authenticated: supply a valid SonarQube user token');","typeGuard":"// Java server-side\nguard: if (sessionRef.get() == null /* or catch UnauthorizedException */) redirect/401 before calling getLogin/getUuid","tryCatchPattern":"try {\n  String login = userSession.getLogin();\n} catch (UnauthorizedException e) {\n  // respond 401 / prompt for token\n  return Response.status(401).build();\n}","preventionTips":["Always send a valid Authorization header (token or basic) for authenticated endpoints","Check /api/authentication/validate or /api/users/current before long workflows","Watch for anonymous mode: endpoints requiring identity still need a token","In server plugins, verify a session exists before using ThreadLocalUserSession accessors"],"tags":["authentication","http","sonarqube"],"backgroundTag":"authentication-required","analyzedSha":"184c821202192afc1c599fc912d0889b69fffa53","analyzedAt":"2026-09-09T12:23:51.573Z","contentChangedAt":"2026-09-09T12:23:51.573Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}