1

I'm building a service which is responsible for allowing a user to link external services to their user account.

Authentication of the web app is using a JWT passed in via query string.

I have a Controller that is attempting to use the OAuth2AuthorizedClientManager to initiate the OAuth client workflow to redirect the user to the target external service and authorize the access.

I am struggling to get the Authorization Grant flow to start - with the code below, my OAuth2AuthorizedClient is always null.

I believe I have a disconnect on how to best use the ClientManager.

Controller:

private final OAuth2AuthorizedClientManager authorizedClientManager;

    @Autowired
    public LinkingController(OAuth2AuthorizedClientManager authorizedClientManager) {
        this.authorizedClientManager = authorizedClientManager;
    }

  @GetMapping("/tenants/{tenantId}/externalsystem/{externalSystemName}/link")
    public ModelAndView linking(@PathVariable Long tenantId, @PathVariable String externalSystemName, Authentication authentication,
                                HttpServletRequest servletRequest,
                                HttpServletResponse servletResponse) {

        // ClientRegistrationRepository does not natively support multi-tenancy, so registrations are
        // Prefixed with a tenantId
        String registrationId = tenantId + "-" + externalSystemName;
        OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId(registrationId)
                .principal(authentication)    // Confirmed this is the correct authentication from the JWT
                .attributes(attrs -> {
                    attrs.put(HttpServletRequest.class.getName(), servletRequest);
                    attrs.put(HttpServletResponse.class.getName(), servletResponse);
                })
                .build();
        OAuth2AuthorizedClient authorizedClient = this.authorizedClientManager.authorize(authorizeRequest);  // Confirmed with debugging that it is using the correct registration repository and finding the correct registration.

        OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
        Map<String, Object> params = new HashMap<>();
        params.put("token", accessToken.getTokenValue());

        return new ModelAndView("rootView", params);
    }

Security Config:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .oauth2Client()
            .and()
            .authorizeRequests()
                .anyRequest()
                .authenticated()
            .and()
                .oauth2ResourceServer()
                    .bearerTokenResolver(getCustomizedTokenResolver())
                    .jwt();
    }

    private BearerTokenResolver getCustomizedTokenResolver() {
        DefaultBearerTokenResolver resolver = new DefaultBearerTokenResolver();
        resolver.setAllowFormEncodedBodyParameter(true);
        resolver.setAllowUriQueryParameter(true);
        return resolver;
    }

    @Bean
    public ClientRegistrationRepository clientRegistrationRepository() {
        return new BridgeClientRegistrationRepository(externalSystemService);
    }

    @Bean
    public OAuth2AuthorizedClientManager authorizedClientManager(OAuth2AuthorizedClientRepository authorizedClientRepository) {
        return new DefaultOAuth2AuthorizedClientManager(clientRegistrationRepository(), authorizedClientRepository);
    }

}

UPDATE

My code originally defined the OAuth2AuthorizedClientManager as:

    @Bean
    public OAuth2AuthorizedClientManager authorizedClientManager(OAuth2AuthorizedClientRepository authorizedClientRepository) {
        return new DefaultOAuth2AuthorizedClientManager(clientRegistrationRepository(), authorizedClientRepository);
    }

It seems that without adding specific providers to the ClientProvider, it would not function. Corrected code is:

    @Bean
    public OAuth2AuthorizedClientManager authorizedClientManager(
            ClientRegistrationRepository clientRegistrationRepository,
            OAuth2AuthorizedClientRepository authorizedClientRepository) {

        OAuth2AuthorizedClientProvider authorizedClientProvider =
                OAuth2AuthorizedClientProviderBuilder.builder()
                        .authorizationCode()
                        .refreshToken()
                        .clientCredentials()
                        .password()
                        .build();

        DefaultOAuth2AuthorizedClientManager authorizedClientManager =
                new DefaultOAuth2AuthorizedClientManager(
                        clientRegistrationRepository, authorizedClientRepository);
        authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);

        return authorizedClientManager;
    }
Josh Collins
  • 101
  • 1
  • 6

0 Answers0