spring-projects/spring-security · error · ServletException

Cannot perform login for

Error message

Cannot perform login for '<username>' already authenticated as '<remoteUser>'

What it means

Servlet 3.0 API login(username, password) on the request wrapper refuses to run when the current request is already authenticated. Performing a new programmatic login while an identity is established would silently replace the user, so Spring Security throws ServletException naming both the requested username and the current remote user.

Solutions

  1. Check request.getRemoteUser()/isAuthenticated() before calling login and skip if already authenticated
  2. Invalidate the session and clear authentication before performing a fresh login
  3. Route the flow through a dedicated login endpoint that runs unauthenticated only
  4. Handle ServletException and treat 'already authenticated' as a no-op or redirect

Example fix

// before
request.login(username, password);
// after
if (request.getRemoteUser() == null) {
    request.login(username, password);
}
Defensive patterns

Strategy: type-guard

Validate before calling

// guard before calling login
if (request.getRemoteUser() != null || request.getUserPrincipal() != null) {
    return; // already authenticated, skip login
}

Type guard

function canLogin(HttpServletRequest request) {
    return request.getRemoteUser() == null && request.getUserPrincipal() == null;
}

Try / catch

try {
    request.login(username, password);
} catch (ServletException ex) {
    if (ex.getMessage().startsWith("Cannot perform login for")) {
        // already authenticated: redirect or no-op
    }
}

Prevention

When it happens

Trigger: Calling request.login(username, password) via the HttpServletRequest wrapper created by HttpServlet3RequestFactory when isAuthenticated() is true — i.e. a user is already logged in on this request/session.

Common situations: Re-submitting a login form inside an already-authenticated session; double-invoking login logic (e.g. filter plus controller both call login); session reuse after SSO/auto-login already authenticated the request.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10). Data as JSON: /api/errors/751752479df17ddf. Report an issue: GitHub.

Appendix: source

Thrown at web/src/main/java/org/springframework/security/web/servletapi/HttpServlet3RequestFactory.java:237

		public boolean authenticate(HttpServletResponse response) throws IOException, ServletException {
			AuthenticationEntryPoint entryPoint = HttpServlet3RequestFactory.this.authenticationEntryPoint;
			if (entryPoint == null) {
				HttpServlet3RequestFactory.this.logger.debug(
						"authenticationEntryPoint is null, so allowing original HttpServletRequest to handle authenticate");
				return super.authenticate(response);
			}
			if (isAuthenticated()) {
				return true;
			}
			entryPoint.commence(this, response,
					new AuthenticationCredentialsNotFoundException("User is not Authenticated"));
			return false;
		}

		@Override
		public void login(String username, String password) throws ServletException {
			if (isAuthenticated()) {
				throw new ServletException("Cannot perform login for '" + username + "' already authenticated as '"
						+ getRemoteUser() + "'");
			}
			AuthenticationManager authManager = HttpServlet3RequestFactory.this.authenticationManager;
			if (authManager == null) {
				HttpServlet3RequestFactory.this.logger
					.debug("authenticationManager is null, so allowing original HttpServletRequest to handle login");
				super.login(username, password);
				return;
			}
			Authentication authentication = getAuthentication(authManager, username, password);
			SecurityContext context = HttpServlet3RequestFactory.this.securityContextHolderStrategy
				.createEmptyContext();
			context.setAuthentication(authentication);
			HttpServlet3RequestFactory.this.securityContextHolderStrategy.setContext(context);
			HttpServlet3RequestFactory.this.securityContextRepository.saveContext(context, this, this.response);
		}

		private Authentication getAuthentication(AuthenticationManager authManager, String username, String password)

View on GitHub (pinned to 96852e8860)