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
- Check request.getRemoteUser()/isAuthenticated() before calling login and skip if already authenticated
- Invalidate the session and clear authentication before performing a fresh login
- Route the flow through a dedicated login endpoint that runs unauthenticated only
- 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
- Only expose login flows on unauthenticated routes
- Check isAuthenticated()/getRemoteUser() before programmatic login
- Avoid calling login from multiple layers (filter + controller) for the same request
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.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- <ex.getMessage()>
- AccountStatusUserDetailsChecker.disabled
- AccountStatusUserDetailsChecker.expired
- An Authentication object was not found in the…
- Authenticated principal required to operate with ACLs
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)