spring-projects/spring-security · error · AuthenticationServiceException

Authentication method not supported

Error message

Authentication method not supported: ${request.method}

What it means

UsernamePasswordAuthenticationFilter.attemptAuthentication() only accepts POST requests when postOnly is true (the default). Any other HTTP method (GET, PUT, ...) throws AuthenticationServiceException with the offending method, which surfaces as HTTP 500 unless handled, rather than a normal authentication failure.

Solutions

  1. Set the login form/HTTP client to POST: <form method="post" action="/login">
  2. If non-POST methods are genuinely required, call filter.setPostOnly(false)
  3. For JSON login, use a filter configured with an appropriate converter rather than form login, or a custom attemptAuthentication
  4. Check for redirects (301/302) that convert POST to GET and fix the client to POST directly to the target

Example fix

// before
<form action="/login"> ... </form>
// after
<form method="post" action="/login"> ... </form>
Defensive patterns

Strategy: validation

Validate before calling

if (!"POST".equalsIgnoreCase(request.getMethod())) {
    throw new IllegalStateException("Login must be submitted via POST");
}

Try / catch

try {
    chain.doFilter(request, response, chain);
} catch (AuthenticationServiceException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Authentication method not supported")) {
        response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
        return;
    }
    throw e;
}

Prevention

When it happens

Trigger: Submitting the login form via GET (missing method="POST" on the form), a redirect turning POST into GET, API clients calling the login URL with the wrong verb, or postOnly left default while the frontend uses another method.

Common situations: HTML forms without an explicit method attribute default to GET; login links (href) instead of form submissions; misconfigured proxies/CDNs rewriting methods; custom frontends sending PUT/JSON to the form-login endpoint.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at web/src/main/java/org/springframework/security/web/authentication/UsernamePasswordAuthenticationFilter.java:77

	private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY;

	private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY;

	private boolean postOnly = true;

	public UsernamePasswordAuthenticationFilter() {
		super(DEFAULT_PATH_REQUEST_MATCHER);
	}

	public UsernamePasswordAuthenticationFilter(AuthenticationManager authenticationManager) {
		super(DEFAULT_PATH_REQUEST_MATCHER, authenticationManager);
	}

	@Override
	public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
			throws AuthenticationException {
		if (this.postOnly && !request.getMethod().equals("POST")) {
			throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
		}
		String username = obtainUsername(request);
		username = (username != null) ? username.trim() : "";
		String password = obtainPassword(request);
		password = (password != null) ? password : "";
		UsernamePasswordAuthenticationToken authRequest = UsernamePasswordAuthenticationToken.unauthenticated(username,
				password);
		// Allow subclasses to set the "details" property
		setDetails(request, authRequest);
		return this.getAuthenticationManager().authenticate(authRequest);
	}

	/**
	 * Enables subclasses to override the composition of the password, such as by
	 * including additional values and a separator.
	 * <p>
	 * This might be used for example if a postcode/zipcode was required in addition to
	 * the password. A delimiter such as a pipe (|) should be used to separate the

View on GitHub (pinned to 96852e8860)