SonarSource/sonarqube · warning · UnauthorizedException

Authentication is required

Error message

Authentication is required

What it means

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.

Solutions

  1. Authenticate first: supply a valid token (Authorization header) or log in to obtain a session
  2. Refresh/renew expired credentials and retry
  3. Verify the endpoint is not expected to be anonymous; use an anonymous-safe API if so
  4. Check reverse-proxy/security config isn't stripping authentication

Example fix

// before
curl http://sonarqube:9000/api/v2/users/current
// after
curl -H "Authorization: Bearer $SONAR_TOKEN" http://sonarqube:9000/api/v2/users/current
Defensive patterns

Strategy: try-catch

Validate before calling

// verify credentials are present before the call
if (token == null || token.isBlank()) throw new IllegalStateException("SONAR_TOKEN not set");

Try / catch

try {
    user = api.usersCurrent();
} catch (UnauthorizedException | ForbiddenException e) {
    // 401: (re)authenticate, refresh token, then retry once
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Related errors


AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09). Data as JSON: /api/errors/e7b7f19dc5a1ec09. Report an issue: GitHub.

Appendix: source

Thrown at server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/security/SecurityContextBackedUserSession.java:60

 * <p>For backwards compatibility with code that expects ThreadLocalUserSession,
 * this wrapper allows legacy code to continue working while the actual user data
 * lives in SecurityContext.</p>
 *
 * <p><strong>Architecture:</strong> All methods delegate to the original UserSession
 * stored in UserSessionAuthentication within SecurityContext. This eliminates
 * dual ThreadLocal storage.</p>
 */
public class SecurityContextBackedUserSession implements UserSession {

  /**
   * Get the UserSession from SecurityContext.
   * This extracts the actual UserSession stored in the SonarUserDetails principal.
   */
  private static UserSession delegate() {
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

    if (authentication == null || authentication instanceof AnonymousAuthenticationToken) {
      throw new UnauthorizedException("Authentication is required");
    }

    // Extract UserSession from SonarUserDetails principal
    Object principal = authentication.getPrincipal();
    if (principal instanceof SonarUserDetails sonarUserDetails) {
      return sonarUserDetails.getUserSession();
    }

    throw new UnauthorizedException("UserSession not found in authentication principal");
  }

  @Override
  @CheckForNull
  public String getLogin() {
    return delegate().getLogin();
  }

  @Override

View on GitHub (pinned to 184c821202)