spring-projects/spring-security · error · ServletException

<ex.getMessage()>

Error message

<ex.getMessage()>

What it means

When the wrapper's getAuthentication() delegates to the configured AuthenticationManager and authentication fails (AuthenticationException), the security context is cleared and the exception is rethrown as a ServletException whose message is the original exception message, with the original as cause. This exposes programmatic-authentication failures to the servlet API caller while ensuring no stale authentication remains.

Solutions

  1. Inspect the ServletException cause for the concrete AuthenticationException subclass and message
  2. Correct the credentials or account state the caller supplied
  3. Catch ServletException and map to an appropriate login-failure response instead of a 500
  4. Verify AuthenticationManager/provider configuration if even valid credentials fail

Example fix

// before
request.authenticate(response);
// after
try {
    request.authenticate(response);
} catch (ServletException e) {
    logger.warn("Authentication failed: " + e.getMessage());
    // render login-failure view
}
Defensive patterns

Strategy: try-catch

Validate before calling

// validate credentials are present before attempting authentication
if (username == null || username.isBlank() || password == null || password.isEmpty()) {
    throw new IllegalArgumentException("Username and password required");
}

Try / catch

try {
    request.login(user, pass);
    return true;
} catch (ServletException ex) {
    Throwable cause = ex.getCause();
    if (cause instanceof AuthenticationException authEx) {
        // e.g. BadCredentialsException, DisabledException
        return handleAuthFailure(authEx);
    }
    throw ex;
}

Prevention

When it happens

Trigger: Calling request.authenticate(request)/the wrapper's authentication path when the AuthenticationManager rejects the credentials or token — e.g. BadCredentialsException, DisabledException, LockedException raised inside authenticate().

Common situations: Wrong username/password supplied to programmatic login; account disabled/locked/expired; an AuthenticationProvider throwing due to misconfiguration; token no longer valid at authenticate() time.

Related errors


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

Appendix: source

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

			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)
				throws ServletException {
			try {
				UsernamePasswordAuthenticationToken authentication = UsernamePasswordAuthenticationToken
					.unauthenticated(username, password);
				Object details = HttpServlet3RequestFactory.this.authenticationDetailsSource.buildDetails(this);
				authentication.setDetails(details);
				return authManager.authenticate(authentication);
			}
			catch (AuthenticationException ex) {
				HttpServlet3RequestFactory.this.securityContextHolderStrategy.clearContext();
				throw new ServletException(ex.getMessage(), ex);
			}
		}

		@Override
		public void logout() throws ServletException {
			List<LogoutHandler> handlers = HttpServlet3RequestFactory.this.logoutHandlers;
			if (CollectionUtils.isEmpty(handlers)) {
				HttpServlet3RequestFactory.this.logger
					.debug("logoutHandlers is null, so allowing original HttpServletRequest to handle logout");
				super.logout();
				return;
			}
			Authentication authentication = HttpServlet3RequestFactory.this.securityContextHolderStrategy.getContext()
				.getAuthentication();
			for (LogoutHandler handler : handlers) {
				handler.logout(this, this.response, authentication);
			}
		}

View on GitHub (pinned to 96852e8860)