I have to perform a very simple task to get all the tasks of the account Google through Google Api.
Before i started this questions i read documentation, try search to answers, read tech forums, etc
First of all, I configured Developers Console:
- turned ON required API's: such as Tasks API
- Create and download to my project all generic keys: WEB, SERVICE + P12 KEY, INSTALL APP
- also, Installed in project all requiered Nugets: Auth, Client, Core, Tasks.v1
May be i wrong, but matter of great concern (Common Questions):
1. Why need too many variants of keys?
Google IP is only service and it shall be necessary only one token (key)
For software there is no fundamental difference between back-end, desktop, desktop on IOS/Android/Blackberry, service,...
Software need only get/set data from/to some Google Account.
It's very confuse.
2. Google Developers Console - is not simple and clear tools for ordinal user which want get ability to sync with google apps.
Why Google not have simple trust Token generation for account ?
3. Google documentation is not fully and complex. Too many blank places: such as REST queries - not see any correct and work samples with test data and headers.
May any known - where it is ?
Ok, let's begin practice - simple Desktop app on VS2012:
4. Most of google samples said that i need to use GoogleWebAuthorizationBroker
The Code below is similar as all codes in documenation
client_secret.json - JSON files from Google Developers Console
I were try all JSON files with secret codes and also manually set secrets
But nothing, GoogleWebAuthorizationBroker.AuthorizeAsync try to open bad browser window and ends
UserCredential credential;
var stream = new FileStream(#"..." + client_secret.json, FileMode.Open, FileAccess.Read);
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
new[] { TasksService.Scope.Tasks },
"user",
CancellationToken.None,
new FileDataStore("Tasks.Auth.Store")).Result;
// Create the service.
var service = new TasksService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Api Project"
});
TaskLists results = service.Tasklists.List().Execute();
What is Wrong ???
5. Ок, try to use this:
GoogleAuthorizationCodeFlow flow;
using (var stream = new FileStream(#"..." + client_secret.json, FileMode.Open, FileAccess.Read))
{
flow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
DataStore = new FileDataStore("Tasks.Auth.Store"),
ClientSecrets = GoogleClientSecrets.Load(stream).Secrets,
Scopes = new[] { TasksService.Scope.Tasks }
});
}
var result = new AuthorizationCodeWebApp(flow, "", "")
.AuthorizeAsync("user_id", CancellationToken.None).Result;
// The data store contains the user credential, so the user has been already authenticated.
TasksService service = new TasksService(new BaseClientService.Initializer
{
ApplicationName = "API Project",
HttpClientInitializer = result.Credential
});
var lists = service.Tasklists.List().Execute();
Always - not auth.
I was try changed "user_id" - but nothing
What is wrong ???
5. Ок, try to use this:
string serviceAccountEmail = "xxx#developer.gserviceaccount.com";
var certificate = new X509Certificate2(#"...\\key.p12", "notasecret", X509KeyStorageFlags.Exportable);
//var certificate = new X509Certificate2(#"key.p12", "notasecret", X509KeyStorageFlags.Exportable);
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = new[] { TasksService.Scope.Tasks }
}.FromCertificate(certificate));
// Create the service.
var service = new TasksService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "API Project",
});
var lists = service.Tasklists.List().Execute();
if (lists.Items != null)
{
foreach (TaskList lst in lists.Items)
{
var title = lst.Title;
var tasks = service.Tasks.List(lst.Id).Execute();
if (tasks.Items != null)
{
foreach (Task tsk in tasks.Items)
{
}
}
}
}
!!! I have access, but not for my account.
Google return only one EMPTY enemy task list (NOT my 2 lists with many tasks in my account)
What is wrong ???
P.S. Please help. I am in deadlock. I did not expect that Google so bad.
Please, do not redirect me to another forums or topics. I all read before.
Thanks
Related
I haven't been able to create an Spreadsheet in GoogleDocs using new SpreadSheet API, since it is now supported instead using Google Drive API.
All the examples I've found are for creating and modifying Sheets, not the main spreadsheet.
static string[] Scopes = { SheetsService.Scope.Spreadsheets };
var credential = GoogleWebAuthorizationBroker.AuthorizeAsync(new ClientSecrets {
ClientId = clientId, // FROM JSON
ClientSecret = clientSecret // FROM JSON
},
Scopes, Environment.UserName, CancellationToken.None,
new FileDataStore("xxIDxx.GoogleDrive.Auth.Store")).Result;
var service = new SheetsService(new BaseClientService.Initializer() {
HttpClientInitializer = credential,
ApplicationName = "Google Sheets API Project",
});
string SpreadSheetID = "AVeryLongAndRandomStringID";
Spreadsheet SpSheet = new Spreadsheet();
SpSheet.Properties = new SpreadsheetProperties();
SpSheet.SpreadsheetId = SpreadSheetID;
SpSheet.Properties.Title = "I HATE THIS SPREADSHEET";
Sheet MySheet = new Sheet();
MySheet.Properties = new SheetProperties();
MySheet.Properties.Title = "MySheet";
MySheet.Properties.SheetId = 34213312;
MySheet.Properties.SheetType = "GRID";
var SheetSet = new List<Sheet>();
SheetSet.Add(MySheet);
SpSheet.Sheets = SheetSet;
var MyNewSpreadSheet = service.Spreadsheets.Create(SpSheet).Execute();
Thanks!
UPDATE:
The small version "var MyNewSpreadSheet" indeed worked (my last attempts also did) but... I haven't realized it was saving the document in MY googleDrive instead my client's account.
What I was trying to accomplish was to create an App where anyone with a google account could create or alter a Spreadsheet document in a "repository" account.
The file "client_secret.json" was generated from my client's account, I don't know why the code creates the Spreadsheet on the logged gmail account.
Any ideas?
Thanks!
You may want to try sending HTTP request with this format:
POST https://sheets.googleapis.com/v4/spreadsheets
As mentioned in Method: spreadsheets.create, if request is successful, the response body contains a newly created instance of Spreadsheet.
Also, please note that using this method requires on of the following OAuth scopes:
https://www.googleapis.com/auth/drive
https://www.googleapis.com/auth/spreadsheets
Furthermore, please try to also check this documentation if it can help. It's about the Sheets API using C#.
I'm trying to use the Google Drive and Spreadsheets APIs from a C# console app. I'd like to authorize both services using user credentials with a FileDataStore so that I don't have to reauth my app every single time it runs. Below is how I'm authorizing my Drive service object:
var userCredential = GoogleWebAuthorizationBroker.AuthorizeAsync
(
new ClientSecrets
{
ClientId = "[clientID]",
ClientSecret = "[clientSecret]"
},
new []
{
"https://www.googleapis.com/auth/drive",
"https://spreadsheets.google.com/feeds"
},
"[userName]",
CancellationToken.None,
new FileDataStore("MyApp.GoogleDrive.Auth.Store")
).Result;
var driveService = new DriveService
(
new BaseClientService.Initializer
{
HttpClientInitializer = userCredential,
ApplicationName = "MyApp",
}
);
For the Spreadsheets service, I'm authorizing as prescribed by this guide, but every time I run my app, I have to open a browser to the given auth URL and manually copy in the access token to get it to work.
Is there a way to auth once, obtain the user credentials as above, and use them with both services? Note, I'm authorizing with both the Drive and the Spreadsheets scope, so I don't think there's a problem with that.
I've tried to make it work like this, but I keep getting 400 Bad Request errors when I attempt to insert rows into my spreadsheet:
var auth = new OAuth2Parameters
{
ClientId = "[clientID]",
ClientSecret = "[clientSecret]",
RedirectUri = "[redirectUri]",
Scope = "https://www.googleapis.com/auth/drive https://spreadsheets.google.com/feeds" ,
AccessToken = userCredential.Token.AccessToken,
RefreshToken = userCredential.Token.RefreshToken,
TokenType = userCredential.Token.TokenType,
};
var requestFactory = new GOAuth2RequestFactory(null, "MyApp", auth);
var spreadsheetsService = new SpreadsheetsService("MyApp")
{
Credentials = new GDataCredentials(userCredential.Token.TokenType + " " + userCredential.Token.AccessToken),
RequestFactory = requestFactory,
};
Is there a way to auth once, obtain the user credentials as above, and use them with both services?
Yes. Provided you have included all scopes and have requested offline access, then you'll get a refresh token which you can store and reuse to get access tokens as needed. Obv you need to consider the security implications.
A 400 bad request doesn't sound like an OAuth issue. I think you have two questions/issues here and it might be worth starting a new thread. Include the http request/response for the 400 in your question.
I'm using Google's Oauth 2.0 to upload videos to Youtube via our server.
My client ID is a "service account". I downloaded the json key and added it to my solution.
Here is the relevant code:
private async Task Run(string filePath)
{
UserCredential credential;
var keyUrl = System.Web.HttpContext.Current.Server.MapPath("~/content/oauth_key.json");
using (var stream = new FileStream(keyUrl, 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
});
When I run it, I get this error: At least one client secrets (Installed or Web) should be set.
However, in my json there is no "client secret":
{
"private_key_id": "9d98c06b3e730070806dcf8227578efd0ba9989b",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIICdQIBADANBgkqhk etc,
"client_email": "546239405652-8igo05a5m8cutggehk3rk3hspjfm3t04#developer.gserviceaccount.com",
"client_id": "546239405652-8igo05a5m8cutggehk3rk3hspjfm3t04.apps.googleusercontent.com",
"type": "service_account"
}
so I assume I overlooked something.
Maybe I can't use the "service account" ? don't know...
The solution that uses json file is quite similar.
Here is sample that create VisionService using GoogleCredential object created from json file with ServiceAccountCredential.
GoogleCredential credential;
using (var stream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
credential = GoogleCredential.FromStream(stream)
.CreateScoped(VisionService.Scope.CloudPlatform);
}
var service = new VisionService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "my-app-name",
});
this sample require two NuGet packages:
Google.Apis.Vision.v1
Google.Apis.Oauth2.v2
I managed to get a service account to work with a P12 file, But would like to know how to use with the JSON file, Or just value from the JSON file to create the certificate.
To get the token
private static String GetOAuthCredentialViaP12Key()
{
const string serviceAccountEmail = SERVICE_ACCOUNT_EMAIL;
var certificate = new X509Certificate2(SERVICE_ACCOUNT_PKCS12_FILE_PATH, "notasecret", X509KeyStorageFlags.Exportable);
var scope = DriveService.Scope.Drive + " https://spreadsheets.google.com/feeds";
var credential = new ServiceAccountCredential( new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = new[] { scope }
}.FromCertificate(certificate) );
if (credential.RequestAccessTokenAsync(CancellationToken.None).Result == false)
{
return null;
}
return credential.Token.AccessToken;
}
And this is how I used the token I got
// Initialize the variables needed to make the request
OAuth2Parameters parameters = new OAuth2Parameters {AccessToken = token};
GOAuth2RequestFactory requestFactory = new GOAuth2RequestFactory(null, "MySpreadsheetIntegration-v1", parameters);
SpreadsheetsService service = new SpreadsheetsService("MySpreadsheetIntegration-v1");
service.RequestFactory = requestFactory;
Not an expert on C# but it looks like you were trying to use the service account to do the OAuth2 web server flow, which shouldn't work.
You probably want to use ServiceAccountCredential instead.
For more information about different Google OAuth2 flows, please refer to the doc for web server, service account, etc.
I have been using the old version of Google Calendar GData API (v1, v2) since November 2011 in my ASP.NET Applications, allowing Users to retrieve and/or create Calendar Events after submitting their usernames and passwords , and this was working perfectly till 17th of November 2014 just before Google decided to shut down this version of API as announced Calendar GData API / Google Calendar Connectors deprecation
Now I am stuck with the new version of Google APIS Calendar (v3) which forces me to use different scenario of Authentication Process instead of the Traditional one. I don't mind at all using this version of Calendar API as it supports all the needed features but now i don't know how to handle multiple users authentication to use their User Client's ID and Secret which are registered per each user Code Console.
So my question is : Is there any way to let user sign in with his/her normal credentials (Either by Username/Password or Google+ Sign UP feature) and bypassing the process of creating API Project, Enabling the needed APIs and creating new User credentials inside the Console through ASP.net code?
Any Sample code made in C# ASP.net is highly appreciated .
EDIT: Here is my code of Authentication I use
public static CalendarService Authenticate()
{
CalendarService service;
GoogleAuthorizationCodeFlow flow;
string json_File = System.Configuration.ConfigurationManager.AppSettings["Authentication_Path"];
string store_path = System.Configuration.ConfigurationManager.AppSettings["FileStore_Path"];
string url = System.Configuration.ConfigurationManager.AppSettings["Authent_URL"];
using (var stream = new FileStream(json_File, FileMode.Open, FileAccess.Read))
{
flow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
DataStore = new FileDataStore(store_path),
ClientSecretsStream = stream,
Scopes = new[] { CalendarService.Scope.Calendar }
});
}
var uri = url;
var result = new AuthorizationCodeWebApp(flow, uri, uri).AuthorizeAsync("TRAININGCALENDAR", CancellationToken.None).Result;
if (result.Credential == null)
{
GoogleCalendar_Bus.Main_Authentication(url, "", "");
}
// The data store contains the user credential, so the user has been already authenticated.
service = new CalendarService(new BaseClientService.Initializer
{
ApplicationName = "Calendar API Sample",
HttpClientInitializer = result.Credential
});
if (result.Credential != null)
{
service = new CalendarService(new BaseClientService.Initializer
{
ApplicationName = "Calendar API Sample",
HttpClientInitializer = result.Credential
});
}
return service;
}
No you need to use Oauth2. When they authenticate you just save the refresh token this will allow you to then get a new access token and you will have access again. You will need to make your own implementation of Idatastore to store these refresh tokens in the database.
The code for creating an implementation of a Idatastore that stores to the Database is to extensive to post here but you can see a basic example here: DatabaseDataStore.cs
Then you can use it like this.
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
new ClientSecrets { ClientId = _client_id
,ClientSecret = _client_secret }
,scopes
,Environment.UserName
,CancellationToken.None
,new DatabaseDataStore(#"LINDAPC\SQL2012", "LindaTest", "test123", "test", "test")).Result;
Update: Now that I can see your code.
Make sure you have the latested .net client lib. Google.Apis.Calendar.v3 Client Library
your code is using FileDataStore this is what you will need to change. You need to make your own implementation of Idatastore similar to the one I have created DatabaseDatastore.
Your code looks different from how I normally do it.
string[] scopes = new string[] {
CalendarService.Scope.Calendar , // Manage your calendars
CalendarService.Scope.CalendarReadonly // View your Calendars
};
try
{
// here is where we Request the user to give us access, or use the Refresh Token that was previously stored in %AppData%
UserCredential credential = GoogleWebAuthorizationBroker.AuthorizeAsync(new ClientSecrets { ClientId = clientId, ClientSecret = clientSecret }
, scopes
, userName
, CancellationToken.None
, new FileDataStore("Daimto.GoogleCalendar.Auth.Store")).Result;
CalendarService service = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Calendar API Sample",
});
return service;
}
catch (Exception ex)
{
Console.WriteLine(ex.InnerException);
return null;
}
This may be due to the fact that you aren't using the most up to date client lib, you can find a sample console application for Google Calendar here unfortunately it also uses FileDatastore you will have to edit it to use DatabaseDataStore. The authentication sample project can be found here Google-Dotnet-Samples/Authentication/ it shows how you can create your own implementation of Idatastore.
I am still working on the tutorial to go along with that sample project I hope to have it completed soon.
All day long I'm trying to delete/add video to my YouTube playlists. I'm using the YouTube Data API v.3.0. for .NET C#.
I have already created a project in Google Developer Console and got my client secrets JSON file. Also my code for obtaining list items is working ok which means that only the PUT operations are not working as expected. I have used almost the same code as in the google developers site code examples.
Authentication method:
private async Task<YouTubeService> GetYouTubeService(string userEmail)
{
UserCredential credential;
using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read))
{
credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
new[]
{
YouTubeService.Scope.Youtube,
YouTubeService.Scope.Youtubepartner,
YouTubeService.Scope.YoutubeUpload,
YouTubeService.Scope.YoutubepartnerChannelAudit,
YouTubeService.Scope.YoutubeReadonly
},
userEmail,
CancellationToken.None,
new FileDataStore(this.GetType().ToString()));
}
var youtubeService = new YouTubeService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = this.GetType().ToString()
});
return youtubeService;
}
Add video to playlist code:
private async Task AddSongToPlaylistAsync(string userEmail, string songId, string playlistId)
{
var youtubeService = await this.GetYouTubeService(userEmail);
var newPlaylistItem = new PlaylistItem();
newPlaylistItem.Snippet = new PlaylistItemSnippet();
newPlaylistItem.Snippet.PlaylistId = playlistId;
newPlaylistItem.Snippet.ResourceId = new ResourceId();
newPlaylistItem.Snippet.ResourceId.Kind = "youtube#video";
newPlaylistItem.Snippet.ResourceId.VideoId = songId;
newPlaylistItem = await youtubeService.PlaylistItems.Insert(newPlaylistItem, "snippet").ExecuteAsync();
}
this is the message that I receive when I try to add a new video to the specified playlist:
Google.Apis.Requests.RequestError
Insufficient Permission [403]
Errors [
Message[Insufficient Permission] Location[ - ] Reason[insufficientPermissions] Domain[global]
]
I'll really appreciate any available help because I didn't find anything useful googling.
Thank you in advance!
I encountered the same issue but if anyone is having issue with the inefficient permission when adding a video to a playlist, you will need to have the YouTubeService.Scope.Youtube (which looks like you already have).
var scopes = new[]
{
YouTubeService.Scope.Youtube
};
If you however added the scope after you already have given the permission, you will need to revoke the client by going to this page manage permissions. You will have to look for your specific client. After you've done that, you can rerun you app and request for permission once again.
Another option is to create a new clientId and clientSecret again and make sure you have the right scope to begin with. I hope this helps.