Invalid_request without any logs in the monitoring dashboard

Hello,

I am implementing Auth0 with my spring boot application. I want Auth0 to handle the authorization part and also the authentication with OAuth2.0.

I integrated Auth0 in my application with basic configuration and it was working just fine.

However i wanted to integrate custom use case to my application. Therefore i added a CustomOAuthAuthenticationSuccessHandler to get roles from Auth0 Api management and adding them as authorities (roles) to my application using the SecurityContextHolder.

However i get an invalid_request from Auth0 without any log or clue about the error and i am not able to log in successfully.

Here is the error

Can you help me on this please ?

I have resolved the issue. I changed my CustomOAuthAuthenticationSuccessHandler implementation. Instead of creating a UserPasswordToken (done previously) i am now creating an OAuth2AuthenticationToken.

After successful attribution of authorities i finally redirect to root page (“/”)

Here is my Handler implementation in case it may be helpful:

package com.interco.reconciliation.handler;

import com.interco.reconciliation.service.Auth0ApiManagementService;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
import com.mashape.unirest.http.exceptions.UnirestException;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;


@Component
public class CustomOAuthAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

    private static final Logger logger = Logger.getLogger(CustomOAuthAuthenticationSuccessHandler.class.getName());

    @Autowired
    private Auth0ApiManagementService auth0ApiManagementService;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        logger.info("Authentication successful. Retrieving roles.");
        // Get the initial list of authorities for authenticated user
        List<GrantedAuthority> authorities = new ArrayList<>(authentication.getAuthorities());

        // Get userId
        OAuth2User principal = (OAuth2User) authentication.getPrincipal();
        OAuth2AuthenticationToken oauthToken = (OAuth2AuthenticationToken) authentication;
        String userId = principal.getAttribute("sub");

        try {
            HttpResponse<JsonNode> roles = this.auth0ApiManagementService.getUserRoles(userId);
            JsonNode rolesBody = roles.getBody();
            for(int i = 0; i < rolesBody.getArray().length(); i++) {
                JSONObject role = rolesBody.getArray().getJSONObject(i);
                String roleName = role.getString("name");
                authorities.add(new SimpleGrantedAuthority("ROLE_" + roleName));
            }

        } catch(UnirestException | UnsupportedEncodingException e) {
            logger.severe("Error fetching roles from Auth0: " + e.getMessage());
            throw new RuntimeException(e);
        }
        logger.info("Roles retrieved and added to authorities: " + authorities.toString());

        OAuth2AuthenticationToken newAuth = new OAuth2AuthenticationToken(principal, authorities, oauthToken.getAuthorizedClientRegistrationId());
        newAuth.setDetails(new WebAuthenticationDetails(request));

        SecurityContextHolder.getContext().setAuthentication(newAuth);

        response.sendRedirect("/");
    }
}

And in my Web Security Configuration file this is how i implemented it:

package com.interco.reconciliation.config;

import static org.springframework.security.config.Customizer.withDefaults;

import com.interco.reconciliation.handler.CustomOAuthAuthenticationSuccessHandler;
import com.interco.reconciliation.service.CustomOAuth2UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.web.SecurityFilterChain;

import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import java.io.IOException;


@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig {

	@Value("${okta.oauth2.issuer}")
	private String issuer;
	@Value("${okta.oauth2.client-id}")
	private String clientId;
	@Autowired
	private CustomOAuth2UserService customOAuth2UserService;
	@Autowired
	private CustomOAuthAuthenticationSuccessHandler customOAuthAuthenticationSuccessHandler;


	@Bean
	public SecurityFilterChain configure(HttpSecurity http) throws Exception {
		http
				.csrf(AbstractHttpConfigurer::disable) // remove later or configure appropriately in production
				.cors(withDefaults()) // remove later or configure appropriately in production
				.authorizeHttpRequests(authorize -> authorize
						.requestMatchers("/").permitAll()
						.anyRequest().authenticated()
				)
				.oauth2Login(oauth2Login ->
						oauth2Login
								.userInfoEndpoint(userInfoEndpoint ->
										userInfoEndpoint.userService(customOAuth2UserService))
								.successHandler(customOAuthAuthenticationSuccessHandler)
				)
				.logout(logout -> logout
						.addLogoutHandler(logoutHandler()));
		return http.build();
	}


	private LogoutHandler logoutHandler() {
		return (request, response, authentication) -> {
			try {
				String baseUrl = ServletUriComponentsBuilder.fromCurrentContextPath().build().toUriString();
				response.sendRedirect(issuer + "v2/logout?client_id=" + clientId + "&returnTo=" + baseUrl);
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
		};
	}

}