{"record":{"id":"e7b7f19dc5a1ec09","repo":"SonarSource/sonarqube","slug":"authentication-is-required-e7b7f1","errorCode":null,"errorMessage":"Authentication is required","messagePattern":"Authentication is required","errorType":"http","errorClass":"UnauthorizedException","httpStatus":401,"severity":"warning","filePath":"server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/security/SecurityContextBackedUserSession.java","lineNumber":60,"sourceCode":" * <p>For backwards compatibility with code that expects ThreadLocalUserSession,\n * this wrapper allows legacy code to continue working while the actual user data\n * lives in SecurityContext.</p>\n *\n * <p><strong>Architecture:</strong> All methods delegate to the original UserSession\n * stored in UserSessionAuthentication within SecurityContext. This eliminates\n * dual ThreadLocal storage.</p>\n */\npublic class SecurityContextBackedUserSession implements UserSession {\n\n  /**\n   * Get the UserSession from SecurityContext.\n   * This extracts the actual UserSession stored in the SonarUserDetails principal.\n   */\n  private static UserSession delegate() {\n    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();\n\n    if (authentication == null || authentication instanceof AnonymousAuthenticationToken) {\n      throw new UnauthorizedException(\"Authentication is required\");\n    }\n\n    // Extract UserSession from SonarUserDetails principal\n    Object principal = authentication.getPrincipal();\n    if (principal instanceof SonarUserDetails sonarUserDetails) {\n      return sonarUserDetails.getUserSession();\n    }\n\n    throw new UnauthorizedException(\"UserSession not found in authentication principal\");\n  }\n\n  @Override\n  @CheckForNull\n  public String getLogin() {\n    return delegate().getLogin();\n  }\n\n  @Override","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/security/SecurityContextBackedUserSession.java#L42-L78","documentation":"UnauthorizedException thrown by SecurityContextBackedUserSession.delegate() when the Spring Security context holds no Authentication or an AnonymousAuthenticationToken, meaning no user is authenticated. All UserSession operations delegated through this wrapper require a real authenticated principal.","triggerScenarios":"Any API call routed through SecurityContextBackedUserSession (getLogin, getPermissions, etc.) while unauthenticated or anonymous — e.g. missing/invalid token, expired session, or endpoint invoked without security filter populating the context.","commonSituations":"Expired or missing bearer token, calling a protected endpoint from a script without credentials, session invalidated server-side, misconfigured security filter chain letting anonymous principals through.","solutions":["Authenticate first: supply a valid token (Authorization header) or log in to obtain a session","Refresh/renew expired credentials and retry","Verify the endpoint is not expected to be anonymous; use an anonymous-safe API if so","Check reverse-proxy/security config isn't stripping authentication"],"exampleFix":"// before\ncurl http://sonarqube:9000/api/v2/users/current\n// after\ncurl -H \"Authorization: Bearer $SONAR_TOKEN\" http://sonarqube:9000/api/v2/users/current","handlingStrategy":"try-catch","validationCode":"// verify credentials are present before the call\nif (token == null || token.isBlank()) throw new IllegalStateException(\"SONAR_TOKEN not set\");","typeGuard":null,"tryCatchPattern":"try {\n    user = api.usersCurrent();\n} catch (UnauthorizedException | ForbiddenException e) {\n    // 401: (re)authenticate, refresh token, then retry once\n}","preventionTips":["Keep tokens valid and rotate before expiry","Always send Authorization header for protected v2 endpoints","Handle 401 by re-authenticating rather than retrying blindly"],"tags":["java","authentication","spring-security"],"backgroundTag":"authentication-required","analyzedSha":"184c821202192afc1c599fc912d0889b69fffa53","analyzedAt":"2026-09-09T12:23:51.573Z","contentChangedAt":"2026-09-09T12:23:51.573Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}