content: package com.anita.multipleauthapi.security.oauth2;
  
  import com.anita.multipleauthapi.config.AppProperties;
  import com.anita.multipleauthapi.model.error.BadRequestException;
  import com.anita.multipleauthapi.security.TokenProvider;
  import com.anita.multipleauthapi.service.util.CookieUtils;
  import jakarta.servlet.ServletException;
  import jakarta.servlet.http.Cookie;
  import jakarta.servlet.http.HttpServletRequest;
  import jakarta.servlet.http.HttpServletResponse;
  import lombok.RequiredArgsConstructor;
  import org.springframework.security.core.Authentication;
  import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
  import org.springframework.stereotype.Component;
  import org.springframework.web.util.UriComponentsBuilder;
  
  import java.io.IOException;
  import java.net.URI;
  import java.util.Optional;
  
  import static com.anita.multipleauthapi.security.oauth2.HttpCookieOAuth2AuthorizationRequestRepository.REDIRECT_URI_PARAM_COOKIE_NAME;
  
  @Component
  @RequiredArgsConstructor
  public class OAuth2AuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
  
      private final TokenProvider tokenProvider;
      private final AppProperties appProperties;
      private final HttpCookieOAuth2AuthorizationRequestRepository httpCookieOAuth2AuthorizationRequestRepository;
  
      @Override
      public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
          String targetUrl = determineTargetUrl(request, response, authentication);
  
          if (response.isCommitted()) {
              logger.debug("Response has already been committed. Unable to redirect to " + targetUrl);
              return;
          }
  
          clearAuthenticationAttributes(request, response);
          getRedirectStrategy().sendRedirect(request, response, targetUrl);
      }
  
      protected String determineTargetUrl(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
          Optional<String> redirectUri = CookieUtils
                  .getCookie(request, REDIRECT_URI_PARAM_COOKIE_NAME)
                  .map(Cookie::getValue);
  
          if (redirectUri.isPresent() && !isAuthorizedRedirectUri(redirectUri.get())) {
              throw new BadRequestException("Sorry! We've got an Unauthorized Redirect URI and can't proceed with the authentication");
          }
  
          String targetUrl = redirectUri.orElse(getDefaultTargetUrl());
  
          String token = tokenProvider.createToken(authentication);
  
          return UriComponentsBuilder.fromUriString(targetUrl)
                  .queryParam("token", token)
                  .build().toUriString();
      }
  
      protected void clearAuthenticationAttributes(HttpServletRequest request, HttpServletResponse response) {
          super.clearAuthenticationAttributes(request);
          httpCookieOAuth2AuthorizationRequestRepository.removeAuthorizationRequestCookies(request, response);
      }
  
      private boolean isAuthorizedRedirectUri(String uri) {
          URI clientRedirectUri = URI.create(uri);
  
          return appProperties.getOAuth2().getAuthorizedRedirectUris()
                  .stream()
                  .anyMatch(authorizedRedirectUri -> {
                      // Only validate host and port. Let the clients use different paths if they want to
                      URI authorizedURI = URI.create(authorizedRedirectUri);
                      return authorizedURI.getHost().equalsIgnoreCase(clientRedirectUri.getHost())
                             && authorizedURI.getPort() == clientRedirectUri.getPort();
                  });
      }
  }
  