/**
   * Endpoint for handling the callback from Google authorization server. Reads the authorization
   * code from the request and makes a request to get the auth token and refresh token.
   *
   * @return Redirect to the afterAuthUrl specified in the call to requestAuthorization(), or
   *     /secure/dashboard if no aftetAuthUrl was specified.
   */
  @GET
  @Path("gappsOAuthResponse")
  public Response handleGoogleAuthorizationCallback(
      @Context HttpServletRequest request, @QueryParam("state") String state) {
    String userId = request.getRemoteUser();
    if (userId == null) {
      throw new UnauthorizedException("Google proxy is not supported for anonymous users");
    }
    LOGGER.info(
        "Got a Google auth callback for user "
            + userId
            + "; query string = "
            + request.getQueryString());
    String code = request.getParameter("code");

    if (code != null) {

      GoogleAuthorizationCodeTokenRequest tokenRequest = flow.newTokenRequest(code);
      tokenRequest.setRedirectUri(authCallbackUrl);

      try {
        GoogleTokenResponse tokenResponse = tokenRequest.execute();
        Credential credential = flow.createAndStoreCredential(tokenResponse, userId);
        logCredential(userId, credential);
      } catch (IOException e) {
        LOGGER.error(e);
        throw new InternalServerErrorException(e.getMessage());
      }
    } else {
      LOGGER.warn("Could not get auth code from Google auth callback");
      oAuth2Dao.delete(userId, GoogleCredentialStore.GOOGLE_APP_ID);
    }

    // redirect to the page the UI originally requested
    String afterAuthUrl = "/secure/dashboard";
    if (state != null) {
      try {
        afterAuthUrl = Base64.decode(state, "UTF-8");
      } catch (UnsupportedEncodingException e) {
        LOGGER.error("UTF-8 is not supported??");
      }
    }
    return Response.seeOther(URI.create(afterAuthUrl)).build();
  }
  private static Credential getOAuth2Credential(GoogleClientSecrets clientSecrets)
      throws Exception {
    GoogleAuthorizationCodeFlow authorizationFlow =
        new GoogleAuthorizationCodeFlow.Builder(
                new NetHttpTransport(),
                new JacksonFactory(),
                clientSecrets,
                Lists.newArrayList(SCOPE))
            // Set the access type to offline so that the token can be refreshed.
            // By default, the library will automatically refresh tokens when it
            // can, but this can be turned off by setting
            // api.adwords.refreshOAuth2Token=false in your ads.properties file.
            .setAccessType("offline")
            .build();

    String authorizeUrl =
        authorizationFlow.newAuthorizationUrl().setRedirectUri(CALLBACK_URL).build();
    System.out.println("Paste this url in your browser: \n" + authorizeUrl + '\n');

    // Wait for the authorization code.
    System.out.println("Type the code you received here: ");
    String authorizationCode = new BufferedReader(new InputStreamReader(System.in)).readLine();

    // Authorize the OAuth2 token.
    GoogleAuthorizationCodeTokenRequest tokenRequest =
        authorizationFlow.newTokenRequest(authorizationCode);
    tokenRequest.setRedirectUri(CALLBACK_URL);
    GoogleTokenResponse tokenResponse = tokenRequest.execute();

    // Create the OAuth2 credential.
    GoogleCredential credential =
        new GoogleCredential.Builder()
            .setTransport(new NetHttpTransport())
            .setJsonFactory(new JacksonFactory())
            .setClientSecrets(clientSecrets)
            .build();

    // Set authorized credentials.
    credential.setFromTokenResponse(tokenResponse);

    return credential;
  }
  protected Credential exchangeCode(
      long companyId, long scopeGroupId, String authorizationCode, String redirectUri)
      throws SystemException, PortalException {

    try {
      GoogleAuthorizationCodeFlow flow = getFlow(companyId, scopeGroupId);

      GoogleAuthorizationCodeTokenRequest token = flow.newTokenRequest(authorizationCode);

      token.setRedirectUri(redirectUri);

      GoogleTokenResponse response = token.execute();

      return flow.createAndStoreCredential(response, null);
    } catch (IOException e) {
      System.err.println("An error occurred: " + e);

      throw new CodeExchangeException();
    }
  }
  /*
   * Get New Credentials from the user from the command line OAuth2 dance.
   */
  public Credential getNewOAuth2Credential() throws OAuthException {

    GoogleAuthorizationCodeFlow authorizationFlow = getAuthorizationFlow();

    String authorizeUrl =
        authorizationFlow.newAuthorizationUrl().setRedirectUri(CALLBACK_URL).build();

    System.out.println(
        "\n**ACTION REQUIRED** Paste this url in your browser"
            + " and authenticate using your **AdWords Admin Email**: \n\n"
            + authorizeUrl
            + '\n');

    // Wait for the authorization code.
    System.out.println("Type the code you received on the web page here: ");
    try {
      String authorizationCode = new BufferedReader(new InputStreamReader(System.in)).readLine();

      // Authorize the OAuth2 token.
      GoogleAuthorizationCodeTokenRequest tokenRequest =
          authorizationFlow.newTokenRequest(authorizationCode);
      tokenRequest.setRedirectUri(CALLBACK_URL);
      GoogleTokenResponse tokenResponse = tokenRequest.execute();

      //  Create the credential.
      Credential credential =
          new GoogleCredential.Builder()
              .setClientSecrets(clientId, clientSecret)
              .setJsonFactory(new JacksonFactory())
              .setTransport(new NetHttpTransport())
              .build()
              .setFromTokenResponse(tokenResponse);

      // Set authorized credentials.
      credential.setFromTokenResponse(tokenResponse);

      return credential;
    } catch (IOException e) {
      throw new OAuthException("An error occured obtaining the OAuth2Credential", e.getCause());
    }
  }