spring-projects/spring-security · error · AccessDeniedException

Can't change password as no Authentication object found in c

Error message

Can't change password as no Authentication object found in context for current user.

What it means

JdbcUserDetailsManager.changePassword requires an Authentication in the SecurityContextHolder to know which user's password to change; if none is present it throws AccessDeniedException. The class then optionally re-authenticates the user against the configured AuthenticationManager before performing the UPDATE. This mirrors InMemoryUserDetailsManager's behavior and is treated as a caller/configuration error.

Source

Thrown at core/src/main/java/org/springframework/security/provisioning/JdbcUserDetailsManager.java:319

	public void deleteUser(String username) {
		if (getEnableAuthorities()) {
			deleteUserAuthorities(username);
		}
		requireJdbcTemplate().update(this.deleteUserSql, username);
		this.userCache.removeUserFromCache(username);
	}

	private void deleteUserAuthorities(String username) {
		requireJdbcTemplate().update(this.deleteUserAuthoritiesSql, username);
	}

	@Override
	public void changePassword(@Nullable String oldPassword, @Nullable String newPassword)
			throws AuthenticationException {
		Authentication currentUser = this.securityContextHolderStrategy.getContext().getAuthentication();
		if (currentUser == null) {
			// This would indicate bad coding somewhere
			throw new AccessDeniedException(
					"Can't change password as no Authentication object found in context " + "for current user.");
		}
		String username = currentUser.getName();
		// If an authentication manager has been set, re-authenticate the user with the
		// supplied password.
		if (this.authenticationManager != null) {
			this.logger.debug(LogMessage.format("Reauthenticating user '%s' for password change request.", username));
			this.authenticationManager
				.authenticate(UsernamePasswordAuthenticationToken.unauthenticated(username, oldPassword));
		}
		else {
			this.logger.debug("No authentication manager set. Password won't be re-checked.");
		}
		this.logger.debug("Changing password for user '" + username + "'");
		requireJdbcTemplate().update(this.changePasswordSql, newPassword, username);
		Authentication authentication = createNewAuthentication(currentUser, newPassword);
		SecurityContext context = this.securityContextHolderStrategy.createEmptyContext();
		context.setAuthentication(authentication);

View on GitHub (pinned to 96852e8860)

Solutions

  1. Invoke changePassword only within an authenticated context (authenticated request or explicit SecurityContextHolder.getContext().setAuthentication(...))
  2. In tests, use @WithMockUser or set an Authentication in the SecurityContextHolder before the call
  3. Wire an AuthenticationManager into JdbcUserDetailsManager so re-authentication with oldPassword works as intended
  4. For unauthenticated reset flows, look up the user directly and update via JDBC or an admin path instead of changePassword

Example fix

// before
jdbcManager.changePassword("old", "new"); // AccessDeniedException
// after
Authentication auth = new UsernamePasswordAuthenticationToken("alice", null);
SecurityContextHolder.getContext().setAuthentication(auth);
jdbcManager.changePassword("old", "new");
Defensive patterns

Strategy: try-catch

Validate before calling

Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth == null || auth instanceof AnonymousAuthenticationToken) {
    throw new AccessDeniedException("Authentication required to change password");
}

Type guard

static boolean hasAuthentication() {
    Authentication a = SecurityContextHolder.getContext().getAuthentication();
    return a != null && a.isAuthenticated();
}

Try / catch

try {
    jdbcManager.changePassword(oldPassword, newPassword);
} catch (AccessDeniedException e) {
    if (e.getMessage().contains("no Authentication object")) {
        // force re-login before password change
    } else if (e instanceof AuthenticationException) {
        // oldPassword re-authentication failed
    } else { throw e; }
}

Prevention

When it happens

Trigger: Calling changePassword when the current thread has no authenticated SecurityContext; running inside a scheduled job or message listener without propagating SecurityContext; a security filter chain that never populates the context for the endpoint; unit tests invoking the method directly without authentication.

Common situations: Password reset flows implemented as unauthenticated endpoints; integration tests missing @WithMockUser; Spring remoting/async execution dropping the context between request and password change.

Understand the failure class

Related errors


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