GoogleCredential deprecation - google-oauth

We want to implement Google OAUTH to play nicely with our web-app based credentials. Flow starts on UI side, which shows user consent screen, and then we obtain a code. That code is then sent to our java based back-end to get refresh token.
At the moment we use this approach:
private Analytics getAnalytics(String refreshToken) throws Exception {
NetHttpTransport httpTransport =
GoogleNetHttpTransport.newTrustedTransport();
JsonFactory jsonFactory =
JacksonFactory.getDefaultInstance();
return new Analytics.Builder(
httpTransport,
jsonFactory,
new GoogleCredential.Builder()
.setTransport(httpTransport)
.setJsonFactory(jsonFactory)
.setClientSecrets(clientId, clientSecret)
.build()
.setRefreshToken(refreshToken)
).build();
}
The problem in above is that GoogleCredential is deprecated. What is they non-deprecated way to do this?
We are using following lib:
com.google.apis.google-api-services-analytics:v3-rev20190807-1.30.10

Google Credential is not fully deprecated, it depends on the library you are using (com.google.auth:google-auth-library-oauth2-http:0.17.1 should still work)
An any case, as mentioned here the non-deprecated way is to use Google Auth Library for Java
There are samples for different ways to build the credentials - depending on your use case.

Related

How to use YouTube Data API

I tried using YouTube Data API.
I really took a good look at everything I found on the internet. The code itself isn't the problem, but I did not find out, where to use this code. Do I simply create a python file (in Visual Studio Code for example) and run it there? Because it didn't work when I tried this...
I also saw many people using the API with the commander only, others used something in chrome (localhost:8888...). So I don`t really know what's the way to go or what I should do.
Thanks for any help :)
Best regards!
I'm not a python developer but as a guess you could start here:
https://developers.google.com/youtube/v3/quickstart/python
using pip to install the dependencies you need.
You should be able to create a simple python file that authenticates with the API and then calls a method on the on the google api client and then output it. There are some examples here:
https://github.com/youtube/api-samples/blob/master/python/
using System;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using Google.Apis.Upload;
using Google.Apis.Util.Store;
using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data;
namespace Google.Apis.YouTube.Samples
{
/// <summary>
/// YouTube Data API v3 sample: upload a video.
/// Relies on the Google APIs Client Library for .NET, v1.7.0 or higher.
/// See https://code.google.com/p/google-api-dotnet-client/wiki/GettingStarted
/// </summary>
internal class UploadVideo
{
[STAThread]
static void Main(string[] args)
{
Console.WriteLine("YouTube Data API: Upload Video");
Console.WriteLine("==============================");
try
{
new UploadVideo().Run().Wait();
}
catch (AggregateException ex)
{
foreach (var e in ex.InnerExceptions)
{
Console.WriteLine("Error: " + e.Message);
}
}
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
private async Task Run()
{
UserCredential credential;
using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read))
{
credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
// This OAuth 2.0 access scope allows an application to upload files to the
// authenticated user's YouTube channel, but doesn't allow other types of access.
new[] { YouTubeService.Scope.YoutubeUpload },
"user",
CancellationToken.None
);
}
var youtubeService = new YouTubeService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = Assembly.GetExecutingAssembly().GetName().Name
});
var video = new Video();
video.Snippet = new VideoSnippet();
video.Snippet.Title = "Default Video Title";
video.Snippet.Description = "Default Video Description";
video.Snippet.Tags = new string[] { "tag1", "tag2" };
video.Snippet.CategoryId = "22"; // See https://developers.google.com/youtube/v3/docs/videoCategories/list
video.Status = new VideoStatus();
video.Status.PrivacyStatus = "unlisted"; // or "private" or "public"
var filePath = #"REPLACE_ME.mp4"; // Replace with path to actual movie file.
using (var fileStream = new FileStream(filePath, FileMode.Open))
{
var videosInsertRequest = youtubeService.Videos.Insert(video, "snippet,status", fileStream, "video/*");
videosInsertRequest.ProgressChanged += videosInsertRequest_ProgressChanged;
videosInsertRequest.ResponseReceived += videosInsertRequest_ResponseReceived;
await videosInsertRequest.UploadAsync();
}
}
void videosInsertRequest_ProgressChanged(Google.Apis.Upload.IUploadProgress progress)
{
switch (progress.Status)
{
case UploadStatus.Uploading:
Console.WriteLine("{0} bytes sent.", progress.BytesSent);
break;
case UploadStatus.Failed:
Console.WriteLine("An error prevented the upload from completing.\n{0}", progress.Exception);
break;
}
}
void videosInsertRequest_ResponseReceived(Video video)
{
Console.WriteLine("Video id '{0}' was successfully uploaded.", video.Id);
}
}
}
Make sure you have python installed on your PC
Create a project: Google’s APIs and Services dashboard
Enable the Youtube v3 API: API Library
Create credentials: Credentials wizard
Now you need to get an access token and a refresh token using the credentials you created
Find an authentication example in one of the following libraries:
https://github.com/googleapis/google-api-python-client
https://github.com/omarryhan/aiogoogle (for the async version)
Copy and paste the client ID and client secret you got from step 4 and paste them in the authentication example you found in step 6 (Should search for an OAuth2 example), this step should provide with an access token and a refresh token
Copy and paste a Youtube example from either:
https://github.com/googleapis/google-api-python-client
https://github.com/omarryhan/aiogoogle (for the async version)
Replace the access token and refresh token fields with the ones you got.
Now you should be able to run the file from any terminal by typing:
python3 yourfile.py
[EDIT]
The API key is not the same as the access token. There are 2 main ways to authenticate with Google APIs:
Access and refresh token
API_KEY.
API key won't work with personal info. You need to get an access and refresh token for that (method 1).
Once you get an access token, it acts in a similar fashion to the API_KEY you got. Getting an access token is a bit more complicated than only working with an API_KEY.
A refresh token is a token you get with the access token upon authentication. Access tokens expire after 3600 seconds. When they expire, your authentication library asks Google's servers for a new access token with the refresh token. The refresh token has a very long lifetime (often indefinite), so make sure you store it securely.
To get an access token and a refresh token (user credentials), you must first create client credentials. Which should consists of 1. a client ID and 2. a client secret. These are just normal strings.
You should also, set a redirect URL in your Google app console in order to properly perform the OAuth2 flow. The OAuth2 flow is the authentication protocol that many APIs rely on to allow them to act on a user's account with the consent of the user. (e.g. when an app asks you to post on your behalf or control your account on your behalf, it typically will use this protocol.)
Aiogoogle's docs does a decent job in explaining the authentication flow(s) available by Google.
https://aiogoogle.readthedocs.io/en/latest/
But this is an async Python library. If you're not familiar with the async syntax, you can read the docs just to get a general idea of how the authentication system works and then apply it to Google's sync Python library.
About point no.6. The links I posted with Aiogoogle being one of them, are just client libraries that help you access Google's API quicker and with less boilerplate. Both libraries have documentation, where they have links to examples on how to use them. So, open the documentation, read it, search for the examples posted, try to understand how the code in the example(s) work. Then maybe download it and run it on your own machine.
I recommend that your read the docs. Hope that helps.

How to connect TFS Online using PAT or OAUT?

Can't believe I'm stuck with a LOGIN :( hate when this happens.
Can somebody enlight me how to connect TF.EXE by using PAT password or in the best case an OAuth token?
I might add that I already have a Pat token and an OAuth token, not a problem while trying to get those, but every time I try this example:
TF.exe workspaces /collection:xxxx.visualstudio.com/xxxx /loginType:OAuth /login:.,MyPatTokenOrMyOauthToken /noprompt
I get the following response:
TF30063: You are not authorized to access xxxx.visualstudio.com\xxxx.
So, I Know command it's ok, because if I don't specify a login, a modal window prompts for credentials, and I tested already with that approach and works fine.
For the end, I might change everything to change tf.exe for the TFS api, but I'm unable to find same methods in the api (see reference: https://learn.microsoft.com/es-es/rest/api/vsts/?view=vsts )
If API has same methods than TF.exe, that will be useful, but so far I don't see same methods in the API.
Hope somebody has the solution for my problem.
Thanks in advance.
From my test, PAT token doesn't work in the following command, you have to get a OAuth token:
tf workspaces /collection:https://xxxx.visualstudio.com /loginType:OAuth /login:.,[OAuth token]
For the api that authenticate with Visual Studio Team Services (VSTS), you could refer to the examples in this link:
Here is an example getting a list of projects for your account:
REST API
using System.Net.Http;
using System.Net.Http.Headers;
...
//encode your personal access token
string credentials = Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(string.Format("{0}:{1}", "", personalAccessToken)));
ListofProjectsResponse.Projects viewModel = null;
//use the httpclient
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("https://{accountname}.visualstudio.com"); //url of our account
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", credentials);
//connect to the REST endpoint
HttpResponseMessage response = client.GetAsync("_apis/projects?stateFilter=All&api-version=1.0").Result;
//check to see if we have a succesfull respond
if (response.IsSuccessStatusCode)
{
//set the viewmodel from the content in the response
viewModel = response.Content.ReadAsAsync<ListofProjectsResponse.Projects>().Result;
//var value = response.Content.ReadAsStringAsync().Result;
}
}
.Net Client Libraries
using Microsoft.TeamFoundation.Core.WebApi;
using Microsoft.VisualStudio.Services.Common;
...
//create uri and VssBasicCredential variables
Uri uri = new Uri(url);
VssBasicCredential credentials = new VssBasicCredential("", personalAccessToken);
using (ProjectHttpClient projectHttpClient = new ProjectHttpClient(uri, credentials))
{
IEnumerable<TeamProjectReference> projects = projectHttpClient.GetProjects().Result;
}
Add a screenshot:
Update:
I've tested with a new account, and the result is as below. If I remove /loginType and /login parameters, a window will pop up to ask me logon.
The screenshot without /loginType and /login parameters:
The screenshot with /loginType and /login parameters:

MuleSoft Google Calendar connector

Is there any way to authenticate Mule google calendar connector with google service account so that I can avoid the access popup every time.
Look at Managing OAuth tokens, if you make the object store that handles these persistent, then it will reuse the access tokens rather than redirecting for authorisation each time: https://docs.mulesoft.com/mule-user-guide/v/3.4/using-a-connector-to-access-an-oauth-api#managing-oauth-tokens-optional
I found a simple solution to my question
public void Auth() {
try {
httpTransport = GoogleNetHttpTransport.newTrustedTransport();
credential = new GoogleCredential.Builder()
.setTransport(httpTransport)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(getConsumerKey())
.setServiceAccountPrivateKeyFromP12File(new File(getConsumerSecret()))
.setServiceAccountScopes(Arrays.asList(getScope())).build();
client = new Calendar.Builder(
httpTransport, JSON_FACTORY, credential)
.setApplicationName(getApplicationName()).build();
}
catch (Exception e) {
e.printStackTrace();
}
}
Just include above function in the exiting google calendar code and remove the token based authentication from the code.
This will work absolutely fine with service account of google.
Thanks

OAuth 2.0 Access Tokens and Refresh Tokens

I have difficult in understanding the proper usage of refresh and access tokens. I know that refresh tokens are related to authorization and access tokens are related to authentication.I would like to explain my use case better so that someone could help me out here. I have a Multi Account Center in Google Merchant Center. I would like to integrate the latest OAuth 2.0 authentication mechanism in my code. I did and could authenticate successfully. I use Google Credential mechanism of building a credential object and inject in using the httprequestinitializer mechanism during httprequest to google. When the google credential object is created , I see that there is no access tokens when I do a googleCredential.getAccessToken(), but then when I do a googleCredential.refreshToken() and then a googleCredential.getAccessToken() , I get an accessToken. However, I was testing how the tokens are created and I am not explicitly passing these tokens in the request to google. All I pass is just the googleCredential object with client secrets and other private keys. The task I am doing is just uploading the sub account product feeds to google via cron script.
My questions are,
Do I have to take care of the refreshing tokens here while passing the googleCredential object here ? (Assume script runs for a more than a day)
When should one use refresh tokens and access tokens, what would a proper choice for me in above use case? (Though for now I am not passing anything explicitly other than googleCredential Object)
What is the validity time for a access token and refresh token(not related to above use case, just to know, some say 14 days for refresh tokens, some say indefinite till user revokes access , etc)
I would be great full if someone clarifies me and pulls me out. I know this platform is to clarify issues majorly on code but I google forum isn't helping either. So posting here.
Sorry for being very verbose.
Thanks in advance.
A refresh token is required for so called OfflineCredentials. These are credentials, that can be used by applications, which are not running in a browser (e.g. desktop applications or some batch processing without UI) and therefore cannot perform an OAuth2 flow.
Please have a look at Using OAuth 2.0 to Access Google APIs
Refresh the access token, if necessary.
Access tokens have limited lifetimes. If your application needs access to a Google API beyond the lifetime of a single access token, it can obtain a refresh token. A refresh token allows your application to obtain new access tokens.
Note: Save refresh tokens in secure long-term storage and continue to use them as long as they remain valid. Limits apply to the number of refresh tokens that are issued per client-user combination, and per user across all clients, and these limits are different. If your application requests enough refresh tokens to go over one of the limits, older refresh tokens stop working.
Some more information to Offline Access!
In Java, it will look like this:
import com.google.api.ads.common.lib.auth.OfflineCredentials;
import com.google.api.ads.common.lib.auth.OfflineCredentials.Api;
import com.google.api.ads.common.lib.auth.OfflineCredentials.ForApiBuilder;
import com.google.api.ads.common.lib.exception.OAuthException;
import com.google.api.ads.common.lib.exception.ValidationException;
import com.google.api.client.auth.oauth2.Credential;
// ...
// Generate offline credentials
// With a previously created OAuth2 refresh token (see API examples)
ForApiBuilder forApiBuilder = new OfflineCredentials.Builder().forApi(Api.ADWORDS);
forApiBuilder.withClientSecrets(clientId, clientSecret);
forApiBuilder.withRefreshToken(refreshToken);
Credential credential = null;
try {
credential = forApiBuilder.build().generateCredential();
} catch (OAuthException e) {
throw new Exception("The given credential could not be refreshed: " + e.getMessage());
} catch (ValidationException e) {
throw new Exception("Client ID, client secret or refresh token are not valid: " + e.getMessage());
}
// Build session
// ...
The refresh token need to be passed to the credential builder in addition to the client ID and the client secret. With the valid OfflineCredentials you are now able to build a new session for a specific Google API.
Regarding your third question: See the accepted answer of following question
Here the source code, which shows how to obtain a refresh token for Google AdWords (see scope) once via commandline. The client ID and the client secret must be passed as commandline arguments.
import java.io.BufferedReader;
import java.io.InputStreamReader;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.PropertiesConfiguration;
import com.google.api.ads.common.lib.auth.GoogleClientSecretsBuilder;
import com.google.api.ads.common.lib.auth.GoogleClientSecretsBuilder.Api;
import com.google.api.ads.common.lib.auth.GoogleClientSecretsBuilder.GoogleClientSecretsForApiBuilder;
import com.google.api.ads.common.lib.exception.ValidationException;
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeTokenRequest;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.common.collect.Lists;
// ...
private static final String SCOPE = "https://adwords.google.com/api/adwords";
// This callback URL will allow you to copy the token from the success screen
private static final String CALLBACK_URL = "urn:ietf:wg:oauth:2.0:oob";
public static void main(String[] args) throws Exception {
if (args.length != 2) {
System.err.println("Please provide client ID and secret as commandline arguments!");
System.err.println("If you do not have a client ID or secret, please create one in the API console: https://code.google.com/apis/console#access");
System.exit(1);
}
GoogleClientSecrets clientSecrets = null;
try {
Configuration configuration = new PropertiesConfiguration();
configuration.setProperty("api.adwords.clientId", args[0]);
configuration.setProperty("api.adwords.clientSecret", args[1]);
GoogleClientSecretsForApiBuilder googleClientSecretsForApiBuilder = new GoogleClientSecretsBuilder().forApi(Api.ADWORDS);
googleClientSecretsForApiBuilder.from(configuration);
clientSecrets = googleClientSecretsForApiBuilder.build();
} catch (ValidationException e) {
System.err.println("Invalid client ID or secret!");
System.exit(1);
}
// Get the OAuth2 credential
Credential credential = getOAuth2Credential(clientSecrets);
System.out.printf("Your refresh token is: %s\n", credential.getRefreshToken());
}
}
private static Credential getOAuth2Credential(GoogleClientSecrets clientSecrets) throws Exception {
/*
* 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
*/
GoogleAuthorizationCodeFlow authorizationFlow = new GoogleAuthorizationCodeFlow.Builder(new NetHttpTransport(), new JacksonFactory(), clientSecrets, Lists.newArrayList(SCOPE)).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;
}
The code is originally from a Goolge AdWords API example. My version is not reading from a configuration file, because I didn't want to store the client ID and secret in some resource file (which I forgot to remove later on). That's why the values are passed as arguments to the program.

ArgumentException: Precondition failed.: !string.IsNullOrEmpty(authorization.RefreshToken) with Service Account for Google Admin SDK Directory access

I'm trying to access the Google Directory using a Service Account. I've fiddled with the DriveService example to get this code:
public static void Main(string[] args)
{
var service = BuildDirectoryService();
var results = service.Orgunits.List(customerID).Execute();
Console.WriteLine("OrgUnits");
foreach (var orgUnit in results.OrganizationUnits)
{
Console.WriteLine(orgUnit.Name);
}
Console.ReadKey();
}
static DirectoryService BuildDirectoryService()
{
X509Certificate2 certificate = new X509Certificate2(SERVICE_ACCOUNT_PKCS12_FILE_PATH, "notasecret",
X509KeyStorageFlags.Exportable);
var provider = new AssertionFlowClient(GoogleAuthenticationServer.Description, certificate)
{
ServiceAccountId = SERVICE_ACCOUNT_EMAIL,
Scope = DirectoryService.Scopes.AdminDirectoryOrgunit.GetStringValue()
};
var auth = new OAuth2Authenticator<AssertionFlowClient>(provider, AssertionFlowClient.GetState);
return new DirectoryService(new BaseClientService.Initializer()
{
Authenticator = auth,
ApplicationName = "TestProject1",
});
}
When I run it, I get
ArgumentException: Precondition failed.: !string.IsNullOrEmpty(authorization.RefreshToken)
I'm going round in circles in the Google documentation. The only stuff I can find about RefreshTokens seems to be for when an individual is authorizing the app and the app may need to work offline. Can anyone help out or point me in the direction of the documentation that will, please.
Service Account authorization actually do not return Refresh Token - so this error makes sense. Do you know where this is coming from?
I am not too familiar with the .NET client library but having the full error trace would help.
As a longshot - The error might be a bad error -
Can you confirm that you've enabled the Admin SDK in the APIs console for this project
Can you confirm that you whitelisted that Client ID for the service account in the domain you are testing with (along with the Admin SDK scopes)
The above code will work if you replace the provider block with:
var provider = new AssertionFlowClient(GoogleAuthenticationServer.Description, certificate)
{
ServiceAccountId = SERVICE_ACCOUNT_EMAIL,
Scope = DirectoryService.Scopes.AdminDirectoryOrgunit.GetStringValue(),
ServiceAccountUser = SERVICE_ACCOUNT_USER //"my.admin.account#my.domain.com"
};
I had seen this in another post and tried it with my standard user account and it didn't work. Then I read something that suggested everything had to be done with an admin account. So, I created a whole new project, using my admin account, including creating a new service account, and authorising it. When I tried it, it worked. So, then I put the old service account details back in but left the admin account in. That worked, too.